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