Home | History | Annotate | Download | only in server
      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 
     17 package com.android.server;
     18 
     19 import android.app.ActivityManagerNative;
     20 import android.app.KeyguardManager;
     21 import android.app.Notification;
     22 import android.app.NotificationManager;
     23 import android.app.PendingIntent;
     24 import android.app.admin.DevicePolicyManager;
     25 import android.app.backup.BackupManager;
     26 import android.app.trust.IStrongAuthTracker;
     27 import android.app.trust.TrustManager;
     28 import android.content.BroadcastReceiver;
     29 import android.content.ContentResolver;
     30 import android.content.Context;
     31 import android.content.Intent;
     32 import android.content.IntentFilter;
     33 import android.content.pm.PackageManager;
     34 import android.content.pm.UserInfo;
     35 import android.content.res.Resources;
     36 
     37 import static android.Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE;
     38 import static android.content.Context.KEYGUARD_SERVICE;
     39 import static android.content.Context.USER_SERVICE;
     40 import static android.Manifest.permission.READ_CONTACTS;
     41 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT;
     42 
     43 import android.database.sqlite.SQLiteDatabase;
     44 import android.os.Binder;
     45 import android.os.Bundle;
     46 import android.os.Handler;
     47 import android.os.IBinder;
     48 import android.os.IProgressListener;
     49 import android.os.Parcel;
     50 import android.os.Process;
     51 import android.os.RemoteException;
     52 import android.os.storage.IMountService;
     53 import android.os.storage.StorageManager;
     54 import android.os.ServiceManager;
     55 import android.os.SystemProperties;
     56 import android.os.UserHandle;
     57 import android.os.UserManager;
     58 import android.provider.Settings;
     59 import android.provider.Settings.Secure;
     60 import android.provider.Settings.SettingNotFoundException;
     61 import android.security.KeyStore;
     62 import android.security.keystore.AndroidKeyStoreProvider;
     63 import android.security.keystore.KeyProperties;
     64 import android.security.keystore.KeyProtection;
     65 import android.service.gatekeeper.GateKeeperResponse;
     66 import android.service.gatekeeper.IGateKeeperService;
     67 import android.text.TextUtils;
     68 import android.util.Log;
     69 import android.util.Slog;
     70 
     71 import com.android.internal.util.ArrayUtils;
     72 import com.android.internal.widget.ICheckCredentialProgressCallback;
     73 import com.android.internal.widget.ILockSettings;
     74 import com.android.internal.widget.LockPatternUtils;
     75 import com.android.internal.widget.VerifyCredentialResponse;
     76 import com.android.server.LockSettingsStorage.CredentialHash;
     77 
     78 import libcore.util.HexEncoding;
     79 
     80 import java.io.ByteArrayOutputStream;
     81 import java.io.FileNotFoundException;
     82 import java.io.IOException;
     83 import java.nio.charset.StandardCharsets;
     84 import java.security.InvalidAlgorithmParameterException;
     85 import java.security.InvalidKeyException;
     86 import java.security.KeyStoreException;
     87 import java.security.MessageDigest;
     88 import java.security.NoSuchAlgorithmException;
     89 import java.security.SecureRandom;
     90 import java.security.UnrecoverableKeyException;
     91 import java.security.cert.CertificateException;
     92 import java.util.Arrays;
     93 import java.util.List;
     94 import java.util.concurrent.CountDownLatch;
     95 import java.util.concurrent.TimeUnit;
     96 
     97 import javax.crypto.BadPaddingException;
     98 import javax.crypto.Cipher;
     99 import javax.crypto.IllegalBlockSizeException;
    100 import javax.crypto.KeyGenerator;
    101 import javax.crypto.NoSuchPaddingException;
    102 import javax.crypto.SecretKey;
    103 import javax.crypto.spec.GCMParameterSpec;
    104 
    105 /**
    106  * Keeps the lock pattern/password data and related settings for each user.
    107  * Used by LockPatternUtils. Needs to be a service because Settings app also needs
    108  * to be able to save lockscreen information for secondary users.
    109  * @hide
    110  */
    111 public class LockSettingsService extends ILockSettings.Stub {
    112     private static final String TAG = "LockSettingsService";
    113     private static final String PERMISSION = ACCESS_KEYGUARD_SECURE_STORAGE;
    114     private static final Intent ACTION_NULL; // hack to ensure notification shows the bouncer
    115     private static final int FBE_ENCRYPTED_NOTIFICATION = 0;
    116     private static final boolean DEBUG = false;
    117 
    118     private static final int PROFILE_KEY_IV_SIZE = 12;
    119     private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
    120     private final Object mSeparateChallengeLock = new Object();
    121 
    122     private final Context mContext;
    123     private final Handler mHandler;
    124     private final LockSettingsStorage mStorage;
    125     private final LockSettingsStrongAuth mStrongAuth;
    126     private final SynchronizedStrongAuthTracker mStrongAuthTracker;
    127 
    128     private LockPatternUtils mLockPatternUtils;
    129     private boolean mFirstCallToVold;
    130     private IGateKeeperService mGateKeeperService;
    131     private NotificationManager mNotificationManager;
    132     private UserManager mUserManager;
    133 
    134     private final KeyStore mKeyStore = KeyStore.getInstance();
    135 
    136     /**
    137      * The UIDs that are used for system credential storage in keystore.
    138      */
    139     private static final int[] SYSTEM_CREDENTIAL_UIDS = {Process.WIFI_UID, Process.VPN_UID,
    140         Process.ROOT_UID, Process.SYSTEM_UID};
    141 
    142     static {
    143         // Just launch the home screen, which happens anyway
    144         ACTION_NULL = new Intent(Intent.ACTION_MAIN);
    145         ACTION_NULL.addCategory(Intent.CATEGORY_HOME);
    146     }
    147 
    148     private interface CredentialUtil {
    149         void setCredential(String credential, String savedCredential, int userId)
    150                 throws RemoteException;
    151         byte[] toHash(String credential, int userId);
    152         String adjustForKeystore(String credential);
    153     }
    154 
    155     // This class manages life cycle events for encrypted users on File Based Encryption (FBE)
    156     // devices. The most basic of these is to show/hide notifications about missing features until
    157     // the user unlocks the account and credential-encrypted storage is available.
    158     public static final class Lifecycle extends SystemService {
    159         private LockSettingsService mLockSettingsService;
    160 
    161         public Lifecycle(Context context) {
    162             super(context);
    163         }
    164 
    165         @Override
    166         public void onStart() {
    167             AndroidKeyStoreProvider.install();
    168             mLockSettingsService = new LockSettingsService(getContext());
    169             publishBinderService("lock_settings", mLockSettingsService);
    170         }
    171 
    172         @Override
    173         public void onBootPhase(int phase) {
    174             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
    175                 mLockSettingsService.maybeShowEncryptionNotifications();
    176             } else if (phase == SystemService.PHASE_BOOT_COMPLETED) {
    177                 // TODO
    178             }
    179         }
    180 
    181         @Override
    182         public void onUnlockUser(int userHandle) {
    183             mLockSettingsService.onUnlockUser(userHandle);
    184         }
    185 
    186         @Override
    187         public void onCleanupUser(int userHandle) {
    188             mLockSettingsService.onCleanupUser(userHandle);
    189         }
    190     }
    191 
    192     private class SynchronizedStrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
    193         public SynchronizedStrongAuthTracker(Context context) {
    194             super(context);
    195         }
    196 
    197         @Override
    198         protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
    199             synchronized (this) {
    200                 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
    201             }
    202         }
    203 
    204         @Override
    205         public int getStrongAuthForUser(int userId) {
    206             synchronized (this) {
    207                 return super.getStrongAuthForUser(userId);
    208             }
    209         }
    210 
    211         void register() {
    212             mStrongAuth.registerStrongAuthTracker(this.mStub);
    213         }
    214     }
    215 
    216     /**
    217      * Tie managed profile to primary profile if it is in unified mode and not tied before.
    218      *
    219      * @param managedUserId Managed profile user Id
    220      * @param managedUserPassword Managed profile original password (when it has separated lock).
    221      *            NULL when it does not have a separated lock before.
    222      */
    223     public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) {
    224         if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId);
    225         // Only for managed profile
    226         if (!UserManager.get(mContext).getUserInfo(managedUserId).isManagedProfile()) {
    227             return;
    228         }
    229         // Do not tie managed profile when work challenge is enabled
    230         if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
    231             return;
    232         }
    233         // Do not tie managed profile to parent when it's done already
    234         if (mStorage.hasChildProfileLock(managedUserId)) {
    235             return;
    236         }
    237         // Do not tie it to parent when parent does not have a screen lock
    238         final int parentId = mUserManager.getProfileParent(managedUserId).id;
    239         if (!mStorage.hasPassword(parentId) && !mStorage.hasPattern(parentId)) {
    240             if (DEBUG) Slog.v(TAG, "Parent does not have a screen lock");
    241             return;
    242         }
    243         if (DEBUG) Slog.v(TAG, "Tie managed profile to parent now!");
    244         byte[] randomLockSeed = new byte[] {};
    245         try {
    246             randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40);
    247             String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed));
    248             setLockPasswordInternal(newPassword, managedUserPassword, managedUserId);
    249             // We store a private credential for the managed user that's unlocked by the primary
    250             // account holder's credential. As such, the user will never be prompted to enter this
    251             // password directly, so we always store a password.
    252             setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    253                     DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, managedUserId);
    254             tieProfileLockToParent(managedUserId, newPassword);
    255         } catch (NoSuchAlgorithmException | RemoteException e) {
    256             Slog.e(TAG, "Fail to tie managed profile", e);
    257             // Nothing client can do to fix this issue, so we do not throw exception out
    258         }
    259     }
    260 
    261     public LockSettingsService(Context context) {
    262         mContext = context;
    263         mHandler = new Handler();
    264         mStrongAuth = new LockSettingsStrongAuth(context);
    265         // Open the database
    266 
    267         mLockPatternUtils = new LockPatternUtils(context);
    268         mFirstCallToVold = true;
    269 
    270         IntentFilter filter = new IntentFilter();
    271         filter.addAction(Intent.ACTION_USER_ADDED);
    272         filter.addAction(Intent.ACTION_USER_STARTING);
    273         filter.addAction(Intent.ACTION_USER_REMOVED);
    274         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
    275 
    276         mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
    277             @Override
    278             public void initialize(SQLiteDatabase db) {
    279                 // Get the lockscreen default from a system property, if available
    280                 boolean lockScreenDisable = SystemProperties.getBoolean(
    281                         "ro.lockscreen.disable.default", false);
    282                 if (lockScreenDisable) {
    283                     mStorage.writeKeyValue(db, LockPatternUtils.DISABLE_LOCKSCREEN_KEY, "1", 0);
    284                 }
    285             }
    286         });
    287         mNotificationManager = (NotificationManager)
    288                 mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    289         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
    290         mStrongAuthTracker = new SynchronizedStrongAuthTracker(mContext);
    291         mStrongAuthTracker.register();
    292 
    293     }
    294 
    295     /**
    296      * If the account is credential-encrypted, show notification requesting the user to unlock
    297      * the device.
    298      */
    299     private void maybeShowEncryptionNotifications() {
    300         final List<UserInfo> users = mUserManager.getUsers();
    301         for (int i = 0; i < users.size(); i++) {
    302             UserInfo user = users.get(i);
    303             UserHandle userHandle = user.getUserHandle();
    304             final boolean isSecure = mStorage.hasPassword(user.id) || mStorage.hasPattern(user.id);
    305             if (isSecure && !mUserManager.isUserUnlockingOrUnlocked(userHandle)) {
    306                 if (!user.isManagedProfile()) {
    307                     // When the user is locked, we communicate it loud-and-clear
    308                     // on the lockscreen; we only show a notification below for
    309                     // locked managed profiles.
    310                 } else {
    311                     UserInfo parent = mUserManager.getProfileParent(user.id);
    312                     if (parent != null &&
    313                             mUserManager.isUserUnlockingOrUnlocked(parent.getUserHandle()) &&
    314                             !mUserManager.isQuietModeEnabled(userHandle)) {
    315                         // Only show notifications for managed profiles once their parent
    316                         // user is unlocked.
    317                         showEncryptionNotificationForProfile(userHandle);
    318                     }
    319                 }
    320             }
    321         }
    322     }
    323 
    324     private void showEncryptionNotificationForProfile(UserHandle user) {
    325         Resources r = mContext.getResources();
    326         CharSequence title = r.getText(
    327                 com.android.internal.R.string.user_encrypted_title);
    328         CharSequence message = r.getText(
    329                 com.android.internal.R.string.profile_encrypted_message);
    330         CharSequence detail = r.getText(
    331                 com.android.internal.R.string.profile_encrypted_detail);
    332 
    333         final KeyguardManager km = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
    334         final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, user.getIdentifier());
    335         if (unlockIntent == null) {
    336             return;
    337         }
    338         unlockIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
    339         PendingIntent intent = PendingIntent.getActivity(mContext, 0, unlockIntent,
    340                 PendingIntent.FLAG_UPDATE_CURRENT);
    341 
    342         showEncryptionNotification(user, title, message, detail, intent);
    343     }
    344 
    345     private void showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message,
    346             CharSequence detail, PendingIntent intent) {
    347         if (DEBUG) Slog.v(TAG, "showing encryption notification, user: " + user.getIdentifier());
    348 
    349         // Suppress all notifications on non-FBE devices for now
    350         if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
    351 
    352         Notification notification = new Notification.Builder(mContext)
    353                 .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
    354                 .setWhen(0)
    355                 .setOngoing(true)
    356                 .setTicker(title)
    357                 .setDefaults(0)  // please be quiet
    358                 .setPriority(Notification.PRIORITY_MAX)
    359                 .setColor(mContext.getColor(
    360                         com.android.internal.R.color.system_notification_accent_color))
    361                 .setContentTitle(title)
    362                 .setContentText(message)
    363                 .setSubText(detail)
    364                 .setVisibility(Notification.VISIBILITY_PUBLIC)
    365                 .setContentIntent(intent)
    366                 .build();
    367         mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
    368     }
    369 
    370     public void hideEncryptionNotification(UserHandle userHandle) {
    371         if (DEBUG) Slog.v(TAG, "hide encryption notification, user: "+ userHandle.getIdentifier());
    372         mNotificationManager.cancelAsUser(null, FBE_ENCRYPTED_NOTIFICATION, userHandle);
    373     }
    374 
    375     public void onCleanupUser(int userId) {
    376         hideEncryptionNotification(new UserHandle(userId));
    377     }
    378 
    379     public void onUnlockUser(final int userId) {
    380         // Hide notification first, as tie managed profile lock takes time
    381         hideEncryptionNotification(new UserHandle(userId));
    382 
    383         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
    384             // As tieManagedProfileLockIfNecessary() may try to unlock user, we should not do it
    385             // in onUnlockUser() synchronously, otherwise it may cause a deadlock
    386             mHandler.post(new Runnable() {
    387                 @Override
    388                 public void run() {
    389                     tieManagedProfileLockIfNecessary(userId, null);
    390                 }
    391             });
    392         }
    393 
    394         // Now we have unlocked the parent user we should show notifications
    395         // about any profiles that exist.
    396         List<UserInfo> profiles = mUserManager.getProfiles(userId);
    397         for (int i = 0; i < profiles.size(); i++) {
    398             UserInfo profile = profiles.get(i);
    399             final boolean isSecure =
    400                     mStorage.hasPassword(profile.id) || mStorage.hasPattern(profile.id);
    401             if (isSecure && profile.isManagedProfile()) {
    402                 UserHandle userHandle = profile.getUserHandle();
    403                 if (!mUserManager.isUserUnlockingOrUnlocked(userHandle) &&
    404                         !mUserManager.isQuietModeEnabled(userHandle)) {
    405                     showEncryptionNotificationForProfile(userHandle);
    406                 }
    407             }
    408         }
    409     }
    410 
    411     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
    412         @Override
    413         public void onReceive(Context context, Intent intent) {
    414             if (Intent.ACTION_USER_ADDED.equals(intent.getAction())) {
    415                 // Notify keystore that a new user was added.
    416                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    417                 if (userHandle > UserHandle.USER_SYSTEM) {
    418                     removeUser(userHandle, /* unknownUser= */ true);
    419                 }
    420                 final KeyStore ks = KeyStore.getInstance();
    421                 final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
    422                 final int parentHandle = parentInfo != null ? parentInfo.id : -1;
    423                 ks.onUserAdded(userHandle, parentHandle);
    424             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
    425                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    426                 mStorage.prefetchUser(userHandle);
    427             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
    428                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
    429                 if (userHandle > 0) {
    430                     removeUser(userHandle, /* unknownUser= */ false);
    431                 }
    432             }
    433         }
    434     };
    435 
    436     @Override // binder interface
    437     public void systemReady() {
    438         migrateOldData();
    439         try {
    440             getGateKeeperService();
    441         } catch (RemoteException e) {
    442             Slog.e(TAG, "Failure retrieving IGateKeeperService", e);
    443         }
    444         // TODO: maybe skip this for split system user mode.
    445         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
    446     }
    447 
    448     private void migrateOldData() {
    449         try {
    450             // These Settings moved before multi-user was enabled, so we only have to do it for the
    451             // root user.
    452             if (getString("migrated", null, 0) == null) {
    453                 final ContentResolver cr = mContext.getContentResolver();
    454                 for (String validSetting : VALID_SETTINGS) {
    455                     String value = Settings.Secure.getString(cr, validSetting);
    456                     if (value != null) {
    457                         setString(validSetting, value, 0);
    458                     }
    459                 }
    460                 // No need to move the password / pattern files. They're already in the right place.
    461                 setString("migrated", "true", 0);
    462                 Slog.i(TAG, "Migrated lock settings to new location");
    463             }
    464 
    465             // These Settings changed after multi-user was enabled, hence need to be moved per user.
    466             if (getString("migrated_user_specific", null, 0) == null) {
    467                 final ContentResolver cr = mContext.getContentResolver();
    468                 List<UserInfo> users = mUserManager.getUsers();
    469                 for (int user = 0; user < users.size(); user++) {
    470                     // Migrate owner info
    471                     final int userId = users.get(user).id;
    472                     final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
    473                     String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
    474                     if (!TextUtils.isEmpty(ownerInfo)) {
    475                         setString(OWNER_INFO, ownerInfo, userId);
    476                         Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
    477                     }
    478 
    479                     // Migrate owner info enabled.  Note there was a bug where older platforms only
    480                     // stored this value if the checkbox was toggled at least once. The code detects
    481                     // this case by handling the exception.
    482                     final String OWNER_INFO_ENABLED = Secure.LOCK_SCREEN_OWNER_INFO_ENABLED;
    483                     boolean enabled;
    484                     try {
    485                         int ivalue = Settings.Secure.getIntForUser(cr, OWNER_INFO_ENABLED, userId);
    486                         enabled = ivalue != 0;
    487                         setLong(OWNER_INFO_ENABLED, enabled ? 1 : 0, userId);
    488                     } catch (SettingNotFoundException e) {
    489                         // Setting was never stored. Store it if the string is not empty.
    490                         if (!TextUtils.isEmpty(ownerInfo)) {
    491                             setLong(OWNER_INFO_ENABLED, 1, userId);
    492                         }
    493                     }
    494                     Settings.Secure.putIntForUser(cr, OWNER_INFO_ENABLED, 0, userId);
    495                 }
    496                 // No need to move the password / pattern files. They're already in the right place.
    497                 setString("migrated_user_specific", "true", 0);
    498                 Slog.i(TAG, "Migrated per-user lock settings to new location");
    499             }
    500 
    501             // Migrates biometric weak such that the fallback mechanism becomes the primary.
    502             if (getString("migrated_biometric_weak", null, 0) == null) {
    503                 List<UserInfo> users = mUserManager.getUsers();
    504                 for (int i = 0; i < users.size(); i++) {
    505                     int userId = users.get(i).id;
    506                     long type = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    507                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    508                             userId);
    509                     long alternateType = getLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
    510                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    511                             userId);
    512                     if (type == DevicePolicyManager.PASSWORD_QUALITY_BIOMETRIC_WEAK) {
    513                         setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    514                                 alternateType,
    515                                 userId);
    516                     }
    517                     setLong(LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
    518                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED,
    519                             userId);
    520                 }
    521                 setString("migrated_biometric_weak", "true", 0);
    522                 Slog.i(TAG, "Migrated biometric weak to use the fallback instead");
    523             }
    524 
    525             // Migrates lockscreen.disabled. Prior to M, the flag was ignored when more than one
    526             // user was present on the system, so if we're upgrading to M and there is more than one
    527             // user we disable the flag to remain consistent.
    528             if (getString("migrated_lockscreen_disabled", null, 0) == null) {
    529                 final List<UserInfo> users = mUserManager.getUsers();
    530                 final int userCount = users.size();
    531                 int switchableUsers = 0;
    532                 for (int i = 0; i < userCount; i++) {
    533                     if (users.get(i).supportsSwitchTo()) {
    534                         switchableUsers++;
    535                     }
    536                 }
    537 
    538                 if (switchableUsers > 1) {
    539                     for (int i = 0; i < userCount; i++) {
    540                         int id = users.get(i).id;
    541 
    542                         if (getBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id)) {
    543                             setBoolean(LockPatternUtils.DISABLE_LOCKSCREEN_KEY, false, id);
    544                         }
    545                     }
    546                 }
    547 
    548                 setString("migrated_lockscreen_disabled", "true", 0);
    549                 Slog.i(TAG, "Migrated lockscreen disabled flag");
    550             }
    551 
    552             final List<UserInfo> users = mUserManager.getUsers();
    553             for (int i = 0; i < users.size(); i++) {
    554                 final UserInfo userInfo = users.get(i);
    555                 if (userInfo.isManagedProfile() && mStorage.hasChildProfileLock(userInfo.id)) {
    556                     // When managed profile has a unified lock, the password quality stored has 2
    557                     // possibilities only.
    558                     // 1). PASSWORD_QUALITY_UNSPECIFIED, which is upgraded from dp2, and we are
    559                     // going to set it back to PASSWORD_QUALITY_ALPHANUMERIC.
    560                     // 2). PASSWORD_QUALITY_ALPHANUMERIC, which is the actual password quality for
    561                     // unified lock.
    562                     final long quality = getLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    563                             DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userInfo.id);
    564                     if (quality == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
    565                         // Only possible when it's upgraded from nyc dp3
    566                         Slog.i(TAG, "Migrated tied profile lock type");
    567                         setLong(LockPatternUtils.PASSWORD_TYPE_KEY,
    568                                 DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, userInfo.id);
    569                     } else if (quality != DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC) {
    570                         // It should not happen
    571                         Slog.e(TAG, "Invalid tied profile lock type: " + quality);
    572                     }
    573                 }
    574                 try {
    575                     final String alias = LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userInfo.id;
    576                     java.security.KeyStore keyStore =
    577                             java.security.KeyStore.getInstance("AndroidKeyStore");
    578                     keyStore.load(null);
    579                     if (keyStore.containsAlias(alias)) {
    580                         keyStore.deleteEntry(alias);
    581                     }
    582                 } catch (KeyStoreException | NoSuchAlgorithmException |
    583                         CertificateException | IOException e) {
    584                     Slog.e(TAG, "Unable to remove tied profile key", e);
    585                 }
    586             }
    587         } catch (RemoteException re) {
    588             Slog.e(TAG, "Unable to migrate old data", re);
    589         }
    590     }
    591 
    592     private final void checkWritePermission(int userId) {
    593         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
    594     }
    595 
    596     private final void checkPasswordReadPermission(int userId) {
    597         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
    598     }
    599 
    600     private final void checkReadPermission(String requestedKey, int userId) {
    601         final int callingUid = Binder.getCallingUid();
    602 
    603         for (int i = 0; i < READ_CONTACTS_PROTECTED_SETTINGS.length; i++) {
    604             String key = READ_CONTACTS_PROTECTED_SETTINGS[i];
    605             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(READ_CONTACTS)
    606                     != PackageManager.PERMISSION_GRANTED) {
    607                 throw new SecurityException("uid=" + callingUid
    608                         + " needs permission " + READ_CONTACTS + " to read "
    609                         + requestedKey + " for user " + userId);
    610             }
    611         }
    612 
    613         for (int i = 0; i < READ_PASSWORD_PROTECTED_SETTINGS.length; i++) {
    614             String key = READ_PASSWORD_PROTECTED_SETTINGS[i];
    615             if (key.equals(requestedKey) && mContext.checkCallingOrSelfPermission(PERMISSION)
    616                     != PackageManager.PERMISSION_GRANTED) {
    617                 throw new SecurityException("uid=" + callingUid
    618                         + " needs permission " + PERMISSION + " to read "
    619                         + requestedKey + " for user " + userId);
    620             }
    621         }
    622     }
    623 
    624     @Override
    625     public boolean getSeparateProfileChallengeEnabled(int userId) throws RemoteException {
    626         checkReadPermission(SEPARATE_PROFILE_CHALLENGE_KEY, userId);
    627         synchronized (mSeparateChallengeLock) {
    628             return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId);
    629         }
    630     }
    631 
    632     @Override
    633     public void setSeparateProfileChallengeEnabled(int userId, boolean enabled,
    634             String managedUserPassword) throws RemoteException {
    635         checkWritePermission(userId);
    636         synchronized (mSeparateChallengeLock) {
    637             setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId);
    638             if (enabled) {
    639                 mStorage.removeChildProfileLock(userId);
    640                 removeKeystoreProfileKey(userId);
    641             } else {
    642                 tieManagedProfileLockIfNecessary(userId, managedUserPassword);
    643             }
    644         }
    645     }
    646 
    647     @Override
    648     public void setBoolean(String key, boolean value, int userId) throws RemoteException {
    649         checkWritePermission(userId);
    650         setStringUnchecked(key, userId, value ? "1" : "0");
    651     }
    652 
    653     @Override
    654     public void setLong(String key, long value, int userId) throws RemoteException {
    655         checkWritePermission(userId);
    656         setStringUnchecked(key, userId, Long.toString(value));
    657     }
    658 
    659     @Override
    660     public void setString(String key, String value, int userId) throws RemoteException {
    661         checkWritePermission(userId);
    662         setStringUnchecked(key, userId, value);
    663     }
    664 
    665     private void setStringUnchecked(String key, int userId, String value) {
    666         mStorage.writeKeyValue(key, value, userId);
    667         if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
    668             BackupManager.dataChanged("com.android.providers.settings");
    669         }
    670     }
    671 
    672     @Override
    673     public boolean getBoolean(String key, boolean defaultValue, int userId) throws RemoteException {
    674         checkReadPermission(key, userId);
    675         String value = getStringUnchecked(key, null, userId);
    676         return TextUtils.isEmpty(value) ?
    677                 defaultValue : (value.equals("1") || value.equals("true"));
    678     }
    679 
    680     @Override
    681     public long getLong(String key, long defaultValue, int userId) throws RemoteException {
    682         checkReadPermission(key, userId);
    683         String value = getStringUnchecked(key, null, userId);
    684         return TextUtils.isEmpty(value) ? defaultValue : Long.parseLong(value);
    685     }
    686 
    687     @Override
    688     public String getString(String key, String defaultValue, int userId) throws RemoteException {
    689         checkReadPermission(key, userId);
    690         return getStringUnchecked(key, defaultValue, userId);
    691     }
    692 
    693     public String getStringUnchecked(String key, String defaultValue, int userId) {
    694         if (Settings.Secure.LOCK_PATTERN_ENABLED.equals(key)) {
    695             long ident = Binder.clearCallingIdentity();
    696             try {
    697                 return mLockPatternUtils.isLockPatternEnabled(userId) ? "1" : "0";
    698             } finally {
    699                 Binder.restoreCallingIdentity(ident);
    700             }
    701         }
    702 
    703         if (LockPatternUtils.LEGACY_LOCK_PATTERN_ENABLED.equals(key)) {
    704             key = Settings.Secure.LOCK_PATTERN_ENABLED;
    705         }
    706 
    707         return mStorage.readKeyValue(key, defaultValue, userId);
    708     }
    709 
    710     @Override
    711     public boolean havePassword(int userId) throws RemoteException {
    712         // Do we need a permissions check here?
    713         return mStorage.hasPassword(userId);
    714     }
    715 
    716     @Override
    717     public boolean havePattern(int userId) throws RemoteException {
    718         // Do we need a permissions check here?
    719         return mStorage.hasPattern(userId);
    720     }
    721 
    722     private void setKeystorePassword(String password, int userHandle) {
    723         final KeyStore ks = KeyStore.getInstance();
    724         ks.onUserPasswordChanged(userHandle, password);
    725     }
    726 
    727     private void unlockKeystore(String password, int userHandle) {
    728         if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
    729         final KeyStore ks = KeyStore.getInstance();
    730         ks.unlock(userHandle, password);
    731     }
    732 
    733     private String getDecryptedPasswordForTiedProfile(int userId)
    734             throws KeyStoreException, UnrecoverableKeyException,
    735             NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException,
    736             InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException,
    737             CertificateException, IOException {
    738         if (DEBUG) Slog.v(TAG, "Get child profile decrytped key");
    739         byte[] storedData = mStorage.readChildProfileLock(userId);
    740         if (storedData == null) {
    741             throw new FileNotFoundException("Child profile lock file not found");
    742         }
    743         byte[] iv = Arrays.copyOfRange(storedData, 0, PROFILE_KEY_IV_SIZE);
    744         byte[] encryptedPassword = Arrays.copyOfRange(storedData, PROFILE_KEY_IV_SIZE,
    745                 storedData.length);
    746         byte[] decryptionResult;
    747         java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
    748         keyStore.load(null);
    749         SecretKey decryptionKey = (SecretKey) keyStore.getKey(
    750                 LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId, null);
    751 
    752         Cipher cipher = Cipher.getInstance(KeyProperties.KEY_ALGORITHM_AES + "/"
    753                 + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE);
    754 
    755         cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv));
    756         decryptionResult = cipher.doFinal(encryptedPassword);
    757         return new String(decryptionResult, StandardCharsets.UTF_8);
    758     }
    759 
    760     private void unlockChildProfile(int profileHandle) throws RemoteException {
    761         try {
    762             doVerifyPassword(getDecryptedPasswordForTiedProfile(profileHandle), false,
    763                     0 /* no challenge */, profileHandle, null /* progressCallback */);
    764         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
    765                 | NoSuchAlgorithmException | NoSuchPaddingException
    766                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
    767                 | BadPaddingException | CertificateException | IOException e) {
    768             if (e instanceof FileNotFoundException) {
    769                 Slog.i(TAG, "Child profile key not found");
    770             } else {
    771                 Slog.e(TAG, "Failed to decrypt child profile key", e);
    772             }
    773         }
    774     }
    775 
    776     private void unlockUser(int userId, byte[] token, byte[] secret) {
    777         // TODO: make this method fully async so we can update UI with progress strings
    778         final CountDownLatch latch = new CountDownLatch(1);
    779         final IProgressListener listener = new IProgressListener.Stub() {
    780             @Override
    781             public void onStarted(int id, Bundle extras) throws RemoteException {
    782                 Log.d(TAG, "unlockUser started");
    783             }
    784 
    785             @Override
    786             public void onProgress(int id, int progress, Bundle extras) throws RemoteException {
    787                 Log.d(TAG, "unlockUser progress " + progress);
    788             }
    789 
    790             @Override
    791             public void onFinished(int id, Bundle extras) throws RemoteException {
    792                 Log.d(TAG, "unlockUser finished");
    793                 latch.countDown();
    794             }
    795         };
    796 
    797         try {
    798             ActivityManagerNative.getDefault().unlockUser(userId, token, secret, listener);
    799         } catch (RemoteException e) {
    800             throw e.rethrowAsRuntimeException();
    801         }
    802 
    803         try {
    804             latch.await(15, TimeUnit.SECONDS);
    805         } catch (InterruptedException e) {
    806             Thread.currentThread().interrupt();
    807         }
    808         try {
    809             if (!mUserManager.getUserInfo(userId).isManagedProfile()) {
    810                 final List<UserInfo> profiles = mUserManager.getProfiles(userId);
    811                 for (UserInfo pi : profiles) {
    812                     // Unlock managed profile with unified lock
    813                     if (pi.isManagedProfile()
    814                             && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
    815                             && mStorage.hasChildProfileLock(pi.id)) {
    816                         unlockChildProfile(pi.id);
    817                     }
    818                 }
    819             }
    820         } catch (RemoteException e) {
    821             Log.d(TAG, "Failed to unlock child profile", e);
    822         }
    823     }
    824 
    825     private byte[] getCurrentHandle(int userId) {
    826         CredentialHash credential;
    827         byte[] currentHandle;
    828 
    829         int currentHandleType = mStorage.getStoredCredentialType(userId);
    830         switch (currentHandleType) {
    831             case CredentialHash.TYPE_PATTERN:
    832                 credential = mStorage.readPatternHash(userId);
    833                 currentHandle = credential != null
    834                         ? credential.hash
    835                         : null;
    836                 break;
    837             case CredentialHash.TYPE_PASSWORD:
    838                 credential = mStorage.readPasswordHash(userId);
    839                 currentHandle = credential != null
    840                         ? credential.hash
    841                         : null;
    842                 break;
    843             case CredentialHash.TYPE_NONE:
    844             default:
    845                 currentHandle = null;
    846                 break;
    847         }
    848 
    849         // sanity check
    850         if (currentHandleType != CredentialHash.TYPE_NONE && currentHandle == null) {
    851             Slog.e(TAG, "Stored handle type [" + currentHandleType + "] but no handle available");
    852         }
    853 
    854         return currentHandle;
    855     }
    856 
    857     private void onUserLockChanged(int userId) throws RemoteException {
    858         if (mUserManager.getUserInfo(userId).isManagedProfile()) {
    859             return;
    860         }
    861         final boolean isSecure = mStorage.hasPassword(userId) || mStorage.hasPattern(userId);
    862         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
    863         final int size = profiles.size();
    864         for (int i = 0; i < size; i++) {
    865             final UserInfo profile = profiles.get(i);
    866             if (profile.isManagedProfile()) {
    867                 final int managedUserId = profile.id;
    868                 if (mLockPatternUtils.isSeparateProfileChallengeEnabled(managedUserId)) {
    869                     continue;
    870                 }
    871                 if (isSecure) {
    872                     tieManagedProfileLockIfNecessary(managedUserId, null);
    873                 } else {
    874                     clearUserKeyProtection(managedUserId);
    875                     getGateKeeperService().clearSecureUserId(managedUserId);
    876                     mStorage.writePatternHash(null, managedUserId);
    877                     setKeystorePassword(null, managedUserId);
    878                     fixateNewestUserKeyAuth(managedUserId);
    879                     mStorage.removeChildProfileLock(managedUserId);
    880                     removeKeystoreProfileKey(managedUserId);
    881                 }
    882             }
    883         }
    884     }
    885 
    886     private boolean isManagedProfileWithUnifiedLock(int userId) {
    887         return mUserManager.getUserInfo(userId).isManagedProfile()
    888                 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
    889     }
    890 
    891     private boolean isManagedProfileWithSeparatedLock(int userId) {
    892         return mUserManager.getUserInfo(userId).isManagedProfile()
    893                 && mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
    894     }
    895 
    896     // This method should be called by LockPatternUtil only, all internal methods in this class
    897     // should call setLockPatternInternal.
    898     @Override
    899     public void setLockPattern(String pattern, String savedCredential, int userId)
    900             throws RemoteException {
    901         checkWritePermission(userId);
    902         synchronized (mSeparateChallengeLock) {
    903             setLockPatternInternal(pattern, savedCredential, userId);
    904             setSeparateProfileChallengeEnabled(userId, true, null);
    905         }
    906     }
    907 
    908     private void setLockPatternInternal(String pattern, String savedCredential, int userId)
    909             throws RemoteException {
    910         byte[] currentHandle = getCurrentHandle(userId);
    911 
    912         if (pattern == null) {
    913             clearUserKeyProtection(userId);
    914             getGateKeeperService().clearSecureUserId(userId);
    915             mStorage.writePatternHash(null, userId);
    916             setKeystorePassword(null, userId);
    917             fixateNewestUserKeyAuth(userId);
    918             onUserLockChanged(userId);
    919             return;
    920         }
    921 
    922         if (isManagedProfileWithUnifiedLock(userId)) {
    923             // get credential from keystore when managed profile has unified lock
    924             try {
    925                 savedCredential = getDecryptedPasswordForTiedProfile(userId);
    926             } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
    927                     | NoSuchAlgorithmException | NoSuchPaddingException
    928                     | InvalidAlgorithmParameterException | IllegalBlockSizeException
    929                     | BadPaddingException | CertificateException | IOException e) {
    930                 if (e instanceof FileNotFoundException) {
    931                     Slog.i(TAG, "Child profile key not found");
    932                 } else {
    933                     Slog.e(TAG, "Failed to decrypt child profile key", e);
    934                 }
    935             }
    936         } else {
    937             if (currentHandle == null) {
    938                 if (savedCredential != null) {
    939                     Slog.w(TAG, "Saved credential provided, but none stored");
    940                 }
    941                 savedCredential = null;
    942             }
    943         }
    944 
    945         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, pattern, userId);
    946         if (enrolledHandle != null) {
    947             CredentialHash willStore
    948                 = new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
    949             setUserKeyProtection(userId, pattern,
    950                 doVerifyPattern(pattern, willStore, true, 0, userId, null /* progressCallback */));
    951             mStorage.writePatternHash(enrolledHandle, userId);
    952             fixateNewestUserKeyAuth(userId);
    953             onUserLockChanged(userId);
    954         } else {
    955             throw new RemoteException("Failed to enroll pattern");
    956         }
    957     }
    958 
    959     // This method should be called by LockPatternUtil only, all internal methods in this class
    960     // should call setLockPasswordInternal.
    961     @Override
    962     public void setLockPassword(String password, String savedCredential, int userId)
    963             throws RemoteException {
    964         checkWritePermission(userId);
    965         synchronized (mSeparateChallengeLock) {
    966             setLockPasswordInternal(password, savedCredential, userId);
    967             setSeparateProfileChallengeEnabled(userId, true, null);
    968         }
    969     }
    970 
    971     private void setLockPasswordInternal(String password, String savedCredential, int userId)
    972             throws RemoteException {
    973         byte[] currentHandle = getCurrentHandle(userId);
    974         if (password == null) {
    975             clearUserKeyProtection(userId);
    976             getGateKeeperService().clearSecureUserId(userId);
    977             mStorage.writePasswordHash(null, userId);
    978             setKeystorePassword(null, userId);
    979             fixateNewestUserKeyAuth(userId);
    980             onUserLockChanged(userId);
    981             return;
    982         }
    983 
    984         if (isManagedProfileWithUnifiedLock(userId)) {
    985             // get credential from keystore when managed profile has unified lock
    986             try {
    987                 savedCredential = getDecryptedPasswordForTiedProfile(userId);
    988             } catch (FileNotFoundException e) {
    989                 Slog.i(TAG, "Child profile key not found");
    990             } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
    991                     | NoSuchAlgorithmException | NoSuchPaddingException
    992                     | InvalidAlgorithmParameterException | IllegalBlockSizeException
    993                     | BadPaddingException | CertificateException | IOException e) {
    994                 Slog.e(TAG, "Failed to decrypt child profile key", e);
    995             }
    996         } else {
    997             if (currentHandle == null) {
    998                 if (savedCredential != null) {
    999                     Slog.w(TAG, "Saved credential provided, but none stored");
   1000                 }
   1001                 savedCredential = null;
   1002             }
   1003         }
   1004 
   1005         byte[] enrolledHandle = enrollCredential(currentHandle, savedCredential, password, userId);
   1006         if (enrolledHandle != null) {
   1007             CredentialHash willStore
   1008                 = new CredentialHash(enrolledHandle, CredentialHash.VERSION_GATEKEEPER);
   1009             setUserKeyProtection(userId, password,
   1010                 doVerifyPassword(password, willStore, true, 0, userId,
   1011                         null /* progressCallback */));
   1012             mStorage.writePasswordHash(enrolledHandle, userId);
   1013             fixateNewestUserKeyAuth(userId);
   1014             onUserLockChanged(userId);
   1015         } else {
   1016             throw new RemoteException("Failed to enroll password");
   1017         }
   1018     }
   1019 
   1020     private void tieProfileLockToParent(int userId, String password) {
   1021         if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId);
   1022         byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8);
   1023         byte[] encryptionResult;
   1024         byte[] iv;
   1025         try {
   1026             KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES);
   1027             keyGenerator.init(new SecureRandom());
   1028             SecretKey secretKey = keyGenerator.generateKey();
   1029             java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
   1030             keyStore.load(null);
   1031             try {
   1032                 keyStore.setEntry(
   1033                         LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId,
   1034                         new java.security.KeyStore.SecretKeyEntry(secretKey),
   1035                         new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT)
   1036                                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
   1037                                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
   1038                                 .build());
   1039                 keyStore.setEntry(
   1040                         LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + userId,
   1041                         new java.security.KeyStore.SecretKeyEntry(secretKey),
   1042                         new KeyProtection.Builder(KeyProperties.PURPOSE_DECRYPT)
   1043                                 .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
   1044                                 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
   1045                                 .setUserAuthenticationRequired(true)
   1046                                 .setUserAuthenticationValidityDurationSeconds(30)
   1047                                 .build());
   1048                 // Key imported, obtain a reference to it.
   1049                 SecretKey keyStoreEncryptionKey = (SecretKey) keyStore.getKey(
   1050                         LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId, null);
   1051                 Cipher cipher = Cipher.getInstance(
   1052                         KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/"
   1053                                 + KeyProperties.ENCRYPTION_PADDING_NONE);
   1054                 cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey);
   1055                 encryptionResult = cipher.doFinal(randomLockSeed);
   1056                 iv = cipher.getIV();
   1057             } finally {
   1058                 // The original key can now be discarded.
   1059                 keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + userId);
   1060             }
   1061         } catch (CertificateException | UnrecoverableKeyException
   1062                 | IOException | BadPaddingException | IllegalBlockSizeException | KeyStoreException
   1063                 | NoSuchPaddingException | NoSuchAlgorithmException | InvalidKeyException e) {
   1064             throw new RuntimeException("Failed to encrypt key", e);
   1065         }
   1066         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
   1067         try {
   1068             if (iv.length != PROFILE_KEY_IV_SIZE) {
   1069                 throw new RuntimeException("Invalid iv length: " + iv.length);
   1070             }
   1071             outputStream.write(iv);
   1072             outputStream.write(encryptionResult);
   1073         } catch (IOException e) {
   1074             throw new RuntimeException("Failed to concatenate byte arrays", e);
   1075         }
   1076         mStorage.writeChildProfileLock(userId, outputStream.toByteArray());
   1077     }
   1078 
   1079     private byte[] enrollCredential(byte[] enrolledHandle,
   1080             String enrolledCredential, String toEnroll, int userId)
   1081             throws RemoteException {
   1082         checkWritePermission(userId);
   1083         byte[] enrolledCredentialBytes = enrolledCredential == null
   1084                 ? null
   1085                 : enrolledCredential.getBytes();
   1086         byte[] toEnrollBytes = toEnroll == null
   1087                 ? null
   1088                 : toEnroll.getBytes();
   1089         GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle,
   1090                 enrolledCredentialBytes, toEnrollBytes);
   1091 
   1092         if (response == null) {
   1093             return null;
   1094         }
   1095 
   1096         byte[] hash = response.getPayload();
   1097         if (hash != null) {
   1098             setKeystorePassword(toEnroll, userId);
   1099         } else {
   1100             // Should not happen
   1101             Slog.e(TAG, "Throttled while enrolling a password");
   1102         }
   1103         return hash;
   1104     }
   1105 
   1106     private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)
   1107             throws RemoteException {
   1108         if (vcr == null) {
   1109             throw new RemoteException("Null response verifying a credential we just set");
   1110         }
   1111         if (vcr.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
   1112             throw new RemoteException("Non-OK response verifying a credential we just set: "
   1113                 + vcr.getResponseCode());
   1114         }
   1115         byte[] token = vcr.getPayload();
   1116         if (token == null) {
   1117             throw new RemoteException("Empty payload verifying a credential we just set");
   1118         }
   1119         addUserKeyAuth(userId, token, secretFromCredential(credential));
   1120     }
   1121 
   1122     private void clearUserKeyProtection(int userId) throws RemoteException {
   1123         addUserKeyAuth(userId, null, null);
   1124     }
   1125 
   1126     private static byte[] secretFromCredential(String credential) throws RemoteException {
   1127         try {
   1128             MessageDigest digest = MessageDigest.getInstance("SHA-512");
   1129             // Personalize the hash
   1130             byte[] personalization = "Android FBE credential hash"
   1131                     .getBytes(StandardCharsets.UTF_8);
   1132             // Pad it to the block size of the hash function
   1133             personalization = Arrays.copyOf(personalization, 128);
   1134             digest.update(personalization);
   1135             digest.update(credential.getBytes(StandardCharsets.UTF_8));
   1136             return digest.digest();
   1137         } catch (NoSuchAlgorithmException e) {
   1138             throw new RuntimeException("NoSuchAlgorithmException for SHA-512");
   1139         }
   1140     }
   1141 
   1142     private void addUserKeyAuth(int userId, byte[] token, byte[] secret)
   1143             throws RemoteException {
   1144         final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
   1145         final IMountService mountService = getMountService();
   1146         final long callingId = Binder.clearCallingIdentity();
   1147         try {
   1148             mountService.addUserKeyAuth(userId, userInfo.serialNumber, token, secret);
   1149         } finally {
   1150             Binder.restoreCallingIdentity(callingId);
   1151         }
   1152     }
   1153 
   1154     private void fixateNewestUserKeyAuth(int userId)
   1155             throws RemoteException {
   1156         final IMountService mountService = getMountService();
   1157         final long callingId = Binder.clearCallingIdentity();
   1158         try {
   1159             mountService.fixateNewestUserKeyAuth(userId);
   1160         } finally {
   1161             Binder.restoreCallingIdentity(callingId);
   1162         }
   1163     }
   1164 
   1165     @Override
   1166     public void resetKeyStore(int userId) throws RemoteException {
   1167         checkWritePermission(userId);
   1168         if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId);
   1169         int managedUserId = -1;
   1170         String managedUserDecryptedPassword = null;
   1171         final List<UserInfo> profiles = mUserManager.getProfiles(userId);
   1172         for (UserInfo pi : profiles) {
   1173             // Unlock managed profile with unified lock
   1174             if (pi.isManagedProfile()
   1175                     && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id)
   1176                     && mStorage.hasChildProfileLock(pi.id)) {
   1177                 try {
   1178                     if (managedUserId == -1) {
   1179                         managedUserDecryptedPassword = getDecryptedPasswordForTiedProfile(pi.id);
   1180                         managedUserId = pi.id;
   1181                     } else {
   1182                         // Should not happen
   1183                         Slog.e(TAG, "More than one managed profile, uid1:" + managedUserId
   1184                                 + ", uid2:" + pi.id);
   1185                     }
   1186                 } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
   1187                         | NoSuchAlgorithmException | NoSuchPaddingException
   1188                         | InvalidAlgorithmParameterException | IllegalBlockSizeException
   1189                         | BadPaddingException | CertificateException | IOException e) {
   1190                     Slog.e(TAG, "Failed to decrypt child profile key", e);
   1191                 }
   1192             }
   1193         }
   1194         try {
   1195             // Clear all the users credentials could have been installed in for this user.
   1196             for (int profileId : mUserManager.getProfileIdsWithDisabled(userId)) {
   1197                 for (int uid : SYSTEM_CREDENTIAL_UIDS) {
   1198                     mKeyStore.clearUid(UserHandle.getUid(profileId, uid));
   1199                 }
   1200             }
   1201         } finally {
   1202             if (managedUserId != -1 && managedUserDecryptedPassword != null) {
   1203                 if (DEBUG) Slog.v(TAG, "Restore tied profile lock");
   1204                 tieProfileLockToParent(managedUserId, managedUserDecryptedPassword);
   1205             }
   1206         }
   1207     }
   1208 
   1209     @Override
   1210     public VerifyCredentialResponse checkPattern(String pattern, int userId,
   1211             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
   1212         return doVerifyPattern(pattern, false, 0, userId, progressCallback);
   1213     }
   1214 
   1215     @Override
   1216     public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
   1217             throws RemoteException {
   1218         return doVerifyPattern(pattern, true, challenge, userId, null /* progressCallback */);
   1219     }
   1220 
   1221     private VerifyCredentialResponse doVerifyPattern(String pattern, boolean hasChallenge,
   1222             long challenge, int userId, ICheckCredentialProgressCallback progressCallback)
   1223             throws RemoteException {
   1224        checkPasswordReadPermission(userId);
   1225        if (TextUtils.isEmpty(pattern)) {
   1226            throw new IllegalArgumentException("Pattern can't be null or empty");
   1227        }
   1228        CredentialHash storedHash = mStorage.readPatternHash(userId);
   1229        return doVerifyPattern(pattern, storedHash, hasChallenge, challenge, userId,
   1230                progressCallback);
   1231     }
   1232 
   1233     private VerifyCredentialResponse doVerifyPattern(String pattern, CredentialHash storedHash,
   1234             boolean hasChallenge, long challenge, int userId,
   1235             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
   1236 
   1237        if (TextUtils.isEmpty(pattern)) {
   1238            throw new IllegalArgumentException("Pattern can't be null or empty");
   1239        }
   1240        boolean shouldReEnrollBaseZero = storedHash != null && storedHash.isBaseZeroPattern;
   1241 
   1242        String patternToVerify;
   1243        if (shouldReEnrollBaseZero) {
   1244            patternToVerify = LockPatternUtils.patternStringToBaseZero(pattern);
   1245        } else {
   1246            patternToVerify = pattern;
   1247        }
   1248 
   1249        VerifyCredentialResponse response = verifyCredential(userId, storedHash, patternToVerify,
   1250                hasChallenge, challenge,
   1251                new CredentialUtil() {
   1252                    @Override
   1253                    public void setCredential(String pattern, String oldPattern, int userId)
   1254                            throws RemoteException {
   1255                         setLockPatternInternal(pattern, oldPattern, userId);
   1256                    }
   1257 
   1258                    @Override
   1259                    public byte[] toHash(String pattern, int userId) {
   1260                        return LockPatternUtils.patternToHash(
   1261                                LockPatternUtils.stringToPattern(pattern));
   1262                    }
   1263 
   1264                    @Override
   1265                    public String adjustForKeystore(String pattern) {
   1266                        return LockPatternUtils.patternStringToBaseZero(pattern);
   1267                    }
   1268                },
   1269                progressCallback
   1270        );
   1271 
   1272        if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK
   1273                && shouldReEnrollBaseZero) {
   1274             setLockPatternInternal(pattern, patternToVerify, userId);
   1275        }
   1276 
   1277        return response;
   1278     }
   1279 
   1280     @Override
   1281     public VerifyCredentialResponse checkPassword(String password, int userId,
   1282             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
   1283         return doVerifyPassword(password, false, 0, userId, progressCallback);
   1284     }
   1285 
   1286     @Override
   1287     public VerifyCredentialResponse verifyPassword(String password, long challenge, int userId)
   1288             throws RemoteException {
   1289         return doVerifyPassword(password, true, challenge, userId, null /* progressCallback */);
   1290     }
   1291 
   1292     @Override
   1293     public VerifyCredentialResponse verifyTiedProfileChallenge(String password, boolean isPattern,
   1294             long challenge, int userId) throws RemoteException {
   1295         checkPasswordReadPermission(userId);
   1296         if (!isManagedProfileWithUnifiedLock(userId)) {
   1297             throw new RemoteException("User id must be managed profile with unified lock");
   1298         }
   1299         final int parentProfileId = mUserManager.getProfileParent(userId).id;
   1300         // Unlock parent by using parent's challenge
   1301         final VerifyCredentialResponse parentResponse = isPattern
   1302                 ? doVerifyPattern(password, true, challenge, parentProfileId,
   1303                         null /* progressCallback */)
   1304                 : doVerifyPassword(password, true, challenge, parentProfileId,
   1305                         null /* progressCallback */);
   1306         if (parentResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
   1307             // Failed, just return parent's response
   1308             return parentResponse;
   1309         }
   1310 
   1311         try {
   1312             // Unlock work profile, and work profile with unified lock must use password only
   1313             return doVerifyPassword(getDecryptedPasswordForTiedProfile(userId), true,
   1314                     challenge,
   1315                     userId, null /* progressCallback */);
   1316         } catch (UnrecoverableKeyException | InvalidKeyException | KeyStoreException
   1317                 | NoSuchAlgorithmException | NoSuchPaddingException
   1318                 | InvalidAlgorithmParameterException | IllegalBlockSizeException
   1319                 | BadPaddingException | CertificateException | IOException e) {
   1320             Slog.e(TAG, "Failed to decrypt child profile key", e);
   1321             throw new RemoteException("Unable to get tied profile token");
   1322         }
   1323     }
   1324 
   1325     private VerifyCredentialResponse doVerifyPassword(String password, boolean hasChallenge,
   1326             long challenge, int userId, ICheckCredentialProgressCallback progressCallback)
   1327             throws RemoteException {
   1328        checkPasswordReadPermission(userId);
   1329        if (TextUtils.isEmpty(password)) {
   1330            throw new IllegalArgumentException("Password can't be null or empty");
   1331        }
   1332        CredentialHash storedHash = mStorage.readPasswordHash(userId);
   1333        return doVerifyPassword(password, storedHash, hasChallenge, challenge, userId,
   1334                progressCallback);
   1335     }
   1336 
   1337     private VerifyCredentialResponse doVerifyPassword(String password, CredentialHash storedHash,
   1338             boolean hasChallenge, long challenge, int userId,
   1339             ICheckCredentialProgressCallback progressCallback) throws RemoteException {
   1340        if (TextUtils.isEmpty(password)) {
   1341            throw new IllegalArgumentException("Password can't be null or empty");
   1342        }
   1343        return verifyCredential(userId, storedHash, password, hasChallenge, challenge,
   1344                new CredentialUtil() {
   1345                    @Override
   1346                    public void setCredential(String password, String oldPassword, int userId)
   1347                            throws RemoteException {
   1348                         setLockPasswordInternal(password, oldPassword, userId);
   1349                    }
   1350 
   1351                    @Override
   1352                    public byte[] toHash(String password, int userId) {
   1353                        return mLockPatternUtils.passwordToHash(password, userId);
   1354                    }
   1355 
   1356                    @Override
   1357                    public String adjustForKeystore(String password) {
   1358                        return password;
   1359                    }
   1360                }, progressCallback);
   1361     }
   1362 
   1363     private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash,
   1364             String credential, boolean hasChallenge, long challenge, CredentialUtil credentialUtil,
   1365             ICheckCredentialProgressCallback progressCallback)
   1366                 throws RemoteException {
   1367         if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) {
   1368             // don't need to pass empty credentials to GateKeeper
   1369             return VerifyCredentialResponse.OK;
   1370         }
   1371 
   1372         if (TextUtils.isEmpty(credential)) {
   1373             return VerifyCredentialResponse.ERROR;
   1374         }
   1375 
   1376         if (storedHash.version == CredentialHash.VERSION_LEGACY) {
   1377             byte[] hash = credentialUtil.toHash(credential, userId);
   1378             if (Arrays.equals(hash, storedHash.hash)) {
   1379                 unlockKeystore(credentialUtil.adjustForKeystore(credential), userId);
   1380 
   1381                 // Users with legacy credentials don't have credential-backed
   1382                 // FBE keys, so just pass through a fake token/secret
   1383                 Slog.i(TAG, "Unlocking user with fake token: " + userId);
   1384                 final byte[] fakeToken = String.valueOf(userId).getBytes();
   1385                 unlockUser(userId, fakeToken, fakeToken);
   1386 
   1387                 // migrate credential to GateKeeper
   1388                 credentialUtil.setCredential(credential, null, userId);
   1389                 if (!hasChallenge) {
   1390                     return VerifyCredentialResponse.OK;
   1391                 }
   1392                 // Fall through to get the auth token. Technically this should never happen,
   1393                 // as a user that had a legacy credential would have to unlock their device
   1394                 // before getting to a flow with a challenge, but supporting for consistency.
   1395             } else {
   1396                 return VerifyCredentialResponse.ERROR;
   1397             }
   1398         }
   1399 
   1400         VerifyCredentialResponse response;
   1401         boolean shouldReEnroll = false;
   1402         GateKeeperResponse gateKeeperResponse = getGateKeeperService()
   1403                 .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes());
   1404         int responseCode = gateKeeperResponse.getResponseCode();
   1405         if (responseCode == GateKeeperResponse.RESPONSE_RETRY) {
   1406              response = new VerifyCredentialResponse(gateKeeperResponse.getTimeout());
   1407         } else if (responseCode == GateKeeperResponse.RESPONSE_OK) {
   1408             byte[] token = gateKeeperResponse.getPayload();
   1409             if (token == null) {
   1410                 // something's wrong if there's no payload with a challenge
   1411                 Slog.e(TAG, "verifyChallenge response had no associated payload");
   1412                 response = VerifyCredentialResponse.ERROR;
   1413             } else {
   1414                 shouldReEnroll = gateKeeperResponse.getShouldReEnroll();
   1415                 response = new VerifyCredentialResponse(token);
   1416             }
   1417         } else {
   1418             response = VerifyCredentialResponse.ERROR;
   1419         }
   1420 
   1421         if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_OK) {
   1422 
   1423 
   1424             // credential has matched
   1425 
   1426             if (progressCallback != null) {
   1427                 progressCallback.onCredentialVerified();
   1428             }
   1429             unlockKeystore(credential, userId);
   1430 
   1431             Slog.i(TAG, "Unlocking user " + userId +
   1432                 " with token length " + response.getPayload().length);
   1433             unlockUser(userId, response.getPayload(), secretFromCredential(credential));
   1434 
   1435             if (isManagedProfileWithSeparatedLock(userId)) {
   1436                 TrustManager trustManager =
   1437                         (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
   1438                 trustManager.setDeviceLockedForUser(userId, false);
   1439             }
   1440             if (shouldReEnroll) {
   1441                 credentialUtil.setCredential(credential, credential, userId);
   1442             }
   1443         } else if (response.getResponseCode() == VerifyCredentialResponse.RESPONSE_RETRY) {
   1444             if (response.getTimeout() > 0) {
   1445                 requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_LOCKOUT, userId);
   1446             }
   1447         }
   1448 
   1449         return response;
   1450     }
   1451 
   1452     @Override
   1453     public boolean checkVoldPassword(int userId) throws RemoteException {
   1454         if (!mFirstCallToVold) {
   1455             return false;
   1456         }
   1457         mFirstCallToVold = false;
   1458 
   1459         checkPasswordReadPermission(userId);
   1460 
   1461         // There's no guarantee that this will safely connect, but if it fails
   1462         // we will simply show the lock screen when we shouldn't, so relatively
   1463         // benign. There is an outside chance something nasty would happen if
   1464         // this service restarted before vold stales out the password in this
   1465         // case. The nastiness is limited to not showing the lock screen when
   1466         // we should, within the first minute of decrypting the phone if this
   1467         // service can't connect to vold, it restarts, and then the new instance
   1468         // does successfully connect.
   1469         final IMountService service = getMountService();
   1470         String password;
   1471         long identity = Binder.clearCallingIdentity();
   1472         try {
   1473             password = service.getPassword();
   1474             service.clearPassword();
   1475         } finally {
   1476             Binder.restoreCallingIdentity(identity);
   1477         }
   1478         if (password == null) {
   1479             return false;
   1480         }
   1481 
   1482         try {
   1483             if (mLockPatternUtils.isLockPatternEnabled(userId)) {
   1484                 if (checkPattern(password, userId, null /* progressCallback */).getResponseCode()
   1485                         == GateKeeperResponse.RESPONSE_OK) {
   1486                     return true;
   1487                 }
   1488             }
   1489         } catch (Exception e) {
   1490         }
   1491 
   1492         try {
   1493             if (mLockPatternUtils.isLockPasswordEnabled(userId)) {
   1494                 if (checkPassword(password, userId, null /* progressCallback */).getResponseCode()
   1495                         == GateKeeperResponse.RESPONSE_OK) {
   1496                     return true;
   1497                 }
   1498             }
   1499         } catch (Exception e) {
   1500         }
   1501 
   1502         return false;
   1503     }
   1504 
   1505     private void removeUser(int userId, boolean unknownUser) {
   1506         mStorage.removeUser(userId);
   1507         mStrongAuth.removeUser(userId);
   1508 
   1509         final KeyStore ks = KeyStore.getInstance();
   1510         ks.onUserRemoved(userId);
   1511 
   1512         try {
   1513             final IGateKeeperService gk = getGateKeeperService();
   1514             if (gk != null) {
   1515                     gk.clearSecureUserId(userId);
   1516             }
   1517         } catch (RemoteException ex) {
   1518             Slog.w(TAG, "unable to clear GK secure user id");
   1519         }
   1520         if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
   1521             removeKeystoreProfileKey(userId);
   1522         }
   1523     }
   1524 
   1525     private void removeKeystoreProfileKey(int targetUserId) {
   1526         if (DEBUG) Slog.v(TAG, "Remove keystore profile key for user: " + targetUserId);
   1527         try {
   1528             java.security.KeyStore keyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
   1529             keyStore.load(null);
   1530             keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT + targetUserId);
   1531             keyStore.deleteEntry(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT + targetUserId);
   1532         } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException
   1533                 | IOException e) {
   1534             // We have tried our best to remove all keys
   1535             Slog.e(TAG, "Unable to remove keystore profile key for user:" + targetUserId, e);
   1536         }
   1537     }
   1538 
   1539     @Override
   1540     public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
   1541         checkPasswordReadPermission(UserHandle.USER_ALL);
   1542         mStrongAuth.registerStrongAuthTracker(tracker);
   1543     }
   1544 
   1545     @Override
   1546     public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
   1547         checkPasswordReadPermission(UserHandle.USER_ALL);
   1548         mStrongAuth.unregisterStrongAuthTracker(tracker);
   1549     }
   1550 
   1551     @Override
   1552     public void requireStrongAuth(int strongAuthReason, int userId) {
   1553         checkWritePermission(userId);
   1554         mStrongAuth.requireStrongAuth(strongAuthReason, userId);
   1555     }
   1556 
   1557     @Override
   1558     public void userPresent(int userId) {
   1559         checkWritePermission(userId);
   1560         mStrongAuth.reportUnlock(userId);
   1561     }
   1562 
   1563     @Override
   1564     public int getStrongAuthForUser(int userId) {
   1565         checkPasswordReadPermission(userId);
   1566         return mStrongAuthTracker.getStrongAuthForUser(userId);
   1567     }
   1568 
   1569     private static final String[] VALID_SETTINGS = new String[] {
   1570         LockPatternUtils.LOCKOUT_PERMANENT_KEY,
   1571         LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
   1572         LockPatternUtils.PATTERN_EVER_CHOSEN_KEY,
   1573         LockPatternUtils.PASSWORD_TYPE_KEY,
   1574         LockPatternUtils.PASSWORD_TYPE_ALTERNATE_KEY,
   1575         LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
   1576         LockPatternUtils.DISABLE_LOCKSCREEN_KEY,
   1577         LockPatternUtils.LOCKSCREEN_OPTIONS,
   1578         LockPatternUtils.LOCKSCREEN_BIOMETRIC_WEAK_FALLBACK,
   1579         LockPatternUtils.BIOMETRIC_WEAK_EVER_CHOSEN_KEY,
   1580         LockPatternUtils.LOCKSCREEN_POWER_BUTTON_INSTANTLY_LOCKS,
   1581         LockPatternUtils.PASSWORD_HISTORY_KEY,
   1582         Secure.LOCK_PATTERN_ENABLED,
   1583         Secure.LOCK_BIOMETRIC_WEAK_FLAGS,
   1584         Secure.LOCK_PATTERN_VISIBLE,
   1585         Secure.LOCK_PATTERN_TACTILE_FEEDBACK_ENABLED
   1586     };
   1587 
   1588     // Reading these settings needs the contacts permission
   1589     private static final String[] READ_CONTACTS_PROTECTED_SETTINGS = new String[] {
   1590         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
   1591         Secure.LOCK_SCREEN_OWNER_INFO
   1592     };
   1593 
   1594     // Reading these settings needs the same permission as checking the password
   1595     private static final String[] READ_PASSWORD_PROTECTED_SETTINGS = new String[] {
   1596             LockPatternUtils.LOCK_PASSWORD_SALT_KEY,
   1597             LockPatternUtils.PASSWORD_HISTORY_KEY,
   1598             LockPatternUtils.PASSWORD_TYPE_KEY,
   1599             SEPARATE_PROFILE_CHALLENGE_KEY
   1600     };
   1601 
   1602     private static final String[] SETTINGS_TO_BACKUP = new String[] {
   1603         Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
   1604         Secure.LOCK_SCREEN_OWNER_INFO
   1605     };
   1606 
   1607     private IMountService getMountService() {
   1608         final IBinder service = ServiceManager.getService("mount");
   1609         if (service != null) {
   1610             return IMountService.Stub.asInterface(service);
   1611         }
   1612         return null;
   1613     }
   1614 
   1615     private class GateKeeperDiedRecipient implements IBinder.DeathRecipient {
   1616         @Override
   1617         public void binderDied() {
   1618             mGateKeeperService.asBinder().unlinkToDeath(this, 0);
   1619             mGateKeeperService = null;
   1620         }
   1621     }
   1622 
   1623     private synchronized IGateKeeperService getGateKeeperService()
   1624             throws RemoteException {
   1625         if (mGateKeeperService != null) {
   1626             return mGateKeeperService;
   1627         }
   1628 
   1629         final IBinder service =
   1630             ServiceManager.getService(Context.GATEKEEPER_SERVICE);
   1631         if (service != null) {
   1632             service.linkToDeath(new GateKeeperDiedRecipient(), 0);
   1633             mGateKeeperService = IGateKeeperService.Stub.asInterface(service);
   1634             return mGateKeeperService;
   1635         }
   1636 
   1637         Slog.e(TAG, "Unable to acquire GateKeeperService");
   1638         return null;
   1639     }
   1640 }
   1641