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 /** Uses the OEM lock HAL. */
31 class VendorLockHidl extends OemLock {
32     private static final String TAG = "OemLock";
33 
34     private Context mContext;
35     private IOemLock mOemLock;
36 
getOemLockHalService()37     static IOemLock getOemLockHalService() {
38         try {
39             return IOemLock.getService(/* retry */ true);
40         } catch (NoSuchElementException e) {
41             Slog.i(TAG, "OemLock Hidl HAL not present on device");
42             return null;
43         } catch (RemoteException e) {
44             throw e.rethrowFromSystemServer();
45         }
46     }
47 
VendorLockHidl(Context context)48     VendorLockHidl(Context context) {
49         mContext = context;
50         mOemLock = getOemLockHalService();
51     }
52 
53     @Override
54     @Nullable
getLockName()55     String getLockName() {
56         final String[] lockName = new String[1];
57         final Integer[] requestStatus = new Integer[1];
58 
59         try {
60             mOemLock.getName(
61                     (status, name) -> {
62                         requestStatus[0] = status;
63                         lockName[0] = name;
64                     });
65         } catch (RemoteException e) {
66             Slog.e(TAG, "Failed to get name from HAL", e);
67             throw e.rethrowFromSystemServer();
68         }
69 
70         switch (requestStatus[0]) {
71             case OemLockStatus.OK:
72                 // Success
73                 return lockName[0];
74 
75             case OemLockStatus.FAILED:
76                 Slog.e(TAG, "Failed to get OEM lock name.");
77                 return null;
78 
79             default:
80                 Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
81                 return null;
82         }
83     }
84 
85     @Override
setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature)86     void setOemUnlockAllowedByCarrier(boolean allowed, @Nullable byte[] signature) {
87         try {
88             ArrayList<Byte> signatureBytes = toByteArrayList(signature);
89             switch (mOemLock.setOemUnlockAllowedByCarrier(allowed, signatureBytes)) {
90                 case OemLockSecureStatus.OK:
91                     Slog.i(TAG, "Updated carrier allows OEM lock state to: " + allowed);
92                     return;
93 
94                 case OemLockSecureStatus.INVALID_SIGNATURE:
95                     if (signatureBytes.isEmpty()) {
96                         throw new IllegalArgumentException("Signature required for carrier unlock");
97                     }
98                     throw new SecurityException(
99                             "Invalid signature used in attempt to carrier unlock");
100 
101                 default:
102                     Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
103                     // Fallthrough
104                 case OemLockSecureStatus.FAILED:
105                     throw new RuntimeException("Failed to set carrier OEM unlock state");
106             }
107         } catch (RemoteException e) {
108             Slog.e(TAG, "Failed to set carrier state with HAL", e);
109             throw e.rethrowFromSystemServer();
110         }
111     }
112 
113     @Override
isOemUnlockAllowedByCarrier()114     boolean isOemUnlockAllowedByCarrier() {
115         final Boolean[] allowedByCarrier = new Boolean[1];
116         final Integer[] requestStatus = new Integer[1];
117         try {
118             mOemLock.isOemUnlockAllowedByCarrier(
119                     (status, allowed) -> {
120                         requestStatus[0] = status;
121                         allowedByCarrier[0] = allowed;
122                     });
123         } catch (RemoteException e) {
124             Slog.e(TAG, "Failed to get carrier state from HAL");
125             throw e.rethrowFromSystemServer();
126         }
127 
128         switch (requestStatus[0]) {
129             case OemLockStatus.OK:
130                 // Success
131                 return allowedByCarrier[0];
132 
133             default:
134                 Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
135                 // Fallthrough
136             case OemLockStatus.FAILED:
137                 throw new RuntimeException("Failed to get carrier OEM unlock state");
138         }
139     }
140 
141     @Override
setOemUnlockAllowedByDevice(boolean allowedByDevice)142     void setOemUnlockAllowedByDevice(boolean allowedByDevice) {
143         try {
144             switch (mOemLock.setOemUnlockAllowedByDevice(allowedByDevice)) {
145                 case OemLockSecureStatus.OK:
146                     Slog.i(TAG, "Updated device allows OEM lock state to: " + allowedByDevice);
147                     return;
148 
149                 default:
150                     Slog.e(TAG, "Unknown return value indicates code is out of sync with HAL");
151                     // Fallthrough
152                 case OemLockSecureStatus.FAILED:
153                     throw new RuntimeException("Failed to set device OEM unlock state");
154             }
155         } catch (RemoteException e) {
156             Slog.e(TAG, "Failed to set device state with HAL", e);
157             throw e.rethrowFromSystemServer();
158         }
159     }
160 
161     @Override
isOemUnlockAllowedByDevice()162     boolean isOemUnlockAllowedByDevice() {
163         final Boolean[] allowedByDevice = new Boolean[1];
164 
165         final Integer[] requestStatus = new Integer[1];
166         try {
167             mOemLock.isOemUnlockAllowedByDevice(
168                     (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