1 /* 2 * Copyright (C) 2019 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.car.settings.setupservice; 18 19 import android.app.Service; 20 import android.app.admin.DevicePolicyManager; 21 import android.content.Intent; 22 import android.content.pm.PackageManager; 23 import android.os.IBinder; 24 import android.os.UserHandle; 25 26 import com.android.car.settings.R; 27 import com.android.car.settings.common.Logger; 28 import com.android.car.settings.security.PasswordHelper; 29 import com.android.car.setupwizardlib.IInitialLockSetupService; 30 import com.android.car.setupwizardlib.InitialLockSetupConstants; 31 import com.android.car.setupwizardlib.InitialLockSetupConstants.LockTypes; 32 import com.android.car.setupwizardlib.InitialLockSetupConstants.SetLockCodes; 33 import com.android.car.setupwizardlib.InitialLockSetupConstants.ValidateLockFlags; 34 import com.android.car.setupwizardlib.LockConfig; 35 import com.android.internal.widget.LockPatternUtils; 36 import com.android.internal.widget.LockPatternView; 37 import com.android.internal.widget.LockscreenCredential; 38 39 import java.nio.charset.StandardCharsets; 40 import java.util.List; 41 42 /** 43 * Service that is used by Setup Wizard (exclusively) to set the initial lock screen. 44 * 45 * <p>This service provides functionality to get the lock config state, check if a password is 46 * valid based on the Settings defined password criteria, and save a lock if there is not one 47 * already saved. The interface for these operations is found in the {@link 48 * IInitialLockSetupService}. 49 */ 50 public class InitialLockSetupService extends Service { 51 52 private static final Logger LOG = new Logger(InitialLockSetupService.class); 53 private static final String SET_LOCK_PERMISSION = "com.android.car.settings.SET_INITIAL_LOCK"; 54 55 private final InitialLockSetupServiceImpl mIInitialLockSetupService = 56 new InitialLockSetupServiceImpl(); 57 58 /** 59 * Will return an {@link IBinder} for the service unless either the caller does not have the 60 * appropriate permissions or a lock has already been set on the device. In this case, the 61 * service will return {@code null}. 62 */ 63 @Override onBind(Intent intent)64 public IBinder onBind(Intent intent) { 65 LOG.v("onBind"); 66 if (checkCallingOrSelfPermission(SET_LOCK_PERMISSION) 67 != PackageManager.PERMISSION_GRANTED) { 68 // Check permission as a failsafe. 69 return null; 70 } 71 int userId = UserHandle.myUserId(); 72 LockPatternUtils lockPatternUtils = new LockPatternUtils(getApplicationContext()); 73 // Deny binding if there is an existing lock. 74 if (lockPatternUtils.getKeyguardStoredPasswordQuality(userId) 75 != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 76 LOG.v("Rejecting binding, lock exists"); 77 return null; 78 } 79 return mIInitialLockSetupService; 80 } 81 82 // Implementation of the service binder interface. 83 private class InitialLockSetupServiceImpl extends IInitialLockSetupService.Stub { 84 85 @Override getServiceVersion()86 public int getServiceVersion() { 87 return InitialLockSetupConstants.LIBRARY_VERSION; 88 } 89 90 @Override getLockConfig(@ockTypes int lockType)91 public LockConfig getLockConfig(@LockTypes int lockType) { 92 // All lock types currently are configured the same. 93 switch (lockType) { 94 case LockTypes.PASSWORD: 95 // fall through 96 case LockTypes.PIN: 97 // fall through 98 case LockTypes.PATTERN: 99 return new LockConfig(/* enabled= */ true, 100 LockPatternUtils.MIN_LOCK_PATTERN_SIZE); 101 } 102 return null; 103 } 104 createLockscreenCredential( @ockTypes int lockType, byte[] password)105 private LockscreenCredential createLockscreenCredential( 106 @LockTypes int lockType, byte[] password) { 107 switch (lockType) { 108 case LockTypes.PASSWORD: 109 String passwordStr = new String(password, StandardCharsets.UTF_8); 110 return LockscreenCredential.createPassword(passwordStr); 111 case LockTypes.PIN: 112 String pinStr = new String(password, StandardCharsets.UTF_8); 113 return LockscreenCredential.createPin(pinStr); 114 case LockTypes.PATTERN: 115 List<LockPatternView.Cell> pattern = 116 LockPatternUtils.byteArrayToPattern(password); 117 return LockscreenCredential.createPattern(pattern); 118 default: 119 LOG.e("Unrecognized lockscreen credential type: " + lockType); 120 return null; 121 } 122 } 123 124 @Override 125 @ValidateLockFlags checkValidLock(@ockTypes int lockType, byte[] password)126 public int checkValidLock(@LockTypes int lockType, byte[] password) { 127 try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) { 128 if (credential == null) { 129 return ValidateLockFlags.INVALID_GENERIC; 130 } 131 PasswordHelper helper = new PasswordHelper(getApplicationContext(), getUserId()); 132 if (!helper.validateCredential(credential)) { 133 return ValidateLockFlags.INVALID_GENERIC; 134 } 135 return 0; 136 } 137 } 138 139 @Override 140 @SetLockCodes setLock(@ockTypes int lockType, byte[] password)141 public int setLock(@LockTypes int lockType, byte[] password) { 142 int userId = UserHandle.myUserId(); 143 LockPatternUtils lockPatternUtils = new LockPatternUtils( 144 InitialLockSetupService.this.getApplicationContext()); 145 int currentPassword = lockPatternUtils.getKeyguardStoredPasswordQuality(userId); 146 if (currentPassword != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 147 LOG.v("Credential already set, rejecting call to setLock"); 148 return SetLockCodes.FAIL_LOCK_EXISTS; 149 } 150 try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) { 151 if (credential == null) { 152 return SetLockCodes.FAIL_LOCK_INVALID; 153 } 154 PasswordHelper helper = new PasswordHelper(getApplicationContext(), userId); 155 if (!helper.validateCredential(credential)) { 156 LOG.v("Credential is not valid, rejecting call to setLock"); 157 return SetLockCodes.FAIL_LOCK_INVALID; 158 } 159 if (!lockPatternUtils.setLockCredential(credential, 160 /* savedCredential= */ LockscreenCredential.createNone(), userId)) { 161 return SetLockCodes.FAIL_LOCK_GENERIC; 162 } 163 return SetLockCodes.SUCCESS; 164 } catch (Exception e) { 165 LOG.e("Save lock exception", e); 166 return SetLockCodes.FAIL_LOCK_GENERIC; 167 } 168 } 169 170 @Override checkValidLockAndReturnError(@ockTypes int lockType, byte[] credentialBytes)171 public String checkValidLockAndReturnError(@LockTypes int lockType, 172 byte[] credentialBytes) { 173 try (LockscreenCredential credential = 174 createLockscreenCredential(lockType, credentialBytes)) { 175 if (credential == null) { 176 return getApplicationContext().getString(R.string.locktype_unavailable); 177 } 178 PasswordHelper helper = new PasswordHelper(getApplicationContext(), getUserId()); 179 helper.validateCredential(credential); 180 return helper.getCredentialValidationErrorMessages(); 181 } 182 } 183 } 184 } 185