• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
setCredential(String credential, String savedCredential, int userId)149         void setCredential(String credential, String savedCredential, int userId)
150                 throws RemoteException;
toHash(String credential, int userId)151         byte[] toHash(String credential, int userId);
adjustForKeystore(String credential)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 
Lifecycle(Context context)161         public Lifecycle(Context context) {
162             super(context);
163         }
164 
165         @Override
onStart()166         public void onStart() {
167             AndroidKeyStoreProvider.install();
168             mLockSettingsService = new LockSettingsService(getContext());
169             publishBinderService("lock_settings", mLockSettingsService);
170         }
171 
172         @Override
onBootPhase(int phase)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
onUnlockUser(int userHandle)182         public void onUnlockUser(int userHandle) {
183             mLockSettingsService.onUnlockUser(userHandle);
184         }
185 
186         @Override
onCleanupUser(int userHandle)187         public void onCleanupUser(int userHandle) {
188             mLockSettingsService.onCleanupUser(userHandle);
189         }
190     }
191 
192     private class SynchronizedStrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
SynchronizedStrongAuthTracker(Context context)193         public SynchronizedStrongAuthTracker(Context context) {
194             super(context);
195         }
196 
197         @Override
handleStrongAuthRequiredChanged(int strongAuthFlags, int userId)198         protected void handleStrongAuthRequiredChanged(int strongAuthFlags, int userId) {
199             synchronized (this) {
200                 super.handleStrongAuthRequiredChanged(strongAuthFlags, userId);
201             }
202         }
203 
204         @Override
getStrongAuthForUser(int userId)205         public int getStrongAuthForUser(int userId) {
206             synchronized (this) {
207                 return super.getStrongAuthForUser(userId);
208             }
209         }
210 
register()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      */
tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword)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 
LockSettingsService(Context context)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      */
maybeShowEncryptionNotifications()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 
showEncryptionNotificationForProfile(UserHandle user)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 
showEncryptionNotification(UserHandle user, CharSequence title, CharSequence message, CharSequence detail, PendingIntent intent)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 
hideEncryptionNotification(UserHandle userHandle)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 
onCleanupUser(int userId)375     public void onCleanupUser(int userId) {
376         hideEncryptionNotification(new UserHandle(userId));
377     }
378 
onUnlockUser(final int userId)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
systemReady()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 
migrateOldData()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 
checkWritePermission(int userId)592     private final void checkWritePermission(int userId) {
593         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsWrite");
594     }
595 
checkPasswordReadPermission(int userId)596     private final void checkPasswordReadPermission(int userId) {
597         mContext.enforceCallingOrSelfPermission(PERMISSION, "LockSettingsRead");
598     }
599 
checkReadPermission(String requestedKey, int userId)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
getSeparateProfileChallengeEnabled(int userId)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
setSeparateProfileChallengeEnabled(int userId, boolean enabled, String managedUserPassword)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
setBoolean(String key, boolean value, int userId)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
setLong(String key, long value, int userId)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
setString(String key, String value, int userId)660     public void setString(String key, String value, int userId) throws RemoteException {
661         checkWritePermission(userId);
662         setStringUnchecked(key, userId, value);
663     }
664 
setStringUnchecked(String key, int userId, String value)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
getBoolean(String key, boolean defaultValue, int userId)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
getLong(String key, long defaultValue, int userId)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
getString(String key, String defaultValue, int userId)688     public String getString(String key, String defaultValue, int userId) throws RemoteException {
689         checkReadPermission(key, userId);
690         return getStringUnchecked(key, defaultValue, userId);
691     }
692 
getStringUnchecked(String key, String defaultValue, int userId)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
havePassword(int userId)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
havePattern(int userId)717     public boolean havePattern(int userId) throws RemoteException {
718         // Do we need a permissions check here?
719         return mStorage.hasPattern(userId);
720     }
721 
setKeystorePassword(String password, int userHandle)722     private void setKeystorePassword(String password, int userHandle) {
723         final KeyStore ks = KeyStore.getInstance();
724         ks.onUserPasswordChanged(userHandle, password);
725     }
726 
unlockKeystore(String password, int userHandle)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 
getDecryptedPasswordForTiedProfile(int userId)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 
unlockChildProfile(int profileHandle)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 
unlockUser(int userId, byte[] token, byte[] secret)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 
getCurrentHandle(int userId)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 
onUserLockChanged(int userId)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 
isManagedProfileWithUnifiedLock(int userId)886     private boolean isManagedProfileWithUnifiedLock(int userId) {
887         return mUserManager.getUserInfo(userId).isManagedProfile()
888                 && !mLockPatternUtils.isSeparateProfileChallengeEnabled(userId);
889     }
890 
isManagedProfileWithSeparatedLock(int userId)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
setLockPattern(String pattern, String savedCredential, int userId)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 
setLockPatternInternal(String pattern, String savedCredential, int userId)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
setLockPassword(String password, String savedCredential, int userId)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 
setLockPasswordInternal(String password, String savedCredential, int userId)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 
tieProfileLockToParent(int userId, String password)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 
enrollCredential(byte[] enrolledHandle, String enrolledCredential, String toEnroll, int userId)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 
setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr)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 
clearUserKeyProtection(int userId)1122     private void clearUserKeyProtection(int userId) throws RemoteException {
1123         addUserKeyAuth(userId, null, null);
1124     }
1125 
secretFromCredential(String credential)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 
addUserKeyAuth(int userId, byte[] token, byte[] secret)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 
fixateNewestUserKeyAuth(int userId)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
resetKeyStore(int userId)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
checkPattern(String pattern, int userId, ICheckCredentialProgressCallback progressCallback)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
verifyPattern(String pattern, long challenge, int userId)1216     public VerifyCredentialResponse verifyPattern(String pattern, long challenge, int userId)
1217             throws RemoteException {
1218         return doVerifyPattern(pattern, true, challenge, userId, null /* progressCallback */);
1219     }
1220 
doVerifyPattern(String pattern, boolean hasChallenge, long challenge, int userId, ICheckCredentialProgressCallback progressCallback)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 
doVerifyPattern(String pattern, CredentialHash storedHash, boolean hasChallenge, long challenge, int userId, ICheckCredentialProgressCallback progressCallback)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
checkPassword(String password, int userId, ICheckCredentialProgressCallback progressCallback)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
verifyPassword(String password, long challenge, int userId)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
verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, int userId)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 
doVerifyPassword(String password, boolean hasChallenge, long challenge, int userId, ICheckCredentialProgressCallback progressCallback)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 
doVerifyPassword(String password, CredentialHash storedHash, boolean hasChallenge, long challenge, int userId, ICheckCredentialProgressCallback progressCallback)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