• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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