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