LockSettingsService.java revision 8fc2ec832f765a51c8fcd04cc89428a3ced4b605
1/*
2 * Copyright (C) 2012 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.server.locksettings;
18
19import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
20import static android.Manifest.permission.READ_CONTACTS;
21import static android.content.Context.KEYGUARD_SERVICE;
22import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
23import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_ENABLED_KEY;
24import static com.android.internal.widget.LockPatternUtils.SYNTHETIC_PASSWORD_HANDLE_KEY;
25
26import android.annotation.UserIdInt;
27import android.app.ActivityManager;
28import android.app.IActivityManager;
29import android.app.KeyguardManager;
30import android.app.Notification;
31import android.app.NotificationManager;
32import android.app.PendingIntent;
33import android.app.admin.DevicePolicyManager;
34import android.app.admin.PasswordMetrics;
35import android.app.backup.BackupManager;
36import android.app.trust.IStrongAuthTracker;
37import android.app.trust.TrustManager;
38import android.content.BroadcastReceiver;
39import android.content.ContentResolver;
40import android.content.Context;
41import android.content.Intent;
42import android.content.IntentFilter;
43import android.content.pm.PackageManager;
44import android.content.pm.UserInfo;
45import android.content.res.Resources;
46import android.database.sqlite.SQLiteDatabase;
47import android.os.Binder;
48import android.os.Bundle;
49import android.os.Handler;
50import android.os.IBinder;
51import android.os.IProgressListener;
52import android.os.Process;
53import android.os.RemoteException;
54import android.os.ResultReceiver;
55import android.os.ServiceManager;
56import android.os.ShellCallback;
57import android.os.StrictMode;
58import android.os.SystemProperties;
59import android.os.UserHandle;
60import android.os.UserManager;
61import android.os.storage.IStorageManager;
62import android.os.storage.StorageManager;
63import android.provider.Settings;
64import android.provider.Settings.Secure;
65import android.provider.Settings.SettingNotFoundException;
66import android.security.GateKeeper;
67import android.security.KeyStore;
68import android.security.keystore.AndroidKeyStoreProvider;
69import android.security.keystore.KeyProperties;
70import android.security.keystore.KeyProtection;
71import android.service.gatekeeper.GateKeeperResponse;
72import android.service.gatekeeper.IGateKeeperService;
73import android.text.TextUtils;
74import android.util.ArrayMap;
75import android.util.Log;
76import android.util.Slog;
77
78import com.android.internal.annotations.VisibleForTesting;
79import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
80import com.android.internal.notification.SystemNotificationChannels;
81import com.android.internal.util.ArrayUtils;
82import com.android.internal.util.DumpUtils;
83import com.android.internal.widget.ICheckCredentialProgressCallback;
84import com.android.internal.widget.ILockSettings;
85import com.android.internal.widget.LockPatternUtils;
86import com.android.internal.widget.VerifyCredentialResponse;
87import com.android.server.SystemService;
88import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
89import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult;
90import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationToken;
91
92import libcore.util.HexEncoding;
93
94import java.io.ByteArrayOutputStream;
95import java.io.FileDescriptor;
96import java.io.FileNotFoundException;
97import java.io.IOException;
98import java.io.PrintWriter;
99import java.nio.charset.StandardCharsets;
100import java.security.InvalidAlgorithmParameterException;
101import java.security.InvalidKeyException;
102import java.security.KeyStoreException;
103import java.security.MessageDigest;
104import java.security.NoSuchAlgorithmException;
105import java.security.SecureRandom;
106import java.security.UnrecoverableKeyException;
107import java.security.cert.CertificateException;
108import java.util.ArrayList;
109import java.util.Arrays;
110import java.util.List;
111import java.util.Map;
112import java.util.concurrent.CountDownLatch;
113import java.util.concurrent.TimeUnit;
114
115import javax.crypto.BadPaddingException;
116import javax.crypto.Cipher;
117import javax.crypto.IllegalBlockSizeException;
118import javax.crypto.KeyGenerator;
119import javax.crypto.NoSuchPaddingException;
120import javax.crypto.SecretKey;
121import javax.crypto.spec.GCMParameterSpec;
122
123/**
124 * Keeps the lock pattern/password data and related settings for each user. Used by
125 * LockPatternUtils. Needs to be a service because Settings app also needs to be able to save
126 * lockscreen information for secondary users.
127 *
128 * @hide
129 */
130public class LockSettingsService extends ILockSettings.Stub {
131    private static final String TAG = "LockSettingsService";
132    private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
133    private static final boolean DEBUG = false;
134
135    private static final int PROFILE_KEY_IV_SIZE = 12;
136    private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
137
138    // Order of holding lock: mSeparateChallengeLock -> mSpManager -> this
139    private final Object mSeparateChallengeLock = new Object();
140
141    private final Injector mInjector;
142    private final Context mContext;
143    private final Handler mHandler;
144    @VisibleForTesting
145    protected final LockSettingsStorage mStorage;
146    private final LockSettingsStrongAuth mStrongAuth;
147    private final SynchronizedStrongAuthTracker mStrongAuthTracker;
148
149    private final LockPatternUtils mLockPatternUtils;
150    private final NotificationManager mNotificationManager;
151    private final UserManager mUserManager;
152    private final IActivityManager mActivityManager;
153    private final SyntheticPasswordManager mSpManager;
154
155    private final KeyStore mKeyStore;
156
157    private boolean mFirstCallToVold;
158    protected IGateKeeperService mGateKeeperService;
159
160    /**
161     * The UIDs that are used for system credential storage in keystore.
162     */
163    private static final int[] SYSTEM_CREDENTIAL_UIDS = {
164            Process.WIFI_UID, Process.VPN_UID,
165            Process.ROOT_UID };
166
167    // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
168    // devices. The most basic of these is to show/hide notifications about missing features until
169    // the user unlocks the account and credential-encrypted storage is available.
170    public static final class Lifecycle extends SystemService {
171        private LockSettingsService mLockSettingsService;
172
173        public Lifecycle(Context context) {
174            super(context);
175        }
176
177        @Override
178        public void onStart() {
179            AndroidKeyStoreProvider.install();
180            mLockSettingsService = new LockSettingsService(getContext());
181            publishBinderService("lock_settings", mLockSettingsService);
182        }
183
184        @Override
185        public void onStartUser(int userHandle) {
186            mLockSettingsService.onStartUser(userHandle);
187        }
188
189        @Override
190        public void onUnlockUser(int userHandle) {
191            mLockSettingsService.onUnlockUser(userHandle);
192        }
193
194        @Override
195        public void onCleanupUser(int userHandle) {
196            mLockSettingsService.onCleanupUser(userHandle);
197        }
198    }
199
200    @VisibleForTesting
201    protected static class SynchronizedStrongAuthTracker
202            extends LockPatternUtils.StrongAuthTracker {
203        public SynchronizedStrongAuthTracker(Context context) {
204            super(context);
205        }
206
207        @Override
208        protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
209            synchronized (this) {
210                super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
211            }
212        }
213
214        @Override
215        public int getStrongAuthForUser(int userId) {
216            synchronized (this) {
217                return super.getStrongAuthForUser(userId);
218            }
219        }
220
221        void register(LockSettingsStrongAuth strongAuth) {
222            strongAuth.registerStrongAuthTracker(this.mStub);
223        }
224    }
225
226    /**
227     * Tie managed profile to primary profile if it is in unified mode and not tied before.
228     *
229     * @param managedUserId Managed profile user Id
230     * @param managedUserPassword Managed profile original password (when it has separated lock).
231     *            NULL when it does not have a separated lock before.
232     */
233    public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
234        if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
235        // Only for managed profile
236        if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) {
237            return;
238        }
239        // Do not tie managed profile when work challenge is enabled
240        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
241            return;
242        }
243        // Do not tie managed profile to parent when it's done already
244        if (mStorage.hasChildProfileLock(managedUserId)) {
245            return;
246        }
247        // Do not tie it to parent when parent does not have a screen lock
248        final int parentId = mUserManager.getProfileParent(managedUserId).id;
249        if (!isUserSecure(parentId)) {
250            if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
251            return;
252        }
253        // Do not tie when the parent has no SID (but does have a screen lock).
254        // This can only happen during an upgrade path where SID is yet to be
255        // generated when the user unlocks for the first time.
256        try {
257            if (getGateKeeperService().getSecureUserId(parentId) == 0) {
258                return;
259            }
260        } catch (RemoteException e) {
261            Slog.e(TAG, "Failed to talk to GateKeeper service", e);
262            return;
263        }
264        if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
265        byte[] randomLockSeed = new byte[] {};
266        try {
267            randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
268            String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
269            setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
270                    managedUserPassword, managedUserId);
271            // We store a private credential for the managed user that's unlocked by the primary
272            // account holder's credential. As such, the user will never be prompted to enter this
273            // password directly, so we always store a password.
274            setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
275                    DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, managedUserId);
276            tieProfileLockToParent(managedUserId, newPassword);
277        } catch (NoSuchAlgorithmException | RemoteException e) {
278            Slog.e(TAG, "Fail to tie managed profile", e);
279            // Nothing client can do to fix this issue, so we do not throw exception out
280        }
281    }
282
283    static class Injector {
284
285        protected Context mContext;
286
287        public Injector(Context context) {
288            mContext = context;
289        }
290
291        public Context getContext() {
292            return mContext;
293        }
294
295        public Handler getHandler() {
296            return new Handler();
297        }
298
299        public LockSettingsStorage getStorage() {
300            final LockSettingsStorage storage = new LockSettingsStorage(mContext);
301            storage.setDatabaseOnCreateCallback(new LockSettingsStorage.Callback() {
302                @Override
303                public void initialize(SQLiteDatabase db) {
304                    // Get the lockscreen default from a system property, if available
305                    boolean lockScreenDisable = SystemProperties.getBoolean(
306                            "ro.lockscreen.disable.default", false);
307                    if (lockScreenDisable) {
308                        storage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
309                    }
310                }
311            });
312            return storage;
313        }
314
315        public LockSettingsStrongAuth getStrongAuth() {
316            return new LockSettingsStrongAuth(mContext);
317        }
318
319        public SynchronizedStrongAuthTracker getStrongAuthTracker() {
320            return new SynchronizedStrongAuthTracker(mContext);
321        }
322
323        public IActivityManager getActivityManager() {
324            return ActivityManager.getService();
325        }
326
327        public LockPatternUtils getLockPatternUtils() {
328            return new LockPatternUtils(mContext);
329        }
330
331        public NotificationManager getNotificationManager() {
332            return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
333        }
334
335        public UserManager getUserManager() {
336            return (UserManager) mContext.getSystemService(Context.USER_SERVICE);
337        }
338
339        public DevicePolicyManager getDevicePolicyManager() {
340            return (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
341        }
342
343        public KeyStore getKeyStore() {
344            return KeyStore.getInstance();
345        }
346
347        public IStorageManager getStorageManager() {
348            final IBinder service = ServiceManager.getService("mount");
349            if (service != null) {
350                return IStorageManager.Stub.asInterface(service);
351            }
352            return null;
353        }
354
355        public SyntheticPasswordManager getSyntheticPasswordManager(LockSettingsStorage storage) {
356            return new SyntheticPasswordManager(storage);
357        }
358
359        public int binderGetCallingUid() {
360            return Binder.getCallingUid();
361        }
362    }
363
364    public LockSettingsService(Context context) {
365        this(new Injector(context));
366    }
367
368    @VisibleForTesting
369    protected LockSettingsService(Injector injector) {
370        mInjector = injector;
371        mContext = injector.getContext();
372        mKeyStore = injector.getKeyStore();
373        mHandler = injector.getHandler();
374        mStrongAuth = injector.getStrongAuth();
375        mActivityManager = injector.getActivityManager();
376
377        mLockPatternUtils = injector.getLockPatternUtils();
378        mFirstCallToVold = true;
379
380        IntentFilter filter = new IntentFilter();
381        filter.addAction(Intent.ACTION_USER_ADDED);
382        filter.addAction(Intent.ACTION_USER_STARTING);
383        filter.addAction(Intent.ACTION_USER_REMOVED);
384        injector.getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter,
385                null, null);
386
387        mStorage = injector.getStorage();
388        mNotificationManager = injector.getNotificationManager();
389        mUserManager = injector.getUserManager();
390        mStrongAuthTracker = injector.getStrongAuthTracker();
391        mStrongAuthTracker.register(mStrongAuth);
392
393        mSpManager = injector.getSyntheticPasswordManager(mStorage);
394    }
395
396    /**
397     * If the account is credential-encrypted, show notification requesting the user to unlock the
398     * device.
399     */
400    private void maybeShowEncryptionNotificationForUser(@UserIdInt int userId) {
401        final UserInfo user = mUserManager.getUserInfo(userId);
402        if (!user.isManagedProfile()) {
403            // When the user is locked, we communicate it loud-and-clear
404            // on the lockscreen; we only show a notification below for
405            // locked managed profiles.
406            return;
407        }
408
409        final UserHandle userHandle = user.getUserHandle();
410        final boolean isSecure = isUserSecure(userId);
411        if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
412            UserInfo parent = mUserManager.getProfileParent(userId);
413            if (parent != null &&
414                    mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
415                    !mUserManager.isQuietModeEnabled(userHandle)) {
416                // Only show notifications for managed profiles once their parent
417                // user is unlocked.
418                showEncryptionNotificationForProfile(userHandle);
419            }
420        }
421    }
422
423    private void showEncryptionNotificationForProfile(UserHandle user) {
424        Resources r = mContext.getResources();
425        CharSequence title = r.getText(
426                com.android.internal.R.string.user_encrypted_title);
427        CharSequence message = r.getText(
428                com.android.internal.R.string.profile_encrypted_message);
429        CharSequence detail = r.getText(
430                com.android.internal.R.string.profile_encrypted_detail);
431
432        final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
433        final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null,
434                user.getIdentifier());
435        if (unlockIntent == null) {
436            return;
437        }
438        unlockIntent.setFlags(
439                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
440        PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
441                PendingIntent.FLAG_UPDATE_CURRENT);
442
443        showEncryptionNotification(user, title, message, detail, intent);
444    }
445
446    private void showEncryptionNotification(UserHandle user, CharSequence title,
447            CharSequence message, CharSequence detail, PendingIntent intent) {
448        if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
449
450        // Suppress all notifications on non-FBE devices for now
451        if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
452
453        Notification notification =
454                new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
455                        .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
456                        .setWhen(0)
457                        .setOngoing(true)
458                        .setTicker(title)
459                        .setColor(mContext.getColor(
460                                com.android.internal.R.color.system_notification_accent_color))
461                        .setContentTitle(title)
462                        .setContentText(message)
463                        .setSubText(detail)
464                        .setVisibility(Notification.VISIBILITY_PUBLIC)
465                        .setContentIntent(intent)
466                        .build();
467        mNotificationManager.notifyAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
468            notification, user);
469    }
470
471    private void hideEncryptionNotification(UserHandle userHandle) {
472        if (DEBUG) Slog.v(TAG, "hide encryption notification, user: " + userHandle.getIdentifier());
473        mNotificationManager.cancelAsUser(null, SystemMessage.NOTE_FBE_ENCRYPTED_NOTIFICATION,
474            userHandle);
475    }
476
477    public void onCleanupUser(int userId) {
478        hideEncryptionNotification(new UserHandle(userId));
479    }
480
481    public void onStartUser(final int userId) {
482        maybeShowEncryptionNotificationForUser(userId);
483    }
484
485    public void onUnlockUser(final int userId) {
486        // Perform tasks which require locks in LSS on a handler, as we are callbacks from
487        // ActivityManager.unlockUser()
488        mHandler.post(new Runnable() {
489            @Override
490            public void run() {
491                // Hide notification first, as tie managed profile lock takes time
492                hideEncryptionNotification(new UserHandle(userId));
493
494                // Now we have unlocked the parent user we should show notifications
495                // about any profiles that exist.
496                List<UserInfo> profiles = mUserManager.getProfiles(userId);
497                for (int i = 0; i < profiles.size(); i++) {
498                    UserInfo profile = profiles.get(i);
499                    final boolean isSecure = isUserSecure(profile.id);
500                    if (isSecure && profile.isManagedProfile()) {
501                        UserHandle userHandle = profile.getUserHandle();
502                        if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
503                                !mUserManager.isQuietModeEnabled(userHandle)) {
504                            showEncryptionNotificationForProfile(userHandle);
505                        }
506                    }
507                }
508
509                if (mUserManager.getUserInfo(userId).isManagedProfile()) {
510                    tieManagedProfileLockIfNecessary(userId, null);
511                }
512            }
513        });
514    }
515
516    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
517        @Override
518        public void onReceive(Context context, Intent intent) {
519            if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
520                // Notify keystore that a new user was added.
521                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
522                if (userHandle > UserHandle.USER_SYSTEM) {
523                    removeUser(userHandle, /* unknownUser= */ true);
524                }
525                final KeyStore ks = KeyStore.getInstance();
526                final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
527                final int parentHandle = parentInfo != null ? parentInfo.id : -1;
528                ks.onUserAdded(userHandle, parentHandle);
529            } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
530                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
531                mStorage.prefetchUser(userHandle);
532            } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
533                final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
534                if (userHandle > 0) {
535                    removeUser(userHandle, /* unknownUser= */ false);
536                }
537            }
538        }
539    };
540
541    @Override // binder interface
542    public void systemReady() {
543        migrateOldData();
544        try {
545            getGateKeeperService();
546            mSpManager.initWeaverService();
547        } catch (RemoteException e) {
548            Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
549        }
550        // TODO: maybe skip this for split system user mode.
551        mStorage.prefetchUser(UserHandle.USER_SYSTEM);
552    }
553
554    private void migrateOldData() {
555        try {
556            // These Settings moved before multi-user was enabled, so we only have to do it for the
557            // root user.
558            if (getString("migrated", null, 0) == null) {
559                final ContentResolver cr = mContext.getContentResolver();
560                for (String validSetting : VALID_SETTINGS) {
561                    String value = Settings.Secure.getString(cr, validSetting);
562                    if (value != null) {
563                        setString(validSetting, value, 0);
564                    }
565                }
566                // No need to move the password / pattern files. They're already in the right place.
567                setString("migrated", "true", 0);
568                Slog.i(TAG, "Migrated lock settings to new location");
569            }
570
571            // These Settings changed after multi-user was enabled, hence need to be moved per user.
572            if (getString("migrated_user_specific", null, 0) == null) {
573                final ContentResolver cr = mContext.getContentResolver();
574                List<UserInfo> users = mUserManager.getUsers();
575                for (int user = 0; user < users.size(); user++) {
576                    // Migrate owner info
577                    final int userId = users.get(user).id;
578                    final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
579                    String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
580                    if (!TextUtils.isEmpty(ownerInfo)) {
581                        setString(OWNER_INFO, ownerInfo, userId);
582                        Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
583                    }
584
585                    // Migrate owner info enabled. Note there was a bug where older platforms only
586                    // stored this value if the checkbox was toggled at least once. The code detects
587                    // this case by handling the exception.
588                    final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
589                    boolean enabled;
590                    try {
591                        int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
592                        enabled = ivalue != 0;
593                        setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
594                    } catch (SettingNotFoundException e) {
595                        // Setting was never stored. Store it if the string is not empty.
596                        if (!TextUtils.isEmpty(ownerInfo)) {
597                            setLong(OWNER_INFO_ENABLED, 1, userId);
598                        }
599                    }
600                    Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
601                }
602                // No need to move the password / pattern files. They're already in the right place.
603                setString("migrated_user_specific", "true", 0);
604                Slog.i(TAG, "Migrated per-user lock settings to new location");
605            }
606
607            // Migrates biometric weak such that the fallback mechanism becomes the primary.
608            if (getString("migrated_biometric_weak", null, 0) == null) {
609                List<UserInfo> users = mUserManager.getUsers();
610                for (int i = 0; i < users.size(); i++) {
611                    int userId = users.get(i).id;
612                    long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
613                            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
614                            userId);
615                    long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
616                            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
617                            userId);
618                    if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
619                        setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
620                                alternateType,
621                                userId);
622                    }
623                    setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
624                            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
625                            userId);
626                }
627                setString("migrated_biometric_weak", "true", 0);
628                Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
629            }
630
631            // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
632            // user was present on the system, so if we're upgrading to M and there is more than one
633            // user we disable the flag to remain consistent.
634            if (getString("migrated_lockscreen_disabled", null, 0) == null) {
635                final List<UserInfo> users = mUserManager.getUsers();
636                final int userCount = users.size();
637                int switchableUsers = 0;
638                for (int i = 0; i < userCount; i++) {
639                    if (users.get(i).supportsSwitchTo()) {
640                        switchableUsers++;
641                    }
642                }
643
644                if (switchableUsers > 1) {
645                    for (int i = 0; i < userCount; i++) {
646                        int id = users.get(i).id;
647
648                        if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
649                            setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
650                        }
651                    }
652                }
653
654                setString("migrated_lockscreen_disabled", "true", 0);
655                Slog.i(TAG, "Migrated lockscreen disabled flag");
656            }
657
658            final List<UserInfo> users = mUserManager.getUsers();
659            for (int i = 0; i < users.size(); i++) {
660                final UserInfo userInfo = users.get(i);
661                if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
662                    // When managed profile has a unified lock, the password quality stored has 2
663                    // possibilities only.
664                    // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
665                    // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
666                    // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
667                    // unified lock.
668                    final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
669                            DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
670                    if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
671                        // Only possible when it's upgraded from nyc dp3
672                        Slog.i(TAG, "Migrated tied profile lock type");
673                        setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
674                                DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
675                    } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
676                        // It should not happen
677                        Slog.e(TAG, "Invalid tied profile lock type: " + quality);
678                    }
679                }
680                try {
681                    final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
682                    java.security.KeyStore keyStore =
683                            java.security.KeyStore.getInstance("AndroidKeyStore");
684                    keyStore.load(null);
685                    if (keyStore.containsAlias(alias)) {
686                        keyStore.deleteEntry(alias);
687                    }
688                } catch (KeyStoreException | NoSuchAlgorithmException |
689                        CertificateException | IOException e) {
690                    Slog.e(TAG, "Unable to remove tied profile key", e);
691                }
692            }
693
694            boolean isWatch = mContext.getPackageManager().hasSystemFeature(
695                    PackageManager.FEATURE_WATCH);
696            // Wear used to set DISABLE_LOCKSCREEN to 'true', but because Wear now allows accounts
697            // and device management the lockscreen must be re-enabled now for users that upgrade.
698            if (isWatch && getString("migrated_wear_lockscreen_disabled", null, 0) == null) {
699                final int userCount = users.size();
700                for (int i = 0; i < userCount; i++) {
701                    int id = users.get(i).id;
702                    setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
703                }
704                setString("migrated_wear_lockscreen_disabled", "true", 0);
705                Slog.i(TAG, "Migrated lockscreen_disabled for Wear devices");
706            }
707        } catch (RemoteException re) {
708            Slog.e(TAG, "Unable to migrate old data", re);
709        }
710    }
711
712    private final void checkWritePermission(int userId) {
713        mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
714    }
715
716    private final void checkPasswordReadPermission(int userId) {
717        mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
718    }
719
720    private final void checkReadPermission(String requestedKey, int userId) {
721        final int callingUid = Binder.getCallingUid();
722
723        for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
724            String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
725            if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
726                    != PackageManager.PERMISSION_GRANTED) {
727                throw new SecurityException("uid=" + callingUid
728                        + " needs permission " + READ_CONTACTS + " to read "
729                        + requestedKey + " for user " + userId);
730            }
731        }
732
733        for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
734            String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
735            if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
736                    != PackageManager.PERMISSION_GRANTED) {
737                throw new SecurityException("uid=" + callingUid
738                        + " needs permission " + PERMISSION + " to read "
739                        + requestedKey + " for user " + userId);
740            }
741        }
742    }
743
744    @Override
745    public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException {
746        checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
747        synchronized (mSeparateChallengeLock) {
748            return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
749        }
750    }
751
752    @Override
753    public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
754            String managedUserPassword) throws RemoteException {
755        checkWritePermission(userId);
756        synchronized (mSeparateChallengeLock) {
757            setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
758            if (enabled) {
759                mStorage.removeChildProfileLock(userId);
760                removeKeystoreProfileKey(userId);
761            } else {
762                tieManagedProfileLockIfNecessary(userId, managedUserPassword);
763            }
764        }
765    }
766
767    @Override
768    public void setBoolean(String key, boolean value, int userId) throws RemoteException {
769        checkWritePermission(userId);
770        setStringUnchecked(key, userId, value ? "1" : "0");
771    }
772
773    @Override
774    public void setLong(String key, long value, int userId) throws RemoteException {
775        checkWritePermission(userId);
776        setStringUnchecked(key, userId, Long.toString(value));
777    }
778
779    @Override
780    public void setString(String key, String value, int userId) throws RemoteException {
781        checkWritePermission(userId);
782        setStringUnchecked(key, userId, value);
783    }
784
785    private void setStringUnchecked(String key, int userId, String value) {
786        mStorage.writeKeyValue(key, value, userId);
787        if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
788            BackupManager.dataChanged("com.android.providers.settings");
789        }
790    }
791
792    @Override
793    public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
794        checkReadPermission(key, userId);
795        String value = getStringUnchecked(key, null, userId);
796        return TextUtils.isEmpty(value) ?
797                defaultValue : (value.equals("1") || value.equals("true"));
798    }
799
800    @Override
801    public long getLong(String key, long defaultValue, int userId) throws RemoteException {
802        checkReadPermission(key, userId);
803        String value = getStringUnchecked(key, null, userId);
804        return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
805    }
806
807    @Override
808    public String getString(String key, String defaultValue, int userId) throws RemoteException {
809        checkReadPermission(key, userId);
810        return getStringUnchecked(key, defaultValue, userId);
811    }
812
813    public String getStringUnchecked(String key, String defaultValue, int userId) {
814        if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
815            long ident = Binder.clearCallingIdentity();
816            try {
817                return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
818            } finally {
819                Binder.restoreCallingIdentity(ident);
820            }
821        }
822
823        if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
824            key = Settings.Secure.LOCK_PATTERN_ENABLED;
825        }
826
827        return mStorage.readKeyValue(key, defaultValue, userId);
828    }
829
830    @Override
831    public boolean havePassword(int userId) throws RemoteException {
832        synchronized (mSpManager) {
833            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
834                long handle = getSyntheticPasswordHandleLocked(userId);
835                return mSpManager.getCredentialType(handle, userId) ==
836                        LockPatternUtils.CREDENTIAL_TYPE_PASSWORD;
837            }
838        }
839        // Do we need a permissions check here?
840        return mStorage.hasPassword(userId);
841    }
842
843    @Override
844    public boolean havePattern(int userId) throws RemoteException {
845        synchronized (mSpManager) {
846            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
847                long handle = getSyntheticPasswordHandleLocked(userId);
848                return mSpManager.getCredentialType(handle, userId) ==
849                        LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
850            }
851        }
852        // Do we need a permissions check here?
853        return mStorage.hasPattern(userId);
854    }
855
856    private boolean isUserSecure(int userId) {
857        synchronized (mSpManager) {
858            try {
859                if (isSyntheticPasswordBasedCredentialLocked(userId)) {
860                    long handle = getSyntheticPasswordHandleLocked(userId);
861                    return mSpManager.getCredentialType(handle, userId) !=
862                            LockPatternUtils.CREDENTIAL_TYPE_NONE;
863                }
864            } catch (RemoteException e) {
865                // fall through
866            }
867        }
868        return mStorage.hasCredential(userId);
869    }
870
871    private void setKeystorePassword(String password, int userHandle) {
872        final KeyStore ks = KeyStore.getInstance();
873        ks.onUserPasswordChanged(userHandle, password);
874    }
875
876    private void unlockKeystore(String password, int userHandle) {
877        if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
878        final KeyStore ks = KeyStore.getInstance();
879        ks.unlock(userHandle, password);
880    }
881
882    @VisibleForTesting
883    protected String getDecryptedPasswordForTiedProfile(int userId)
884            throws KeyStoreException, UnrecoverableKeyException,
885            NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
886            InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
887            CertificateException, IOException {
888        if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
889        byte[] storedData = mStorage.readChildProfileLock(userId);
890        if (storedData == null) {
891            throw new FileNotFoundException("Child profile lock file not found");
892        }
893        byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
894        byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
895                storedData.length);
896        byte[] decryptionResult;
897        java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
898        keyStore.load(null);
899        SecretKey decryptionKey = (SecretKey) keyStore.getKey(
900                LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
901
902        Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
903                + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
904
905        cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
906        decryptionResult = cipher.doFinal(encryptedPassword);
907        return new String(decryptionResult, StandardCharsets.UTF_8);
908    }
909
910    private void unlockChildProfile(int profileHandle) throws RemoteException {
911        try {
912            doVerifyCredential(getDecryptedPasswordForTiedProfile(profileHandle),
913                    LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
914                    false, 0 /* no challenge */, profileHandle, null /* progressCallback */);
915        } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
916                | NoSuchAlgorithmException | NoSuchPaddingException
917                | InvalidAlgorithmParameterException | IllegalBlockSizeException
918                | BadPaddingException | CertificateException | IOException e) {
919            if (e instanceof FileNotFoundException) {
920                Slog.i(TAG, "Child profile key not found");
921            } else {
922                Slog.e(TAG, "Failed to decrypt child profile key", e);
923            }
924        }
925    }
926
927    private void unlockUser(int userId, byte[] token, byte[] secret) {
928        // TODO: make this method fully async so we can update UI with progress strings
929        final CountDownLatch latch = new CountDownLatch(1);
930        final IProgressListener listener = new IProgressListener.Stub() {
931            @Override
932            public void onStarted(int id, Bundle extras) throws RemoteException {
933                Log.d(TAG, "unlockUser started");
934            }
935
936            @Override
937            public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
938                Log.d(TAG, "unlockUser progress " + progress);
939            }
940
941            @Override
942            public void onFinished(int id, Bundle extras) throws RemoteException {
943                Log.d(TAG, "unlockUser finished");
944                latch.countDown();
945            }
946        };
947
948        try {
949            mActivityManager.unlockUser(userId, token, secret, listener);
950        } catch (RemoteException e) {
951            throw e.rethrowAsRuntimeException();
952        }
953
954        try {
955            latch.await(15, TimeUnit.SECONDS);
956        } catch (InterruptedException e) {
957            Thread.currentThread().interrupt();
958        }
959        try {
960            if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
961                final List<UserInfo> profiles = mUserManager.getProfiles(userId);
962                for (UserInfo pi : profiles) {
963                    // Unlock managed profile with unified lock
964                    if (pi.isManagedProfile()
965                            && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
966                            && mStorage.hasChildProfileLock(pi.id)
967                            && mUserManager.isUserRunning(pi.id)) {
968                        unlockChildProfile(pi.id);
969                    }
970                }
971            }
972        } catch (RemoteException e) {
973            Log.d(TAG, "Failed to unlock child profile", e);
974        }
975    }
976
977    private Map<Integer, String> getDecryptedPasswordsForAllTiedProfiles(int userId) {
978        if (mUserManager.getUserInfo(userId).isManagedProfile()) {
979            return null;
980        }
981        Map<Integer, String> result = new ArrayMap<Integer, String>();
982        final List<UserInfo> profiles = mUserManager.getProfiles(userId);
983        final int size = profiles.size();
984        for (int i = 0; i < size; i++) {
985            final UserInfo profile = profiles.get(i);
986            if (!profile.isManagedProfile()) {
987                continue;
988            }
989            final int managedUserId = profile.id;
990            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
991                continue;
992            }
993            try {
994                result.put(userId, getDecryptedPasswordForTiedProfile(userId));
995            } catch (KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException
996                    | NoSuchPaddingException | InvalidKeyException
997                    | InvalidAlgorithmParameterException | IllegalBlockSizeException
998                    | BadPaddingException | CertificateException | IOException e) {
999                // ignore
1000            }
1001        }
1002        return result;
1003    }
1004
1005    /**
1006     * Synchronize all profile's work challenge of the given user if it's unified: tie or clear them
1007     * depending on the parent user's secure state.
1008     *
1009     * When clearing tied work challenges, a pre-computed password table for profiles are required,
1010     * since changing password for profiles requires existing password, and existing passwords can
1011     * only be computed before the parent user's password is cleared.
1012     *
1013     * Strictly this is a recursive function, since setLockCredentialInternal ends up calling this
1014     * method again on profiles. However the recursion is guaranteed to terminate as this method
1015     * terminates when the user is a managed profile.
1016     */
1017    private void synchronizeUnifiedWorkChallengeForProfiles(int userId,
1018            Map<Integer, String> profilePasswordMap) throws RemoteException {
1019        if (mUserManager.getUserInfo(userId).isManagedProfile()) {
1020            return;
1021        }
1022        final boolean isSecure = isUserSecure(userId);
1023        final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1024        final int size = profiles.size();
1025        for (int i = 0; i < size; i++) {
1026            final UserInfo profile = profiles.get(i);
1027            if (profile.isManagedProfile()) {
1028                final int managedUserId = profile.id;
1029                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
1030                    continue;
1031                }
1032                if (isSecure) {
1033                    tieManagedProfileLockIfNecessary(managedUserId, null);
1034                } else {
1035                    // We use cached work profile password computed before clearing the parent's
1036                    // credential, otherwise they get lost
1037                    if (profilePasswordMap != null && profilePasswordMap.containsKey(managedUserId)) {
1038                        setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE,
1039                                profilePasswordMap.get(managedUserId), managedUserId);
1040                    } else {
1041                        Slog.wtf(TAG, "clear tied profile challenges, but no password supplied.");
1042                        // Supplying null here would lead to untrusted credential change
1043                        setLockCredentialInternal(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null,
1044                                managedUserId);
1045                    }
1046                    mStorage.removeChildProfileLock(managedUserId);
1047                    removeKeystoreProfileKey(managedUserId);
1048                }
1049            }
1050        }
1051    }
1052
1053    private boolean isManagedProfileWithUnifiedLock(int userId) {
1054        return mUserManager.getUserInfo(userId).isManagedProfile()
1055                && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1056    }
1057
1058    private boolean isManagedProfileWithSeparatedLock(int userId) {
1059        return mUserManager.getUserInfo(userId).isManagedProfile()
1060                && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
1061    }
1062
1063    // This method should be called by LockPatternUtil only, all internal methods in this class
1064    // should call setLockCredentialInternal.
1065    @Override
1066    public void setLockCredential(String credential, int type, String savedCredential, int userId)
1067            throws RemoteException {
1068        checkWritePermission(userId);
1069        synchronized (mSeparateChallengeLock) {
1070            setLockCredentialInternal(credential, type, savedCredential, userId);
1071            setSeparateProfileChallengeEnabled(userId, true, null);
1072            notifyPasswordChanged(userId);
1073        }
1074    }
1075
1076    private void setLockCredentialInternal(String credential, int credentialType,
1077            String savedCredential, int userId) throws RemoteException {
1078        // Normalize savedCredential and credential such that empty string is always represented
1079        // as null.
1080        if (TextUtils.isEmpty(savedCredential)) {
1081            savedCredential = null;
1082        }
1083        if (TextUtils.isEmpty(credential)) {
1084            credential = null;
1085        }
1086        synchronized (mSpManager) {
1087            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1088                spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
1089                        userId);
1090                return;
1091            }
1092        }
1093        if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1094            if (credential != null) {
1095                Slog.wtf(TAG, "CredentialType is none, but credential is non-null.");
1096            }
1097            clearUserKeyProtection(userId);
1098            getGateKeeperService().clearSecureUserId(userId);
1099            mStorage.writeCredentialHash(CredentialHash.createEmptyHash(), userId);
1100            setKeystorePassword(null, userId);
1101            fixateNewestUserKeyAuth(userId);
1102            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
1103            notifyActivePasswordMetricsAvailable(null, userId);
1104            return;
1105        }
1106        if (credential == null) {
1107            throw new RemoteException("Null credential with mismatched credential type");
1108        }
1109
1110        CredentialHash currentHandle = mStorage.readCredentialHash(userId);
1111        if (isManagedProfileWithUnifiedLock(userId)) {
1112            // get credential from keystore when managed profile has unified lock
1113            if (savedCredential == null) {
1114                try {
1115                    savedCredential = getDecryptedPasswordForTiedProfile(userId);
1116                } catch (FileNotFoundException e) {
1117                    Slog.i(TAG, "Child profile key not found");
1118                } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1119                        | NoSuchAlgorithmException | NoSuchPaddingException
1120                        | InvalidAlgorithmParameterException | IllegalBlockSizeException
1121                        | BadPaddingException | CertificateException | IOException e) {
1122                    Slog.e(TAG, "Failed to decrypt child profile key", e);
1123                }
1124            }
1125        } else {
1126            if (currentHandle.hash == null) {
1127                if (savedCredential != null) {
1128                    Slog.w(TAG, "Saved credential provided, but none stored");
1129                }
1130                savedCredential = null;
1131            }
1132        }
1133        synchronized (mSpManager) {
1134            if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1135                initializeSyntheticPasswordLocked(currentHandle.hash, savedCredential,
1136                        currentHandle.type, userId);
1137                spBasedSetLockCredentialInternalLocked(credential, credentialType, savedCredential,
1138                        userId);
1139                return;
1140            }
1141        }
1142        if (DEBUG) Slog.d(TAG, "setLockCredentialInternal: user=" + userId);
1143        byte[] enrolledHandle = enrollCredential(currentHandle.hash, savedCredential, credential,
1144                userId);
1145        if (enrolledHandle != null) {
1146            CredentialHash willStore = CredentialHash.create(enrolledHandle, credentialType);
1147            mStorage.writeCredentialHash(willStore, userId);
1148            // push new secret and auth token to vold
1149            GateKeeperResponse gkResponse = getGateKeeperService()
1150                    .verifyChallenge(userId, 0, willStore.hash, credential.getBytes());
1151            setUserKeyProtection(userId, credential, convertResponse(gkResponse));
1152            fixateNewestUserKeyAuth(userId);
1153            // Refresh the auth token
1154            doVerifyCredential(credential, credentialType, true, 0, userId, null /* progressCallback */);
1155            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
1156        } else {
1157            throw new RemoteException("Failed to enroll " +
1158                    (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? "password"
1159                            : "pattern"));
1160        }
1161    }
1162
1163    private VerifyCredentialResponse convertResponse(GateKeeperResponse gateKeeperResponse) {
1164        VerifyCredentialResponse response;
1165        int responseCode = gateKeeperResponse.getResponseCode();
1166        if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
1167            response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
1168        } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
1169            byte[] token = gateKeeperResponse.getPayload();
1170            if (token == null) {
1171                // something's wrong if there's no payload with a challenge
1172                Slog.e(TAG, "verifyChallenge response had no associated payload");
1173                response = VerifyCredentialResponse.ERROR;
1174            } else {
1175                response = new VerifyCredentialResponse(token);
1176            }
1177        } else {
1178            response = VerifyCredentialResponse.ERROR;
1179        }
1180        return response;
1181    }
1182
1183    @VisibleForTesting
1184    protected void tieProfileLockToParent(int userId, String password) {
1185        if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
1186        byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
1187        byte[] encryptionResult;
1188        byte[] iv;
1189        try {
1190            KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
1191            keyGenerator.init(new SecureRandom());
1192            SecretKey secretKey = keyGenerator.generateKey();
1193            java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1194            keyStore.load(null);
1195            try {
1196                keyStore.setEntry(
1197                        LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
1198                        new java.security.KeyStore.SecretKeyEntry(secretKey),
1199                        new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
1200                                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1201                                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1202                                .build());
1203                keyStore.setEntry(
1204                        LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
1205                        new java.security.KeyStore.SecretKeyEntry(secretKey),
1206                        new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
1207                                .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
1208                                .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
1209                                .setUserAuthenticationRequired(true)
1210                                .setUserAuthenticationValidityDurationSeconds(30)
1211                                .build());
1212                // Key imported, obtain a reference to it.
1213                SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
1214                        LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
1215                Cipher cipher = Cipher.getInstance(
1216                        KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
1217                                + KeyProperties.ENCRYPTION_PADDING_NONE);
1218                cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
1219                encryptionResult = cipher.doFinal(randomLockSeed);
1220                iv = cipher.getIV();
1221            } finally {
1222                // The original key can now be discarded.
1223                keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
1224            }
1225        } catch (CertificateException | UnrecoverableKeyException
1226                | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
1227                | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
1228            throw new RuntimeException("Failed to encrypt key", e);
1229        }
1230        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
1231        try {
1232            if (iv.length != PROFILE_KEY_IV_SIZE) {
1233                throw new RuntimeException("Invalid iv length: " + iv.length);
1234            }
1235            outputStream.write(iv);
1236            outputStream.write(encryptionResult);
1237        } catch (IOException e) {
1238            throw new RuntimeException("Failed to concatenate byte arrays", e);
1239        }
1240        mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
1241    }
1242
1243    private byte[] enrollCredential(byte[] enrolledHandle,
1244            String enrolledCredential, String toEnroll, int userId)
1245            throws RemoteException {
1246        checkWritePermission(userId);
1247        byte[] enrolledCredentialBytes = enrolledCredential == null
1248                ? null
1249                : enrolledCredential.getBytes();
1250        byte[] toEnrollBytes = toEnroll == null
1251                ? null
1252                : toEnroll.getBytes();
1253        GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
1254                enrolledCredentialBytes, toEnrollBytes);
1255
1256        if (response == null) {
1257            return null;
1258        }
1259
1260        byte[] hash = response.getPayload();
1261        if (hash != null) {
1262            setKeystorePassword(toEnroll, userId);
1263        } else {
1264            // Should not happen
1265            Slog.e(TAG, "Throttled while enrolling a password");
1266        }
1267        return hash;
1268    }
1269
1270    private void setAuthlessUserKeyProtection(int userId, byte[] key) throws RemoteException {
1271        if (DEBUG) Slog.d(TAG, "setAuthlessUserKeyProtectiond: user=" + userId);
1272        addUserKeyAuth(userId, null, key);
1273    }
1274
1275    private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
1276            throws RemoteException {
1277        if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId);
1278        if (vcr == null) {
1279            throw new RemoteException("Null response verifying a credential we just set");
1280        }
1281        if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1282            throw new RemoteException("Non-OK response verifying a credential we just set: "
1283                    + vcr.getResponseCode());
1284        }
1285        byte[] token = vcr.getPayload();
1286        if (token == null) {
1287            throw new RemoteException("Empty payload verifying a credential we just set");
1288        }
1289        addUserKeyAuth(userId, token, secretFromCredential(credential));
1290    }
1291
1292    private void clearUserKeyProtection(int userId) throws RemoteException {
1293        if (DEBUG) Slog.d(TAG, "clearUserKeyProtection user=" + userId);
1294        addUserKeyAuth(userId, null, null);
1295    }
1296
1297    private static byte[] secretFromCredential(String credential) throws RemoteException {
1298        try {
1299            MessageDigest digest = MessageDigest.getInstance("SHA-512");
1300            // Personalize the hash
1301            byte[] personalization = "Android FBE credential hash"
1302                    .getBytes(StandardCharsets.UTF_8);
1303            // Pad it to the block size of the hash function
1304            personalization = Arrays.copyOf(personalization, 128);
1305            digest.update(personalization);
1306            digest.update(credential.getBytes(StandardCharsets.UTF_8));
1307            return digest.digest();
1308        } catch (NoSuchAlgorithmException e) {
1309            throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
1310        }
1311    }
1312
1313    private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
1314            throws RemoteException {
1315        final UserInfo userInfo = mUserManager.getUserInfo(userId);
1316        final IStorageManager storageManager = mInjector.getStorageManager();
1317        final long callingId = Binder.clearCallingIdentity();
1318        try {
1319            storageManager.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
1320        } finally {
1321            Binder.restoreCallingIdentity(callingId);
1322        }
1323    }
1324
1325    private void fixateNewestUserKeyAuth(int userId)
1326            throws RemoteException {
1327        if (DEBUG) Slog.d(TAG, "fixateNewestUserKeyAuth: user=" + userId);
1328        final IStorageManager storageManager = mInjector.getStorageManager();
1329        final long callingId = Binder.clearCallingIdentity();
1330        try {
1331            storageManager.fixateNewestUserKeyAuth(userId);
1332        } finally {
1333            Binder.restoreCallingIdentity(callingId);
1334        }
1335    }
1336
1337    @Override
1338    public void resetKeyStore(int userId) throws RemoteException {
1339        checkWritePermission(userId);
1340        if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
1341        int managedUserId = -1;
1342        String managedUserDecryptedPassword = null;
1343        final List<UserInfo> profiles = mUserManager.getProfiles(userId);
1344        for (UserInfo pi : profiles) {
1345            // Unlock managed profile with unified lock
1346            if (pi.isManagedProfile()
1347                    && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
1348                    && mStorage.hasChildProfileLock(pi.id)) {
1349                try {
1350                    if (managedUserId == -1) {
1351                        managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
1352                        managedUserId = pi.id;
1353                    } else {
1354                        // Should not happen
1355                        Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
1356                                + ", uid2:" + pi.id);
1357                    }
1358                } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1359                        | NoSuchAlgorithmException | NoSuchPaddingException
1360                        | InvalidAlgorithmParameterException | IllegalBlockSizeException
1361                        | BadPaddingException | CertificateException | IOException e) {
1362                    Slog.e(TAG, "Failed to decrypt child profile key", e);
1363                }
1364            }
1365        }
1366        try {
1367            // Clear all the users credentials could have been installed in for this user.
1368            for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
1369                for (int uid : SYSTEM_CREDENTIAL_UIDS) {
1370                    mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
1371                }
1372            }
1373        } finally {
1374            if (managedUserId != -1 && managedUserDecryptedPassword != null) {
1375                if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
1376                tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
1377            }
1378        }
1379    }
1380
1381    @Override
1382    public VerifyCredentialResponse checkCredential(String credential, int type, int userId,
1383            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1384        checkPasswordReadPermission(userId);
1385        return doVerifyCredential(credential, type, false, 0, userId, progressCallback);
1386    }
1387
1388    @Override
1389    public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge,
1390            int userId) throws RemoteException {
1391        checkPasswordReadPermission(userId);
1392        return doVerifyCredential(credential, type, true, challenge, userId,
1393                null /* progressCallback */);
1394    }
1395
1396    /**
1397     * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero
1398     * format.
1399     */
1400    private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType,
1401            boolean hasChallenge, long challenge, int userId,
1402            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1403        if (TextUtils.isEmpty(credential)) {
1404            throw new IllegalArgumentException("Credential can't be null or empty");
1405        }
1406        synchronized (mSpManager) {
1407            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
1408                VerifyCredentialResponse response = spBasedDoVerifyCredentialLocked(credential,
1409                        credentialType, hasChallenge, challenge, userId, progressCallback);
1410                if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1411                    mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1412                }
1413                return response;
1414            }
1415        }
1416        CredentialHash storedHash = mStorage.readCredentialHash(userId);
1417        if (storedHash.type != credentialType) {
1418            Slog.wtf(TAG, "doVerifyCredential type mismatch with stored credential??"
1419                    + " stored: " + storedHash.type + " passed in: " + credentialType);
1420            return VerifyCredentialResponse.ERROR;
1421        }
1422
1423        boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN
1424                && storedHash.isBaseZeroPattern;
1425
1426        String credentialToVerify;
1427        if (shouldReEnrollBaseZero) {
1428            credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential);
1429        } else {
1430            credentialToVerify = credential;
1431        }
1432
1433        VerifyCredentialResponse response = verifyCredential(userId, storedHash, credentialToVerify,
1434                hasChallenge, challenge, progressCallback);
1435
1436        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1437            mStrongAuth.reportSuccessfulStrongAuthUnlock(userId);
1438            if (shouldReEnrollBaseZero) {
1439                setLockCredentialInternal(credential, storedHash.type, credentialToVerify, userId);
1440            }
1441        }
1442
1443        return response;
1444    }
1445
1446    @Override
1447    public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type,
1448            long challenge, int userId) throws RemoteException {
1449        checkPasswordReadPermission(userId);
1450        if (!isManagedProfileWithUnifiedLock(userId)) {
1451            throw new RemoteException("User id must be managed profile with unified lock");
1452        }
1453        final int parentProfileId = mUserManager.getProfileParent(userId).id;
1454        // Unlock parent by using parent's challenge
1455        final VerifyCredentialResponse parentResponse = doVerifyCredential(
1456                credential,
1457                type,
1458                true /* hasChallenge */,
1459                challenge,
1460                parentProfileId,
1461                null /* progressCallback */);
1462        if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1463            // Failed, just return parent's response
1464            return parentResponse;
1465        }
1466
1467        try {
1468            // Unlock work profile, and work profile with unified lock must use password only
1469            return doVerifyCredential(getDecryptedPasswordForTiedProfile(userId),
1470                    LockPatternUtils.CREDENTIAL_TYPE_PASSWORD,
1471                    true,
1472                    challenge,
1473                    userId, null /* progressCallback */);
1474        } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
1475                | NoSuchAlgorithmException | NoSuchPaddingException
1476                | InvalidAlgorithmParameterException | IllegalBlockSizeException
1477                | BadPaddingException | CertificateException | IOException e) {
1478            Slog.e(TAG, "Failed to decrypt child profile key", e);
1479            throw new RemoteException("Unable to get tied profile token");
1480        }
1481    }
1482
1483    /**
1484     * Lowest-level credential verification routine that talks to GateKeeper. If verification
1485     * passes, unlock the corresponding user and keystore. Also handles the migration from legacy
1486     * hash to GK.
1487     */
1488    private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
1489            String credential, boolean hasChallenge, long challenge,
1490            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1491        if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
1492            // don't need to pass empty credentials to GateKeeper
1493            return VerifyCredentialResponse.OK;
1494        }
1495
1496        if (storedHash == null || TextUtils.isEmpty(credential)) {
1497            return VerifyCredentialResponse.ERROR;
1498        }
1499
1500        // We're potentially going to be doing a bunch of disk I/O below as part
1501        // of unlocking the user, so yell if calling from the main thread.
1502        StrictMode.noteDiskRead();
1503
1504        if (storedHash.version == CredentialHash.VERSION_LEGACY) {
1505            final byte[] hash;
1506            if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1507                hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential));
1508            } else {
1509                hash = mLockPatternUtils.passwordToHash(credential, userId);
1510            }
1511            if (Arrays.equals(hash, storedHash.hash)) {
1512                if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) {
1513                    unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId);
1514                } else {
1515                    unlockKeystore(credential, userId);
1516                }
1517                // Users with legacy credentials don't have credential-backed
1518                // FBE keys, so just pass through a fake token/secret
1519                Slog.i(TAG, "Unlocking user with fake token: " + userId);
1520                final byte[] fakeToken = String.valueOf(userId).getBytes();
1521                unlockUser(userId, fakeToken, fakeToken);
1522
1523                // migrate credential to GateKeeper
1524                setLockCredentialInternal(credential, storedHash.type, null, userId);
1525                if (!hasChallenge) {
1526                    notifyActivePasswordMetricsAvailable(credential, userId);
1527                    return VerifyCredentialResponse.OK;
1528                }
1529                // Fall through to get the auth token. Technically this should never happen,
1530                // as a user that had a legacy credential would have to unlock their device
1531                // before getting to a flow with a challenge, but supporting for consistency.
1532            } else {
1533                return VerifyCredentialResponse.ERROR;
1534            }
1535        }
1536        GateKeeperResponse gateKeeperResponse = getGateKeeperService()
1537                .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
1538        VerifyCredentialResponse response = convertResponse(gateKeeperResponse);
1539        boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
1540
1541        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1542
1543            // credential has matched
1544
1545            if (progressCallback != null) {
1546                progressCallback.onCredentialVerified();
1547            }
1548            notifyActivePasswordMetricsAvailable(credential, userId);
1549            unlockKeystore(credential, userId);
1550
1551            Slog.i(TAG, "Unlocking user " + userId + " with token length "
1552                    + response.getPayload().length);
1553            unlockUser(userId, response.getPayload(), secretFromCredential(credential));
1554
1555            if (isManagedProfileWithSeparatedLock(userId)) {
1556                TrustManager trustManager =
1557                        (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1558                trustManager.setDeviceLockedForUser(userId, false);
1559            }
1560            if (shouldReEnroll) {
1561                setLockCredentialInternal(credential, storedHash.type, credential, userId);
1562            } else {
1563                // Now that we've cleared of all required GK migration, let's do the final
1564                // migration to synthetic password.
1565                synchronized (mSpManager) {
1566                    if (shouldMigrateToSyntheticPasswordLocked(userId)) {
1567                        AuthenticationToken auth = initializeSyntheticPasswordLocked(
1568                                storedHash.hash, credential, storedHash.type, userId);
1569                        activateEscrowTokens(auth, userId);
1570                    }
1571                }
1572            }
1573        } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1574            if (response.getTimeout() > 0) {
1575                requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1576            }
1577        }
1578
1579        return response;
1580    }
1581
1582    private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) {
1583        final PasswordMetrics metrics;
1584        if (password == null) {
1585            metrics = new PasswordMetrics();
1586        } else {
1587            metrics = PasswordMetrics.computeForPassword(password);
1588            metrics.quality = mLockPatternUtils.getKeyguardStoredPasswordQuality(userId);
1589        }
1590
1591        // Asynchronous to avoid dead lock
1592        mHandler.post(() -> {
1593            DevicePolicyManager dpm = (DevicePolicyManager)
1594                    mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1595            dpm.setActivePasswordState(metrics, userId);
1596        });
1597    }
1598
1599    /**
1600     * Call after {@link #notifyActivePasswordMetricsAvailable} so metrics are updated before
1601     * reporting the password changed.
1602     */
1603    private void notifyPasswordChanged(@UserIdInt int userId) {
1604        // Same handler as notifyActivePasswordMetricsAvailable to ensure correct ordering
1605        mHandler.post(() -> {
1606            DevicePolicyManager dpm = (DevicePolicyManager)
1607                    mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
1608            dpm.reportPasswordChanged(userId);
1609        });
1610    }
1611
1612    @Override
1613    public boolean checkVoldPassword(int userId) throws RemoteException {
1614        if (!mFirstCallToVold) {
1615            return false;
1616        }
1617        mFirstCallToVold = false;
1618
1619        checkPasswordReadPermission(userId);
1620
1621        // There's no guarantee that this will safely connect, but if it fails
1622        // we will simply show the lock screen when we shouldn't, so relatively
1623        // benign. There is an outside chance something nasty would happen if
1624        // this service restarted before vold stales out the password in this
1625        // case. The nastiness is limited to not showing the lock screen when
1626        // we should, within the first minute of decrypting the phone if this
1627        // service can't connect to vold, it restarts, and then the new instance
1628        // does successfully connect.
1629        final IStorageManager service = mInjector.getStorageManager();
1630        String password;
1631        long identity = Binder.clearCallingIdentity();
1632        try {
1633            password = service.getPassword();
1634            service.clearPassword();
1635        } finally {
1636            Binder.restoreCallingIdentity(identity);
1637        }
1638        if (password == null) {
1639            return false;
1640        }
1641
1642        try {
1643            if (mLockPatternUtils.isLockPatternEnabled(userId)) {
1644                if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId,
1645                        null /* progressCallback */)
1646                                .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1647                    return true;
1648                }
1649            }
1650        } catch (Exception e) {
1651        }
1652
1653        try {
1654            if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
1655                if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId,
1656                        null /* progressCallback */)
1657                                .getResponseCode() == GateKeeperResponse.RESPONSE_OK) {
1658                    return true;
1659                }
1660            }
1661        } catch (Exception e) {
1662        }
1663
1664        return false;
1665    }
1666
1667    private void removeUser(int userId, boolean unknownUser) {
1668        mSpManager.removeUser(userId);
1669        mStorage.removeUser(userId);
1670        mStrongAuth.removeUser(userId);
1671
1672        final KeyStore ks = KeyStore.getInstance();
1673        ks.onUserRemoved(userId);
1674
1675        try {
1676            final IGateKeeperService gk = getGateKeeperService();
1677            if (gk != null) {
1678                gk.clearSecureUserId(userId);
1679            }
1680        } catch (RemoteException ex) {
1681            Slog.w(TAG, "unable to clear GK secure user id");
1682        }
1683        if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
1684            removeKeystoreProfileKey(userId);
1685        }
1686    }
1687
1688    private void removeKeystoreProfileKey(int targetUserId) {
1689        if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
1690        try {
1691            java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
1692            keyStore.load(null);
1693            keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
1694            keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
1695        } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
1696                | IOException e) {
1697            // We have tried our best to remove all keys
1698            Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
1699        }
1700    }
1701
1702    @Override
1703    public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
1704        checkPasswordReadPermission(UserHandle.USER_ALL);
1705        mStrongAuth.registerStrongAuthTracker(tracker);
1706    }
1707
1708    @Override
1709    public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
1710        checkPasswordReadPermission(UserHandle.USER_ALL);
1711        mStrongAuth.unregisterStrongAuthTracker(tracker);
1712    }
1713
1714    @Override
1715    public void requireStrongAuth(int strongAuthReason, int userId) {
1716        checkWritePermission(userId);
1717        mStrongAuth.requireStrongAuth(strongAuthReason, userId);
1718    }
1719
1720    @Override
1721    public void userPresent(int userId) {
1722        checkWritePermission(userId);
1723        mStrongAuth.reportUnlock(userId);
1724    }
1725
1726    @Override
1727    public int getStrongAuthForUser(int userId) {
1728        checkPasswordReadPermission(userId);
1729        return mStrongAuthTracker.getStrongAuthForUser(userId);
1730    }
1731
1732    private boolean isCallerShell() {
1733        final int callingUid = Binder.getCallingUid();
1734        return callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
1735    }
1736
1737    private void enforceShell() {
1738        if (!isCallerShell()) {
1739            throw new SecurityException("Caller must be shell");
1740        }
1741    }
1742
1743    @Override
1744    public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
1745            String[] args, ShellCallback callback, ResultReceiver resultReceiver)
1746            throws RemoteException {
1747        enforceShell();
1748        final long origId = Binder.clearCallingIdentity();
1749        try {
1750            (new LockSettingsShellCommand(mContext, new LockPatternUtils(mContext))).exec(
1751                    this, in, out, err, args, callback, resultReceiver);
1752        } finally {
1753            Binder.restoreCallingIdentity(origId);
1754        }
1755    }
1756
1757    private static final String[] VALID_SETTINGS = new String[] {
1758            LockPatternUtils.LOCKOUT_PERMANENT_KEY,
1759            LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
1760            LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
1761            LockPatternUtils.PASSWORD_TYPE_KEY,
1762            LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
1763            LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1764            LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
1765            LockPatternUtils.LOCKSCREEN_OPTIONS,
1766            LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
1767            LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
1768            LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
1769            LockPatternUtils.PASSWORD_HISTORY_KEY,
1770            Secure.LOCK_PATTERN_ENABLED,
1771            Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
1772            Secure.LOCK_PATTERN_VISIBLE,
1773            Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
1774    };
1775
1776    // Reading these settings needs the contacts permission
1777    private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
1778            Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1779            Secure.LOCK_SCREEN_OWNER_INFO
1780    };
1781
1782    // Reading these settings needs the same permission as checking the password
1783    private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
1784            LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
1785            LockPatternUtils.PASSWORD_HISTORY_KEY,
1786            LockPatternUtils.PASSWORD_TYPE_KEY,
1787            SEPARATE_PROFILE_CHALLENGE_KEY
1788    };
1789
1790    private static final String[] SETTINGS_TO_BACKUP = new String[] {
1791            Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
1792            Secure.LOCK_SCREEN_OWNER_INFO
1793    };
1794
1795    private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
1796        @Override
1797        public void binderDied() {
1798            mGateKeeperService.asBinder().unlinkToDeath(this, 0);
1799            mGateKeeperService = null;
1800        }
1801    }
1802
1803    protected synchronized IGateKeeperService getGateKeeperService()
1804            throws RemoteException {
1805        if (mGateKeeperService != null) {
1806            return mGateKeeperService;
1807        }
1808
1809        final IBinder service = ServiceManager.getService(Context.GATEKEEPER_SERVICE);
1810        if (service != null) {
1811            service.linkToDeath(new GateKeeperDiedRecipient(), 0);
1812            mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
1813            return mGateKeeperService;
1814        }
1815
1816        Slog.e(TAG, "Unable to acquire GateKeeperService");
1817        return null;
1818    }
1819
1820    /**
1821     * Precondition: vold and keystore unlocked.
1822     *
1823     * Create new synthetic password, set up synthetic password blob protected by the supplied
1824     * user credential, and make the newly-created SP blob active.
1825     *
1826     * The invariant under a synthetic password is:
1827     * 1. If user credential exists, then both vold and keystore and protected with keys derived
1828     *     from the synthetic password.
1829     * 2. If user credential does not exist, vold and keystore protection are cleared. This is to
1830     *     make it consistent with current behaviour. It also allows ActivityManager to call
1831     *     unlockUser() with empty secret.
1832     * 3. Once a user is migrated to have synthetic password, its value will never change, no matter
1833     *     whether the user changes his lockscreen PIN or clear/reset it. When the user clears its
1834     *     lockscreen PIN, we still maintain the existing synthetic password in a password blob
1835     *     protected by a default PIN. The only exception is when the DPC performs an untrusted
1836     *     credential change, in which case we have no way to derive the existing synthetic password
1837     *     and has to create a new one.
1838     * 4. The user SID is linked with synthetic password, but its cleared/re-created when the user
1839     *     clears/re-creates his lockscreen PIN.
1840     *
1841     *
1842     * Different cases of calling this method:
1843     * 1. credentialHash != null
1844     *     This implies credential != null, a new SP blob will be provisioned, and existing SID
1845     *     migrated to associate with the new SP.
1846     *     This happens during a normal migration case when the user currently has password.
1847     *
1848     * 2. credentialhash == null and credential == null
1849     *     A new SP blob and a new SID will be created, while the user has no credentials.
1850     *     This can happens when we are activating an escrow token on a unsecured device, during
1851     *     which we want to create the SP structure with an empty user credential.
1852     *
1853     * 3. credentialhash == null and credential != null
1854     *     This is the untrusted credential reset, OR the user sets a new lockscreen password
1855     *     FOR THE FIRST TIME on a SP-enabled device. New credential and new SID will be created
1856     */
1857    private AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash,
1858            String credential, int credentialType, int userId) throws RemoteException {
1859        Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId);
1860        AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid(getGateKeeperService(),
1861                credentialHash, credential, userId);
1862        if (auth == null) {
1863            Slog.wtf(TAG, "initializeSyntheticPasswordLocked returns null auth token");
1864            return null;
1865        }
1866        long handle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
1867                credential, credentialType, auth, userId);
1868        if (credential != null) {
1869            if (credentialHash == null) {
1870                // Since when initializing SP, we didn't provide an existing password handle
1871                // for it to migrate SID, we need to create a new SID for the user.
1872                mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
1873            }
1874            mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1875            setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
1876            setKeystorePassword(auth.deriveKeyStorePassword(), userId);
1877        } else {
1878            clearUserKeyProtection(userId);
1879            setKeystorePassword(null, userId);
1880            getGateKeeperService().clearSecureUserId(userId);
1881        }
1882        fixateNewestUserKeyAuth(userId);
1883        setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, handle, userId);
1884        return auth;
1885    }
1886
1887    private long getSyntheticPasswordHandleLocked(int userId) {
1888        try {
1889            return getLong(SYNTHETIC_PASSWORD_HANDLE_KEY, 0, userId);
1890        } catch (RemoteException e) {
1891            return SyntheticPasswordManager.DEFAULT_HANDLE;
1892        }
1893    }
1894
1895    private boolean isSyntheticPasswordBasedCredentialLocked(int userId) throws RemoteException {
1896        long handle = getSyntheticPasswordHandleLocked(userId);
1897        // This is a global setting
1898        long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
1899      return enabled != 0 && handle != SyntheticPasswordManager.DEFAULT_HANDLE;
1900    }
1901
1902    private boolean shouldMigrateToSyntheticPasswordLocked(int userId) throws RemoteException {
1903        long handle = getSyntheticPasswordHandleLocked(userId);
1904        // This is a global setting
1905        long enabled = getLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 0, UserHandle.USER_SYSTEM);
1906        return enabled != 0 && handle == SyntheticPasswordManager.DEFAULT_HANDLE;
1907    }
1908
1909    private void enableSyntheticPasswordLocked() throws RemoteException {
1910        setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM);
1911    }
1912
1913    private VerifyCredentialResponse spBasedDoVerifyCredentialLocked(String userCredential, int
1914            credentialType, boolean hasChallenge, long challenge, int userId,
1915            ICheckCredentialProgressCallback progressCallback) throws RemoteException {
1916        if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredentialLocked: user=" + userId);
1917        if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) {
1918            userCredential = null;
1919        }
1920        long handle = getSyntheticPasswordHandleLocked(userId);
1921        AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
1922                getGateKeeperService(), handle, userCredential, userId);
1923
1924        VerifyCredentialResponse response = authResult.gkResponse;
1925        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
1926            // credential has matched
1927            // perform verifyChallenge with synthetic password which generates the real auth
1928            // token for the current user
1929            response = mSpManager.verifyChallenge(getGateKeeperService(), authResult.authToken,
1930                    challenge, userId);
1931            if (response.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
1932                Slog.wtf(TAG, "verifyChallenge with SP failed.");
1933                return VerifyCredentialResponse.ERROR;
1934            }
1935            if (progressCallback != null) {
1936                progressCallback.onCredentialVerified();
1937            }
1938            notifyActivePasswordMetricsAvailable(userCredential, userId);
1939            unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
1940
1941            final byte[] secret = authResult.authToken.deriveDiskEncryptionKey();
1942            Slog.i(TAG, "Unlocking user " + userId + " with secret only, length " + secret.length);
1943            unlockUser(userId, null, secret);
1944
1945            if (isManagedProfileWithSeparatedLock(userId)) {
1946                TrustManager trustManager =
1947                        (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
1948                trustManager.setDeviceLockedForUser(userId, false);
1949            }
1950            activateEscrowTokens(authResult.authToken, userId);
1951        } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
1952            if (response.getTimeout() > 0) {
1953                requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
1954            }
1955        }
1956
1957        return response;
1958    }
1959
1960    /**
1961     * Change the user's lockscreen password by creating a new SP blob and update the handle, based
1962     * on an existing authentication token. Even though a new SP blob is created, the underlying
1963     * synthetic password is never changed.
1964     *
1965     * When clearing credential, we keep the SP unchanged, but clear its password handle so its
1966     * SID is gone. We also clear password from (software-based) keystore and vold, which will be
1967     * added back when new password is set in future.
1968     */
1969    private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType,
1970            AuthenticationToken auth, int userId) throws RemoteException {
1971        if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId);
1972        long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(),
1973                credential, credentialType, auth, userId);
1974        final Map<Integer, String> profilePasswords;
1975        if (credential != null) {
1976            // // not needed by synchronizeUnifiedWorkChallengeForProfiles()
1977            profilePasswords = null;
1978
1979            if (mSpManager.hasSidForUser(userId)) {
1980                // We are changing password of a secured device, nothing more needed as
1981                // createPasswordBasedSyntheticPassword has already taken care of maintaining
1982                // the password handle and SID unchanged.
1983
1984                //refresh auth token
1985                mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1986            } else {
1987                // A new password is set on a previously-unsecured device, we need to generate
1988                // a new SID, and re-add keys to vold and keystore.
1989                mSpManager.newSidForUser(getGateKeeperService(), auth, userId);
1990                mSpManager.verifyChallenge(getGateKeeperService(), auth, 0L, userId);
1991                setAuthlessUserKeyProtection(userId, auth.deriveDiskEncryptionKey());
1992                fixateNewestUserKeyAuth(userId);
1993                setKeystorePassword(auth.deriveKeyStorePassword(), userId);
1994            }
1995        } else {
1996            // Cache all profile password if they use unified work challenge. This will later be
1997            // used to clear the profile's password in synchronizeUnifiedWorkChallengeForProfiles()
1998            profilePasswords = getDecryptedPasswordsForAllTiedProfiles(userId);
1999
2000            // we are clearing password of a secured device, so need to nuke SID as well.
2001            mSpManager.clearSidForUser(userId);
2002            getGateKeeperService().clearSecureUserId(userId);
2003            // Clear key from vold so ActivityManager can just unlock the user with empty secret
2004            // during boot.
2005            clearUserKeyProtection(userId);
2006            fixateNewestUserKeyAuth(userId);
2007            setKeystorePassword(null, userId);
2008        }
2009        setLong(SYNTHETIC_PASSWORD_HANDLE_KEY, newHandle, userId);
2010        synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
2011        return newHandle;
2012    }
2013
2014    private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType,
2015            String savedCredential, int userId) throws RemoteException {
2016        if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId);
2017        if (isManagedProfileWithUnifiedLock(userId)) {
2018            // get credential from keystore when managed profile has unified lock
2019            try {
2020                savedCredential = getDecryptedPasswordForTiedProfile(userId);
2021            } catch (FileNotFoundException e) {
2022                Slog.i(TAG, "Child profile key not found");
2023            } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
2024                    | NoSuchAlgorithmException | NoSuchPaddingException
2025                    | InvalidAlgorithmParameterException | IllegalBlockSizeException
2026                    | BadPaddingException | CertificateException | IOException e) {
2027                Slog.e(TAG, "Failed to decrypt child profile key", e);
2028            }
2029        }
2030        long handle = getSyntheticPasswordHandleLocked(userId);
2031        AuthenticationResult authResult = mSpManager.unwrapPasswordBasedSyntheticPassword(
2032                getGateKeeperService(), handle, savedCredential, userId);
2033        VerifyCredentialResponse response = authResult.gkResponse;
2034        AuthenticationToken auth = authResult.authToken;
2035        if (auth != null) {
2036            // We are performing a trusted credential change i.e. a correct existing credential
2037            // is provided
2038            setLockCredentialWithAuthTokenLocked(credential, credentialType, auth, userId);
2039            mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2040        } else if (response != null
2041                && response.getResponseCode() == VerifyCredentialResponse.RESPONSE_ERROR){
2042            // We are performing an untrusted credential change i.e. by DevicePolicyManager.
2043            // So provision a new SP and SID. This would invalidate existing escrow tokens.
2044            // Still support this for now but this flow will be removed in the next release.
2045
2046            Slog.w(TAG, "Untrusted credential change invoked");
2047            initializeSyntheticPasswordLocked(null, credential, credentialType, userId);
2048            synchronizeUnifiedWorkChallengeForProfiles(userId, null);
2049            mSpManager.destroyPasswordBasedSyntheticPassword(handle, userId);
2050        } else /* response == null || responseCode == VerifyCredentialResponse.RESPONSE_RETRY */ {
2051            Slog.w(TAG, "spBasedSetLockCredentialInternalLocked: " +
2052                    (response != null ? "rate limit exceeded" : "failed"));
2053            return;
2054        }
2055        notifyActivePasswordMetricsAvailable(credential, userId);
2056
2057    }
2058
2059    @Override
2060    public long addEscrowToken(byte[] token, int userId) throws RemoteException {
2061        ensureCallerSystemUid();
2062        if (DEBUG) Slog.d(TAG, "addEscrowToken: user=" + userId);
2063        synchronized (mSpManager) {
2064            enableSyntheticPasswordLocked();
2065            // Migrate to synthetic password based credentials if the user has no password,
2066            // the token can then be activated immediately.
2067            AuthenticationToken auth = null;
2068            if (!isUserSecure(userId)) {
2069                if (shouldMigrateToSyntheticPasswordLocked(userId)) {
2070                    auth = initializeSyntheticPasswordLocked(null, null,
2071                            LockPatternUtils.CREDENTIAL_TYPE_NONE, userId);
2072                } else /* isSyntheticPasswordBasedCredentialLocked(userId) */ {
2073                    long pwdHandle = getSyntheticPasswordHandleLocked(userId);
2074                    auth = mSpManager.unwrapPasswordBasedSyntheticPassword(getGateKeeperService(),
2075                            pwdHandle, null, userId).authToken;
2076                }
2077            }
2078            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2079                disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
2080                if (!mSpManager.hasEscrowData(userId)) {
2081                    throw new SecurityException("Escrow token is disabled on the current user");
2082                }
2083            }
2084            long handle = mSpManager.createTokenBasedSyntheticPassword(token, userId);
2085            if (auth != null) {
2086                mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2087            }
2088            return handle;
2089        }
2090    }
2091
2092    private void activateEscrowTokens(AuthenticationToken auth, int userId) throws RemoteException {
2093        if (DEBUG) Slog.d(TAG, "activateEscrowTokens: user=" + userId);
2094        disableEscrowTokenOnNonManagedDevicesIfNeeded(userId);
2095        synchronized (mSpManager) {
2096            for (long handle : mSpManager.getPendingTokensForUser(userId)) {
2097                Slog.i(TAG, String.format("activateEscrowTokens: %x %d ", handle, userId));
2098                mSpManager.activateTokenBasedSyntheticPassword(handle, auth, userId);
2099            }
2100        }
2101    }
2102
2103    @Override
2104    public boolean isEscrowTokenActive(long handle, int userId) throws RemoteException {
2105        ensureCallerSystemUid();
2106        synchronized (mSpManager) {
2107            return mSpManager.existsHandle(handle, userId);
2108        }
2109    }
2110
2111    @Override
2112    public boolean removeEscrowToken(long handle, int userId) throws RemoteException {
2113        ensureCallerSystemUid();
2114        synchronized (mSpManager) {
2115            if (handle == getSyntheticPasswordHandleLocked(userId)) {
2116                Slog.w(TAG, "Cannot remove password handle");
2117                return false;
2118            }
2119            if (mSpManager.removePendingToken(handle, userId)) {
2120                return true;
2121            }
2122            if (mSpManager.existsHandle(handle, userId)) {
2123                mSpManager.destroyTokenBasedSyntheticPassword(handle, userId);
2124                return true;
2125            } else {
2126                return false;
2127            }
2128        }
2129    }
2130
2131    @Override
2132    public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle,
2133            byte[] token, int userId) throws RemoteException {
2134        ensureCallerSystemUid();
2135        boolean result;
2136        synchronized (mSpManager) {
2137            if (!mSpManager.hasEscrowData(userId)) {
2138                throw new SecurityException("Escrow token is disabled on the current user");
2139            }
2140            result = setLockCredentialWithTokenInternal(credential, type, tokenHandle, token,
2141                    userId);
2142        }
2143        if (result) {
2144            synchronized (mSeparateChallengeLock) {
2145                setSeparateProfileChallengeEnabled(userId, true, null);
2146            }
2147            notifyPasswordChanged(userId);
2148        }
2149        return result;
2150    }
2151
2152    private boolean setLockCredentialWithTokenInternal(String credential, int type,
2153            long tokenHandle, byte[] token, int userId) throws RemoteException {
2154        synchronized (mSpManager) {
2155            AuthenticationResult result = mSpManager.unwrapTokenBasedSyntheticPassword(
2156                    getGateKeeperService(), tokenHandle, token, userId);
2157            if (result.authToken == null) {
2158                Slog.w(TAG, "Invalid escrow token supplied");
2159                return false;
2160            }
2161            long oldHandle = getSyntheticPasswordHandleLocked(userId);
2162            setLockCredentialWithAuthTokenLocked(credential, type, result.authToken, userId);
2163            mSpManager.destroyPasswordBasedSyntheticPassword(oldHandle, userId);
2164            return true;
2165        }
2166    }
2167
2168    @Override
2169    public void unlockUserWithToken(long tokenHandle, byte[] token, int userId)
2170            throws RemoteException {
2171        ensureCallerSystemUid();
2172        AuthenticationResult authResult;
2173        synchronized (mSpManager) {
2174            if (!mSpManager.hasEscrowData(userId)) {
2175                throw new SecurityException("Escrow token is disabled on the current user");
2176            }
2177            authResult = mSpManager.unwrapTokenBasedSyntheticPassword(getGateKeeperService(),
2178                    tokenHandle, token, userId);
2179            if (authResult.authToken == null) {
2180                Slog.w(TAG, "Invalid escrow token supplied");
2181                return;
2182            }
2183        }
2184        unlockUser(userId, null, authResult.authToken.deriveDiskEncryptionKey());
2185    }
2186
2187    @Override
2188    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args){
2189        if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
2190
2191        pw.println("Current lock settings service state:");
2192        pw.println(String.format("SP Enabled = %b",
2193                mLockPatternUtils.isSyntheticPasswordEnabled()));
2194
2195        List<UserInfo> users = mUserManager.getUsers();
2196        for (int user = 0; user < users.size(); user++) {
2197            final int userId = users.get(user).id;
2198            pw.println("    User " + userId);
2199            synchronized (mSpManager) {
2200                pw.println(String.format("        SP Handle = %x",
2201                        getSyntheticPasswordHandleLocked(userId)));
2202            }
2203            try {
2204                pw.println(String.format("        SID = %x",
2205                        getGateKeeperService().getSecureUserId(userId)));
2206            } catch (RemoteException e) {
2207                // ignore.
2208            }
2209        }
2210    }
2211
2212    private void disableEscrowTokenOnNonManagedDevicesIfNeeded(int userId) {
2213        long ident = Binder.clearCallingIdentity();
2214        try {
2215            // Managed profile should have escrow enabled
2216            if (mUserManager.getUserInfo(userId).isManagedProfile()) {
2217                Slog.i(TAG, "Managed profile can have escrow token");
2218                return;
2219            }
2220            DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
2221            // Devices with Device Owner should have escrow enabled on all users.
2222            if (dpm.getDeviceOwnerComponentOnAnyUser() != null) {
2223                Slog.i(TAG, "Corp-owned device can have escrow token");
2224                return;
2225            }
2226            // We could also have a profile owner on the given (non-managed) user for unicorn cases
2227            if (dpm.getProfileOwnerAsUser(userId) != null) {
2228                Slog.i(TAG, "User with profile owner can have escrow token");
2229                return;
2230            }
2231            // If the device is yet to be provisioned (still in SUW), there is still
2232            // a chance that Device Owner will be set on the device later, so postpone
2233            // disabling escrow token for now.
2234            if (!dpm.isDeviceProvisioned()) {
2235                Slog.i(TAG, "Postpone disabling escrow tokens until device is provisioned");
2236                return;
2237            }
2238
2239            // Escrow tokens are enabled on automotive builds.
2240            if (mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
2241                return;
2242            }
2243
2244            // Disable escrow token permanently on all other device/user types.
2245            Slog.i(TAG, "Disabling escrow token on user " + userId);
2246            if (isSyntheticPasswordBasedCredentialLocked(userId)) {
2247                mSpManager.destroyEscrowData(userId);
2248            }
2249        } catch (RemoteException e) {
2250            Slog.e(TAG, "disableEscrowTokenOnNonManagedDevices", e);
2251        } finally {
2252            Binder.restoreCallingIdentity(ident);
2253        }
2254    }
2255
2256    private void ensureCallerSystemUid() throws SecurityException {
2257        final int callingUid = mInjector.binderGetCallingUid();
2258        if (callingUid != Process.SYSTEM_UID) {
2259            throw new SecurityException("Only system can call this API.");
2260        }
2261    }
2262}
2263