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 20 import android.app.Service; 21 import android.app.admin.DevicePolicyManager; 22 import android.content.Intent; 23 import android.content.pm.PackageManager; 24 import android.os.IBinder; 25 import android.os.UserHandle; 26 import android.text.TextUtils; 27 28 import com.android.car.settings.common.Logger; 29 import com.android.car.settings.security.PasswordHelper; 30 import com.android.car.setupwizardlib.IInitialLockSetupService; 31 import com.android.car.setupwizardlib.InitialLockSetupConstants; 32 import com.android.car.setupwizardlib.InitialLockSetupConstants.LockTypes; 33 import com.android.car.setupwizardlib.InitialLockSetupConstants.SetLockCodes; 34 import com.android.car.setupwizardlib.InitialLockSetupConstants.ValidateLockFlags; 35 import com.android.car.setupwizardlib.InitialLockSetupHelper; 36 import com.android.car.setupwizardlib.LockConfig; 37 import com.android.internal.widget.LockPatternUtils; 38 import com.android.internal.widget.LockPatternView; 39 import com.android.internal.widget.LockscreenCredential; 40 41 import java.util.ArrayList; 42 import java.util.Arrays; 43 import java.util.List; 44 45 /** 46 * Service that is used by Setup Wizard (exclusively) to set the initial lock screen. 47 * 48 * <p>This service provides functionality to get the lock config state, check if a password is 49 * valid based on the Settings defined password criteria, and save a lock if there is not one 50 * already saved. The interface for these operations is found in the {@link 51 * IInitialLockSetupService}. 52 */ 53 public class InitialLockSetupService extends Service { 54 55 private static final Logger LOG = new Logger(InitialLockSetupService.class); 56 private static final String SET_LOCK_PERMISSION = "com.android.car.settings.SET_INITIAL_LOCK"; 57 58 private final InitialLockSetupServiceImpl mIInitialLockSetupService = 59 new InitialLockSetupServiceImpl(); 60 61 /** 62 * Will return an {@link IBinder} for the service unless either the caller does not have the 63 * appropriate permissions or a lock has already been set on the device. In this case, the 64 * service will return {@code null}. 65 */ 66 @Override onBind(Intent intent)67 public IBinder onBind(Intent intent) { 68 LOG.v("onBind"); 69 if (checkCallingOrSelfPermission(SET_LOCK_PERMISSION) 70 != PackageManager.PERMISSION_GRANTED) { 71 // Check permission as a failsafe. 72 return null; 73 } 74 int userId = UserHandle.myUserId(); 75 LockPatternUtils lockPatternUtils = new LockPatternUtils(getApplicationContext()); 76 // Deny binding if there is an existing lock. 77 if (lockPatternUtils.getKeyguardStoredPasswordQuality(userId) 78 != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 79 LOG.v("Rejecting binding, lock exists"); 80 return null; 81 } 82 return mIInitialLockSetupService; 83 } 84 85 // Translates the byte[] pattern received into the List<LockPatternView.Cell> that is 86 // recognized by LockPatternUtils. toSettingsPattern(byte[] pattern)87 private List<LockPatternView.Cell> toSettingsPattern(byte[] pattern) { 88 List<LockPatternView.Cell> outputList = new ArrayList<>(); 89 for (int i = 0; i < pattern.length; i++) { 90 outputList.add(LockPatternView.Cell.of( 91 InitialLockSetupHelper.getPatternCellRowFromByte(pattern[i]), 92 InitialLockSetupHelper.getPatternCellColumnFromByte(pattern[i]))); 93 } 94 return outputList; 95 } 96 97 // Implementation of the service binder interface. 98 private class InitialLockSetupServiceImpl extends IInitialLockSetupService.Stub { 99 100 @Override getServiceVersion()101 public int getServiceVersion() { 102 return InitialLockSetupConstants.LIBRARY_VERSION; 103 } 104 105 @Override getLockConfig(@ockTypes int lockType)106 public LockConfig getLockConfig(@LockTypes int lockType) { 107 // All lock types currently are configured the same. 108 switch (lockType) { 109 case LockTypes.PASSWORD: 110 // fall through 111 case LockTypes.PIN: 112 // fall through 113 case LockTypes.PATTERN: 114 return new LockConfig(/* enabled= */ true, 115 LockPatternUtils.MIN_LOCK_PATTERN_SIZE); 116 } 117 return null; 118 } 119 120 @Override 121 @ValidateLockFlags checkValidLock(@ockTypes int lockType, byte[] password)122 public int checkValidLock(@LockTypes int lockType, byte[] password) { 123 PasswordHelper passwordHelper; 124 switch (lockType) { 125 case LockTypes.PASSWORD: 126 passwordHelper = new PasswordHelper(getApplicationContext(), 127 /* isPin= */ false, getUserId()); 128 return passwordHelper.validateSetupWizard(password); 129 case LockTypes.PIN: 130 passwordHelper = new PasswordHelper(getApplicationContext(), 131 /* isPin= */ true, getUserId()); 132 return passwordHelper.validateSetupWizard(password); 133 case LockTypes.PATTERN: 134 return password.length >= LockPatternUtils.MIN_LOCK_PATTERN_SIZE 135 ? 0 : ValidateLockFlags.INVALID_LENGTH; 136 default: 137 LOG.e("other lock type, returning generic error"); 138 return ValidateLockFlags.INVALID_GENERIC; 139 } 140 } 141 142 @Override 143 @SetLockCodes setLock(@ockTypes int lockType, byte[] password)144 public int setLock(@LockTypes int lockType, byte[] password) { 145 int userId = UserHandle.myUserId(); 146 LockPatternUtils lockPatternUtils = new LockPatternUtils( 147 InitialLockSetupService.this.getApplicationContext()); 148 int currentPassword = lockPatternUtils.getKeyguardStoredPasswordQuality(userId); 149 if (currentPassword != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { 150 LOG.v("Password already set, rejecting call to setLock"); 151 return SetLockCodes.FAIL_LOCK_EXISTS; 152 } 153 String errorMessage = checkValidLockAndReturnError(lockType, password); 154 if (!TextUtils.isEmpty(errorMessage)) { 155 LOG.v("Password is not valid, rejecting call to setLock"); 156 return SetLockCodes.FAIL_LOCK_INVALID; 157 } 158 159 boolean success = false; 160 try { 161 switch (lockType) { 162 case LockTypes.PASSWORD: 163 // Need to remove setup wizard lib byte array encoding and use the 164 // LockPatternUtils encoding. 165 CharSequence passwordStr = 166 InitialLockSetupHelper.byteArrayToCharSequence(password); 167 lockPatternUtils.setLockCredential( 168 LockscreenCredential.createPassword(passwordStr), 169 /* savedPassword= */ LockscreenCredential.createNone(), 170 userId); 171 success = true; 172 break; 173 case LockTypes.PIN: 174 // Need to remove setup wizard lib byte array encoding and use the 175 // LockPatternUtils encoding. 176 CharSequence pinStr = 177 InitialLockSetupHelper.byteArrayToCharSequence(password); 178 lockPatternUtils.setLockCredential( 179 LockscreenCredential.createPin(pinStr), 180 /* savedPassword= */ LockscreenCredential.createNone(), 181 userId); 182 success = true; 183 break; 184 case LockTypes.PATTERN: 185 // Need to remove the setup wizard lib pattern encoding and use the 186 // LockPatternUtils pattern format. 187 List<LockPatternView.Cell> pattern = toSettingsPattern(password); 188 lockPatternUtils.setLockCredential( 189 LockscreenCredential.createPattern(pattern), 190 /* savedPassword= */ LockscreenCredential.createNone(), 191 userId); 192 pattern.clear(); 193 success = true; 194 break; 195 default: 196 LOG.e("Unknown lock type, returning a failure"); 197 } 198 } catch (Exception e) { 199 LOG.e("Save lock exception", e); 200 success = false; 201 } 202 Arrays.fill(password, (byte) 0); 203 return success ? SetLockCodes.SUCCESS : SetLockCodes.FAIL_LOCK_GENERIC; 204 } 205 206 @Override checkValidLockAndReturnError(@ockTypes int lockType, byte[] credentialBytes)207 public String checkValidLockAndReturnError(@LockTypes int lockType, 208 byte[] credentialBytes) { 209 PasswordHelper passwordHelper = new PasswordHelper(getApplicationContext(), 210 /* isPin= */ lockType == LockTypes.PIN, /* userId */ getUserId()); 211 return passwordHelper.validateSetupWizardAndReturnError(lockType, credentialBytes); 212 } 213 } 214 } 215