1 /*
2  * Copyright (C) 2020 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 #define LOG_TAG "EmulatedUserHal"
17 
18 #include "EmulatedUserHal.h"
19 
20 #include <cutils/log.h>
21 #include <utils/SystemClock.h>
22 
23 #include "UserHalHelper.h"
24 
25 namespace android {
26 namespace hardware {
27 namespace automotive {
28 namespace vehicle {
29 namespace V2_0 {
30 
31 namespace impl {
32 
33 namespace {
34 
35 using android::base::Error;
36 using android::base::Result;
37 
38 constexpr int32_t INITIAL_USER_INFO = static_cast<int32_t>(VehicleProperty::INITIAL_USER_INFO);
39 constexpr int32_t SWITCH_USER = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
40 constexpr int32_t CREATE_USER = static_cast<int32_t>(VehicleProperty::CREATE_USER);
41 constexpr int32_t REMOVE_USER = static_cast<int32_t>(VehicleProperty::REMOVE_USER);
42 constexpr int32_t USER_IDENTIFICATION_ASSOCIATION =
43         static_cast<int32_t>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
44 
getRequestId(const VehiclePropValue & value)45 Result<int32_t> getRequestId(const VehiclePropValue& value) {
46     if (value.value.int32Values.size() < 1) {
47         return Error(static_cast<int>(StatusCode::INVALID_ARG))
48                << "no int32values on " << toString(value);
49     }
50     return value.value.int32Values[0];
51 }
52 
getSwitchUserMessageType(const VehiclePropValue & value)53 Result<SwitchUserMessageType> getSwitchUserMessageType(const VehiclePropValue& value) {
54     if (value.value.int32Values.size() < 2) {
55         return Error(static_cast<int>(StatusCode::INVALID_ARG))
56                << "missing switch user message type " << toString(value);
57     }
58     return user_hal_helper::verifyAndCast<SwitchUserMessageType>(value.value.int32Values[1]);
59 }
60 
61 }  // namespace
62 
isSupported(int32_t prop)63 bool EmulatedUserHal::isSupported(int32_t prop) {
64     switch (prop) {
65         case INITIAL_USER_INFO:
66         case SWITCH_USER:
67         case CREATE_USER:
68         case REMOVE_USER:
69         case USER_IDENTIFICATION_ASSOCIATION:
70             return true;
71         default:
72             return false;
73     }
74 }
75 
onSetProperty(const VehiclePropValue & value)76 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetProperty(
77         const VehiclePropValue& value) {
78     ALOGV("onSetProperty(): %s", toString(value).c_str());
79 
80     switch (value.prop) {
81         case INITIAL_USER_INFO:
82             return onSetInitialUserInfoResponse(value);
83         case SWITCH_USER:
84             return onSetSwitchUserResponse(value);
85         case CREATE_USER:
86             return onSetCreateUserResponse(value);
87         case REMOVE_USER:
88             ALOGI("REMOVE_USER is FYI only, nothing to do...");
89             return {};
90         case USER_IDENTIFICATION_ASSOCIATION:
91             return onSetUserIdentificationAssociation(value);
92         default:
93             return Error(static_cast<int>(StatusCode::INVALID_ARG))
94                    << "Unsupported property: " << toString(value);
95     }
96 }
97 
onGetProperty(const VehiclePropValue & value)98 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onGetProperty(
99         const VehiclePropValue& value) {
100     ALOGV("onGetProperty(%s)", toString(value).c_str());
101     switch (value.prop) {
102         case INITIAL_USER_INFO:
103         case SWITCH_USER:
104         case CREATE_USER:
105         case REMOVE_USER:
106             ALOGE("onGetProperty(): %d is only supported on SET", value.prop);
107             return Error(static_cast<int>(StatusCode::INVALID_ARG)) << "only supported on SET";
108         case USER_IDENTIFICATION_ASSOCIATION:
109             return onGetUserIdentificationAssociation(value);
110         default:
111             ALOGE("onGetProperty(): %d is not supported", value.prop);
112             return Error(static_cast<int>(StatusCode::INVALID_ARG)) << "not supported by User HAL";
113     }
114 }
115 
onGetUserIdentificationAssociation(const VehiclePropValue & value)116 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onGetUserIdentificationAssociation(
117         const VehiclePropValue& value) {
118     if (mSetUserIdentificationAssociationResponseFromCmd == nullptr) {
119         return defaultUserIdentificationAssociation(value);
120     }
121     ALOGI("get(USER_IDENTIFICATION_ASSOCIATION): returning %s",
122           toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
123     auto newValue = std::unique_ptr<VehiclePropValue>(
124             new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd));
125     auto requestId = getRequestId(value);
126     if (requestId.ok()) {
127         // Must use the same requestId
128         newValue->value.int32Values[0] = *requestId;
129     } else {
130         ALOGE("get(USER_IDENTIFICATION_ASSOCIATION): no requestId on %s", toString(value).c_str());
131     }
132     return newValue;
133 }
134 
onSetInitialUserInfoResponse(const VehiclePropValue & value)135 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetInitialUserInfoResponse(
136         const VehiclePropValue& value) {
137     auto requestId = getRequestId(value);
138     if (!requestId.ok()) {
139         ALOGE("Failed to get requestId on set(INITIAL_USER_INFO): %s",
140               requestId.error().message().c_str());
141         return requestId.error();
142     }
143 
144     if (value.areaId != 0) {
145         ALOGD("set(INITIAL_USER_INFO) called from lshal; storing it: %s", toString(value).c_str());
146         mInitialUserResponseFromCmd.reset(new VehiclePropValue(value));
147         return {};
148     }
149 
150     ALOGD("set(INITIAL_USER_INFO) called from Android: %s", toString(value).c_str());
151     if (mInitialUserResponseFromCmd != nullptr) {
152         ALOGI("replying INITIAL_USER_INFO with lshal value:  %s",
153               toString(*mInitialUserResponseFromCmd).c_str());
154         return sendUserHalResponse(std::move(mInitialUserResponseFromCmd), *requestId);
155     }
156 
157     // Returns default response
158     auto updatedValue = user_hal_helper::toVehiclePropValue(InitialUserInfoResponse{
159             .requestId = *requestId,
160             .action = InitialUserInfoResponseAction::DEFAULT,
161     });
162     ALOGI("no lshal response; replying with InitialUserInfoResponseAction::DEFAULT: %s",
163           toString(*updatedValue).c_str());
164     return updatedValue;
165 }
166 
onSetSwitchUserResponse(const VehiclePropValue & value)167 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetSwitchUserResponse(
168         const VehiclePropValue& value) {
169     auto requestId = getRequestId(value);
170     if (!requestId.ok()) {
171         ALOGE("Failed to get requestId on set(SWITCH_USER): %s",
172               requestId.error().message().c_str());
173         return requestId.error();
174     }
175 
176     auto messageType = getSwitchUserMessageType(value);
177     if (!messageType.ok()) {
178         ALOGE("Failed to get messageType on set(SWITCH_USER): %s",
179               messageType.error().message().c_str());
180         return messageType.error();
181     }
182 
183     if (value.areaId != 0) {
184         if (*messageType == SwitchUserMessageType::VEHICLE_REQUEST) {
185             // User HAL can also request a user switch, so we need to check it first
186             ALOGD("set(SWITCH_USER) called from lshal to emulate a vehicle request: %s",
187                   toString(value).c_str());
188             return std::unique_ptr<VehiclePropValue>(new VehiclePropValue(value));
189         }
190         // Otherwise, we store it
191         ALOGD("set(SWITCH_USER) called from lshal; storing it: %s", toString(value).c_str());
192         mSwitchUserResponseFromCmd.reset(new VehiclePropValue(value));
193         return {};
194     }
195     ALOGD("set(SWITCH_USER) called from Android: %s", toString(value).c_str());
196 
197     if (mSwitchUserResponseFromCmd != nullptr) {
198         ALOGI("replying SWITCH_USER with lshal value:  %s",
199               toString(*mSwitchUserResponseFromCmd).c_str());
200         return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), *requestId);
201     }
202 
203     if (*messageType == SwitchUserMessageType::LEGACY_ANDROID_SWITCH ||
204         *messageType == SwitchUserMessageType::ANDROID_POST_SWITCH) {
205         ALOGI("request is %s; ignoring it", toString(*messageType).c_str());
206         return {};
207     }
208 
209     // Returns default response
210     auto updatedValue = user_hal_helper::toVehiclePropValue(SwitchUserResponse{
211             .requestId = *requestId,
212             .messageType = SwitchUserMessageType::VEHICLE_RESPONSE,
213             .status = SwitchUserStatus::SUCCESS,
214     });
215     ALOGI("no lshal response; replying with VEHICLE_RESPONSE / SUCCESS: %s",
216           toString(*updatedValue).c_str());
217     return updatedValue;
218 }
219 
onSetCreateUserResponse(const VehiclePropValue & value)220 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetCreateUserResponse(
221         const VehiclePropValue& value) {
222     auto requestId = getRequestId(value);
223     if (!requestId.ok()) {
224         ALOGE("Failed to get requestId on set(CREATE_USER): %s",
225               requestId.error().message().c_str());
226         return requestId.error();
227     }
228 
229     if (value.areaId != 0) {
230         ALOGD("set(CREATE_USER) called from lshal; storing it: %s", toString(value).c_str());
231         mCreateUserResponseFromCmd.reset(new VehiclePropValue(value));
232         return {};
233     }
234     ALOGD("set(CREATE_USER) called from Android: %s", toString(value).c_str());
235 
236     if (mCreateUserResponseFromCmd != nullptr) {
237         ALOGI("replying CREATE_USER with lshal value:  %s",
238               toString(*mCreateUserResponseFromCmd).c_str());
239         return sendUserHalResponse(std::move(mCreateUserResponseFromCmd), *requestId);
240     }
241 
242     // Returns default response
243     auto updatedValue = user_hal_helper::toVehiclePropValue(CreateUserResponse{
244             .requestId = *requestId,
245             .status = CreateUserStatus::SUCCESS,
246     });
247     ALOGI("no lshal response; replying with SUCCESS: %s", toString(*updatedValue).c_str());
248     return updatedValue;
249 }
250 
onSetUserIdentificationAssociation(const VehiclePropValue & value)251 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::onSetUserIdentificationAssociation(
252         const VehiclePropValue& value) {
253     auto requestId = getRequestId(value);
254     if (!requestId.ok()) {
255         ALOGE("Failed to get requestId on set(USER_IDENTIFICATION_ASSOCIATION): %s",
256               requestId.error().message().c_str());
257         return requestId.error();
258     }
259 
260     if (value.areaId != 0) {
261         ALOGD("set(USER_IDENTIFICATION_ASSOCIATION) called from lshal; storing it: %s",
262               toString(value).c_str());
263         mSetUserIdentificationAssociationResponseFromCmd.reset(new VehiclePropValue(value));
264         return {};
265     }
266     ALOGD("set(USER_IDENTIFICATION_ASSOCIATION) called from Android: %s", toString(value).c_str());
267 
268     if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
269         ALOGI("replying USER_IDENTIFICATION_ASSOCIATION with lshal value:  %s",
270               toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
271         // Not moving response so it can be used on GET requests
272         auto copy = std::unique_ptr<VehiclePropValue>(
273                 new VehiclePropValue(*mSetUserIdentificationAssociationResponseFromCmd));
274         return sendUserHalResponse(std::move(copy), *requestId);
275     }
276     // Returns default response
277     return defaultUserIdentificationAssociation(value);
278 }
279 
defaultUserIdentificationAssociation(const VehiclePropValue & request)280 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::defaultUserIdentificationAssociation(
281         const VehiclePropValue& request) {
282     // TODO(b/159498909): return a response with NOT_ASSOCIATED_ANY_USER for all requested types
283     ALOGE("no lshal response for %s; replying with NOT_AVAILABLE", toString(request).c_str());
284     return Error(static_cast<int>(StatusCode::NOT_AVAILABLE)) << "not set by lshal";
285 }
286 
sendUserHalResponse(std::unique_ptr<VehiclePropValue> response,int32_t requestId)287 Result<std::unique_ptr<VehiclePropValue>> EmulatedUserHal::sendUserHalResponse(
288         std::unique_ptr<VehiclePropValue> response, int32_t requestId) {
289     switch (response->areaId) {
290         case 1:
291             ALOGD("returning response with right request id");
292             response->value.int32Values[0] = requestId;
293             break;
294         case 2:
295             ALOGD("returning response with wrong request id");
296             response->value.int32Values[0] = -requestId;
297             break;
298         case 3:
299             ALOGD("not generating a property change event because of lshal prop: %s",
300                   toString(*response).c_str());
301             return Error(static_cast<int>(StatusCode::NOT_AVAILABLE))
302                    << "not generating a property change event because of lshal prop: "
303                    << toString(*response);
304         default:
305             ALOGE("invalid action on lshal response: %s", toString(*response).c_str());
306             return Error(static_cast<int>(StatusCode::INTERNAL_ERROR))
307                    << "invalid action on lshal response: " << toString(*response);
308     }
309 
310     ALOGD("updating property to: %s", toString(*response).c_str());
311     return response;
312 }
313 
showDumpHelp(int fd)314 void EmulatedUserHal::showDumpHelp(int fd) {
315     dprintf(fd, "%s: dumps state used for user management\n", kUserHalDumpOption);
316 }
317 
dump(int fd,std::string indent)318 void EmulatedUserHal::dump(int fd, std::string indent) {
319     if (mInitialUserResponseFromCmd != nullptr) {
320         dprintf(fd, "%sInitialUserInfo response: %s\n", indent.c_str(),
321                 toString(*mInitialUserResponseFromCmd).c_str());
322     } else {
323         dprintf(fd, "%sNo InitialUserInfo response\n", indent.c_str());
324     }
325     if (mSwitchUserResponseFromCmd != nullptr) {
326         dprintf(fd, "%sSwitchUser response: %s\n", indent.c_str(),
327                 toString(*mSwitchUserResponseFromCmd).c_str());
328     } else {
329         dprintf(fd, "%sNo SwitchUser response\n", indent.c_str());
330     }
331     if (mCreateUserResponseFromCmd != nullptr) {
332         dprintf(fd, "%sCreateUser response: %s\n", indent.c_str(),
333                 toString(*mCreateUserResponseFromCmd).c_str());
334     } else {
335         dprintf(fd, "%sNo CreateUser response\n", indent.c_str());
336     }
337     if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
338         dprintf(fd, "%sSetUserIdentificationAssociation response: %s\n", indent.c_str(),
339                 toString(*mSetUserIdentificationAssociationResponseFromCmd).c_str());
340     } else {
341         dprintf(fd, "%sNo SetUserIdentificationAssociation response\n", indent.c_str());
342     }
343 }
344 
345 }  // namespace impl
346 
347 }  // namespace V2_0
348 }  // namespace vehicle
349 }  // namespace automotive
350 }  // namespace hardware
351 }  // namespace android
352