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