• 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 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.ArrayList;
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 = UserHandle.myUserId();
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     // Implementation of the service binder interface.
84     private class InitialLockSetupServiceImpl extends IInitialLockSetupService.Stub {
85 
86         @Override
getServiceVersion()87         public int getServiceVersion() {
88             return InitialLockSetupConstants.LIBRARY_VERSION;
89         }
90 
91         @Override
getLockConfig(@ockTypes int lockType)92         public LockConfig getLockConfig(@LockTypes int lockType) {
93             // All lock types currently are configured the same.
94             switch (lockType) {
95                 case LockTypes.PASSWORD:
96                     // fall through
97                 case LockTypes.PIN:
98                     // fall through
99                 case LockTypes.PATTERN:
100                     return new LockConfig(/* enabled= */ true,
101                             LockPatternUtils.MIN_LOCK_PATTERN_SIZE);
102             }
103             return null;
104         }
105 
byteArrayToPattern(byte[] bytes)106         private List<LockPatternView.Cell> byteArrayToPattern(byte[] bytes) {
107             if (bytes.length > 0 && bytes[0] <= 9) {
108                 // Be compatible with old clients that incorrectly created the byte[] with cells
109                 // numbered binary 1-9 instead of the LockPatternUtils convention of ASCII 1-9.
110                 List<LockPatternView.Cell> pattern = new ArrayList<>();
111                 for (int i = 0; i < bytes.length; i++) {
112                     pattern.add(LockPatternView.Cell.of(
113                                 (byte) ((bytes[i] - 1) / 3), (byte) ((bytes[i] - 1) % 3)));
114                 }
115                 return pattern;
116             }
117             return LockPatternUtils.byteArrayToPattern(bytes);
118         }
119 
createLockscreenCredential( @ockTypes int lockType, byte[] password)120         private LockscreenCredential createLockscreenCredential(
121                 @LockTypes int lockType, byte[] password) {
122             switch (lockType) {
123                 case LockTypes.PASSWORD:
124                     String passwordStr = new String(password, StandardCharsets.UTF_8);
125                     return LockscreenCredential.createPassword(passwordStr);
126                 case LockTypes.PIN:
127                     String pinStr = new String(password, StandardCharsets.UTF_8);
128                     return LockscreenCredential.createPin(pinStr);
129                 case LockTypes.PATTERN:
130                     List<LockPatternView.Cell> pattern = byteArrayToPattern(password);
131                     return LockscreenCredential.createPattern(pattern);
132                 default:
133                     LOG.e("Unrecognized lockscreen credential type: " + lockType);
134                     return null;
135             }
136         }
137 
138         @Override
139         @ValidateLockFlags
checkValidLock(@ockTypes int lockType, byte[] password)140         public int checkValidLock(@LockTypes int lockType, byte[] password) {
141             try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) {
142                 if (credential == null) {
143                     return ValidateLockFlags.INVALID_GENERIC;
144                 }
145                 PasswordHelper helper = new PasswordHelper(getApplicationContext(), getUserId());
146                 if (!helper.validateCredential(credential)) {
147                     return ValidateLockFlags.INVALID_GENERIC;
148                 }
149                 return 0;
150             }
151         }
152 
153         @Override
154         @SetLockCodes
setLock(@ockTypes int lockType, byte[] password)155         public int setLock(@LockTypes int lockType, byte[] password) {
156             int userId = UserHandle.myUserId();
157             LockPatternUtils lockPatternUtils = new LockPatternUtils(
158                     InitialLockSetupService.this.getApplicationContext());
159             int currentPassword = lockPatternUtils.getKeyguardStoredPasswordQuality(userId);
160             if (currentPassword != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) {
161                 LOG.v("Credential already set, rejecting call to setLock");
162                 return SetLockCodes.FAIL_LOCK_EXISTS;
163             }
164             try (LockscreenCredential credential = createLockscreenCredential(lockType, password)) {
165                 if (credential == null) {
166                     return SetLockCodes.FAIL_LOCK_INVALID;
167                 }
168                 PasswordHelper helper = new PasswordHelper(getApplicationContext(), userId);
169                 if (!helper.validateCredential(credential)) {
170                     LOG.v("Credential is not valid, rejecting call to setLock");
171                     return SetLockCodes.FAIL_LOCK_INVALID;
172                 }
173                 if (!lockPatternUtils.setLockCredential(credential,
174                             /* savedCredential= */ LockscreenCredential.createNone(), userId)) {
175                     return SetLockCodes.FAIL_LOCK_GENERIC;
176                 }
177                 return SetLockCodes.SUCCESS;
178             } catch (Exception e) {
179                 LOG.e("Save lock exception", e);
180                 return SetLockCodes.FAIL_LOCK_GENERIC;
181             }
182         }
183 
184         @Override
checkValidLockAndReturnError(@ockTypes int lockType, byte[] credentialBytes)185         public String checkValidLockAndReturnError(@LockTypes int lockType,
186                 byte[] credentialBytes) {
187             try (LockscreenCredential credential =
188                     createLockscreenCredential(lockType, credentialBytes)) {
189                 if (credential == null) {
190                     return getApplicationContext().getString(R.string.locktype_unavailable);
191                 }
192                 PasswordHelper helper = new PasswordHelper(getApplicationContext(), getUserId());
193                 helper.validateCredential(credential);
194                 return helper.getCredentialValidationErrorMessages();
195             }
196         }
197     }
198 }
199