1 /*
2  * Copyright (C) 2017 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.server.oemlock;
18 
19 import android.annotation.Nullable;
20 import android.content.Context;
21 import android.hardware.oemlock.V1_0.IOemLock;
22 import android.hardware.oemlock.V1_0.OemLockSecureStatus;
23 import android.hardware.oemlock.V1_0.OemLockStatus;
24 import android.os.RemoteException;
25 import android.util.Slog;
26 
27 import java.util.ArrayList;
28 import java.util.NoSuchElementException;
29 
30 /**
31  * Uses the OEM lock HAL.
32  */
33 class VendorLock extends OemLock {
34     private static final String TAG = "OemLock";
35 
36     private Context mContext;
37     private IOemLock mOemLock;
38 
getOemLockHalService()39     static IOemLock getOemLockHalService() {
40         try {
41             return IOemLock.getService(/* retry */ true);
42         } catch (NoSuchElementException e) {
43             Slog.i(TAG, "OemLock HAL not present on device");
44             return null;
45         } catch (RemoteException e) {
46             throw e.rethrowFromSystemServer();
47         }
48     }
49 
VendorLock(Context context, IOemLock oemLock)50     VendorLock(Context context, IOemLock oemLock) {
51         mContext = context;
52         mOemLock = oemLock;
53     }
54 
55     @Override
56     @Nullable
getLockName()57     String getLockName() {
58         final Integer[] requestStatus = new Integer[1];
59         final String[] lockName = new String[1];
60 
61         try {
62             mOemLock.getName((status, name) -> {
63                 requestStatus[0] = status;
64                 lockName[0] = name;
65             });
66         } catch (RemoteException e) {
67             Slog.e(TAG, "Failed to get name from HAL", e);
68             throw e.rethrowFromSystemServer();
69         }
70 
71         switch (requestStatus[0]) {
72             case OemLockStatus.OK:
73                 // Success
74                 return lockName[0];
75 
76             case OemLockStatus.FAILED:
77                 Slog.e(TAG, "Failed to get OEM lock name.");
78                 return null;
79 
80             default:
81                 Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
82                 return null;
83         }
84     }
85 
86     @Override
setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature)87     void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) {
88         try {
89             ArrayList<Byte> signatureBytes = toByteArrayList(signature);
90             switch (mOemLock.setOemUnlockAllowedByCarrier(allowed, signatureBytes)) {
91                 case OemLockSecureStatus.OK:
92                     Slog.i(TAG, "Updated carrier allows OEM lock state to: " + allowed);
93                     return;
94 
95                 case OemLockSecureStatus.INVALID_SIGNATURE:
96                     if (signatureBytes.isEmpty()) {
97                         throw new IllegalArgumentException("Signature required for carrier unlock");
98                     }
99                     throw new SecurityException(
100                             "Invalid signature used in attempt to carrier unlock");
101 
102                 default:
103                     Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
104                     // Fallthrough
105                 case OemLockSecureStatus.FAILED:
106                     throw new RuntimeException("Failed to set carrier OEM unlock state");
107             }
108         } catch (RemoteException e) {
109             Slog.e(TAG, "Failed to set carrier state with HAL", e);
110             throw e.rethrowFromSystemServer();
111         }
112     }
113 
114     @Override
isOemUnlockAllowedByCarrier()115     boolean isOemUnlockAllowedByCarrier() {
116         final Integer[] requestStatus = new Integer[1];
117         final Boolean[] allowedByCarrier = new Boolean[1];
118 
119         try {
120             mOemLock.isOemUnlockAllowedByCarrier((status, allowed) -> {
121                 requestStatus[0] = status;
122                 allowedByCarrier[0] = allowed;
123             });
124         } catch (RemoteException e) {
125             Slog.e(TAG, "Failed to get carrier state from HAL");
126             throw e.rethrowFromSystemServer();
127         }
128 
129         switch (requestStatus[0]) {
130             case OemLockStatus.OK:
131                 // Success
132                 return allowedByCarrier[0];
133 
134             default:
135                 Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
136                 // Fallthrough
137             case OemLockStatus.FAILED:
138                 throw new RuntimeException("Failed to get carrier OEM unlock state");
139         }
140     }
141 
142     @Override
setOemUnlockAllowedByDevice(boolean allowedByDevice)143     void setOemUnlockAllowedByDevice(boolean allowedByDevice) {
144         try {
145             switch (mOemLock.setOemUnlockAllowedByDevice(allowedByDevice)) {
146                 case OemLockSecureStatus.OK:
147                     Slog.i(TAG, "Updated device allows OEM lock state to: " + allowedByDevice);
148                     return;
149 
150                 default:
151                     Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
152                     // Fallthrough
153                 case OemLockSecureStatus.FAILED:
154                     throw new RuntimeException("Failed to set device OEM unlock state");
155             }
156         } catch (RemoteException e) {
157             Slog.e(TAG, "Failed to set device state with HAL", e);
158             throw e.rethrowFromSystemServer();
159         }
160     }
161 
162     @Override
isOemUnlockAllowedByDevice()163     boolean isOemUnlockAllowedByDevice() {
164         final Integer[] requestStatus = new Integer[1];
165         final Boolean[] allowedByDevice = new Boolean[1];
166 
167         try {
168             mOemLock.isOemUnlockAllowedByDevice((status, allowed) -> {
169                 requestStatus[0] = status;
170                 allowedByDevice[0] = allowed;
171             });
172         } catch (RemoteException e) {
173             Slog.e(TAG, "Failed to get devie state from HAL");
174             throw e.rethrowFromSystemServer();
175         }
176 
177         switch (requestStatus[0]) {
178             case OemLockStatus.OK:
179                 // Success
180                 return allowedByDevice[0];
181 
182             default:
183                 Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
184                 // Fallthrough
185             case OemLockStatus.FAILED:
186                 throw new RuntimeException("Failed to get device OEM unlock state");
187         }
188     }
189 
toByteArrayList(byte[] data)190     private ArrayList<Byte> toByteArrayList(byte[] data) {
191         if (data == null) {
192             return new ArrayList<Byte>();
193         }
194         ArrayList<Byte> result = new ArrayList<Byte>(data.length);
195         for (final byte b : data) {
196             result.add(b);
197         }
198         return result;
199     }
200 }
201