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