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 "UserHalHelper"
17
18 #include "UserHalHelper.h"
19
20 #include <log/log.h>
21 #include <utils/SystemClock.h>
22
23 namespace android {
24 namespace hardware {
25 namespace automotive {
26 namespace vehicle {
27 namespace V2_0 {
28
29 namespace user_hal_helper {
30 namespace {
31
32 using android::base::Error;
33 using android::base::Result;
34
35 static constexpr const char* kSeparator = "||";
36 static const size_t kNumFieldsPerUserInfo = 2;
37 static const size_t kNumFieldsPerSetAssociation = 2;
38
verifyPropValue(const VehiclePropValue & propValue,VehicleProperty vehicleProperty,size_t minInt32Values)39 Result<void> verifyPropValue(const VehiclePropValue& propValue, VehicleProperty vehicleProperty,
40 size_t minInt32Values) {
41 auto prop = verifyAndCast<VehicleProperty>(propValue.prop);
42 if (!prop.ok()) {
43 return Error() << "Invalid vehicle property: " << prop.error();
44 }
45 if (*prop != vehicleProperty) {
46 return Error() << "Mismatching " << toString(vehicleProperty) << " request, received "
47 << toString(*prop) << " property";
48 }
49 if (propValue.value.int32Values.size() < minInt32Values) {
50 return Error() << "Int32Values must have at least " << minInt32Values
51 << " values, received " << propValue.value.int32Values.size();
52 }
53 return {};
54 }
55
parseUserInfo(const hidl_vec<int32_t> & int32Values,size_t startPos,UserInfo * userInfo)56 Result<void> parseUserInfo(const hidl_vec<int32_t>& int32Values, size_t startPos,
57 UserInfo* userInfo) {
58 if (int32Values.size() < startPos + kNumFieldsPerUserInfo) {
59 return Error() << "Int32Values must have at least " << startPos + 2 << " values, received "
60 << int32Values.size();
61 }
62 userInfo->userId = int32Values[startPos];
63 int32_t intUserFlags = int32Values[startPos + 1];
64 int32_t expectedUserFlags = 0;
65 for (const auto& v : hidl_enum_range<UserFlags>()) {
66 int32_t intEnumUserFlag = static_cast<int32_t>(v);
67 if ((intUserFlags & intEnumUserFlag) != 0) {
68 expectedUserFlags |= intEnumUserFlag;
69 }
70 }
71 if (intUserFlags != expectedUserFlags) {
72 return Error() << "Invalid user flags: " << intUserFlags << ", must be '|' of UserFlags";
73 }
74 // intUserFlags is actually not a valid UserFlags enum, instead, it is a 'bit or' of possible
75 // multiple UserFlags. However, because the HAL interface was defined incorrectly, we have to
76 // cast it to UserFlags here, which is defined behavior because the underlying type for
77 // UserFlags is int32_t and our intUserFlags is within the range of int32_t.
78 userInfo->flags = static_cast<UserFlags>(intUserFlags);
79 return {};
80 }
81
parseUsersInfo(const hidl_vec<int32_t> & int32Values,size_t startPos,UsersInfo * usersInfo)82 Result<void> parseUsersInfo(const hidl_vec<int32_t>& int32Values, size_t startPos,
83 UsersInfo* usersInfo) {
84 if (int32Values.size() < startPos + 3) {
85 return Error() << "Int32Values must have at least " << startPos + 3 << " values, received "
86 << int32Values.size();
87 }
88 auto ret = parseUserInfo(int32Values, startPos, &usersInfo->currentUser);
89 if (!ret.ok()) {
90 return ret;
91 }
92 usersInfo->numberUsers = int32Values[startPos + 2];
93 usersInfo->existingUsers.resize(usersInfo->numberUsers);
94 for (size_t i = 0; i < static_cast<size_t>(usersInfo->numberUsers); ++i) {
95 ret = parseUserInfo(int32Values, startPos + 3 + (kNumFieldsPerUserInfo * i),
96 &usersInfo->existingUsers[i]);
97 if (!ret.ok()) {
98 return Error() << "Failed to parse existing user '" << i << "' info: " << ret.error();
99 }
100 }
101 return {};
102 }
103
parseUserAssociationTypes(const hidl_vec<int32_t> & int32Values,size_t startPos,size_t numberAssociationTypes,hidl_vec<UserIdentificationAssociationType> * associationTypes)104 Result<void> parseUserAssociationTypes(
105 const hidl_vec<int32_t>& int32Values, size_t startPos, size_t numberAssociationTypes,
106 hidl_vec<UserIdentificationAssociationType>* associationTypes) {
107 size_t minInt32Values = startPos + numberAssociationTypes;
108 if (int32Values.size() < minInt32Values) {
109 return Error() << "Int32Values must have at least " << minInt32Values
110 << " values, received " << int32Values.size();
111 }
112 associationTypes->resize(numberAssociationTypes);
113 for (size_t i = 0; i < static_cast<size_t>(numberAssociationTypes); ++i) {
114 size_t pos = startPos + i;
115 auto type = verifyAndCast<UserIdentificationAssociationType>(int32Values[pos]);
116 if (!type.ok()) {
117 return Error() << "Invalid association type in query '" << i << "': " << type.error();
118 }
119 (*associationTypes)[i] = *type;
120 }
121 return {};
122 }
123
parseUserAssociations(const hidl_vec<int32_t> & int32Values,size_t startPos,size_t numberAssociations,hidl_vec<UserIdentificationSetAssociation> * associations)124 Result<void> parseUserAssociations(const hidl_vec<int32_t>& int32Values, size_t startPos,
125 size_t numberAssociations,
126 hidl_vec<UserIdentificationSetAssociation>* associations) {
127 size_t minInt32Values = startPos + (numberAssociations * kNumFieldsPerSetAssociation);
128 if (int32Values.size() < minInt32Values) {
129 return Error() << "Int32Values must have at least " << minInt32Values
130 << " values, received " << int32Values.size();
131 }
132 associations->resize(numberAssociations);
133 for (size_t i = 0; i < static_cast<size_t>(numberAssociations); ++i) {
134 size_t pos = startPos + (kNumFieldsPerSetAssociation * i);
135 auto type = verifyAndCast<UserIdentificationAssociationType>(int32Values[pos]);
136 if (!type.ok()) {
137 return Error() << "Invalid association type in request '" << i << "': " << type.error();
138 }
139 (*associations)[i].type = *type;
140 auto value = verifyAndCast<UserIdentificationAssociationSetValue>(int32Values[pos + 1]);
141 if (!value.ok()) {
142 return Error() << "Invalid association set value in request '" << i
143 << "': " << value.error();
144 }
145 (*associations)[i].value = *value;
146 }
147 return {};
148 }
149
150 } // namespace
151
152 template <typename T>
verifyAndCast(int32_t value)153 Result<T> verifyAndCast(int32_t value) {
154 T castValue = static_cast<T>(value);
155 for (const auto& v : hidl_enum_range<T>()) {
156 if (castValue == v) {
157 return castValue;
158 }
159 }
160 return Error() << "Value " << value << " not in enum values";
161 }
162
toInitialUserInfoRequest(const VehiclePropValue & propValue)163 Result<InitialUserInfoRequest> toInitialUserInfoRequest(const VehiclePropValue& propValue) {
164 auto ret = verifyPropValue(propValue, VehicleProperty::INITIAL_USER_INFO, 2);
165 if (!ret.ok()) {
166 return ret.error();
167 }
168 InitialUserInfoRequest request;
169 request.requestId = propValue.value.int32Values[0];
170 auto requestType = verifyAndCast<InitialUserInfoRequestType>(propValue.value.int32Values[1]);
171 if (!requestType.ok()) {
172 return Error() << "Invalid InitialUserInfoRequestType: " << requestType.error();
173 }
174 request.requestType = *requestType;
175 ret = parseUsersInfo(propValue.value.int32Values, 2, &request.usersInfo);
176 if (!ret.ok()) {
177 return Error() << "Failed to parse users info: " << ret.error();
178 }
179 return request;
180 }
181
toSwitchUserRequest(const VehiclePropValue & propValue)182 Result<SwitchUserRequest> toSwitchUserRequest(const VehiclePropValue& propValue) {
183 auto ret = verifyPropValue(propValue, VehicleProperty::SWITCH_USER, 2);
184 if (!ret.ok()) {
185 return ret.error();
186 }
187 SwitchUserRequest request;
188 auto messageType = verifyAndCast<SwitchUserMessageType>(propValue.value.int32Values[1]);
189 if (!messageType.ok()) {
190 return Error() << "Invalid SwitchUserMessageType: " << messageType.error();
191 }
192 if (*messageType != SwitchUserMessageType::LEGACY_ANDROID_SWITCH &&
193 *messageType != SwitchUserMessageType::ANDROID_SWITCH &&
194 *messageType != SwitchUserMessageType::ANDROID_POST_SWITCH) {
195 return Error() << "Invalid " << toString(*messageType)
196 << " message type from Android System";
197 }
198 request.requestId = propValue.value.int32Values[0];
199 request.messageType = *messageType;
200 ret = parseUserInfo(propValue.value.int32Values, 2, &request.targetUser);
201 if (!ret.ok()) {
202 return Error() << "Failed to parse target user info: " << ret.error();
203 }
204 ret = parseUsersInfo(propValue.value.int32Values, 4, &request.usersInfo);
205 if (!ret.ok()) {
206 return Error() << "Failed to parse users info: " << ret.error();
207 }
208 return request;
209 }
210
toCreateUserRequest(const VehiclePropValue & propValue)211 Result<CreateUserRequest> toCreateUserRequest(const VehiclePropValue& propValue) {
212 auto ret = verifyPropValue(propValue, VehicleProperty::CREATE_USER, 1);
213 if (!ret.ok()) {
214 return ret.error();
215 }
216 CreateUserRequest request;
217 request.requestId = propValue.value.int32Values[0];
218 ret = parseUserInfo(propValue.value.int32Values, 1, &request.newUserInfo);
219 if (!ret.ok()) {
220 return Error() << "Failed to parse new user info: " << ret.error();
221 }
222 request.newUserName = propValue.value.stringValue;
223 ret = parseUsersInfo(propValue.value.int32Values, 3, &request.usersInfo);
224 if (!ret.ok()) {
225 return Error() << "Failed to parse users info: " << ret.error();
226 }
227 return request;
228 }
229
toRemoveUserRequest(const VehiclePropValue & propValue)230 Result<RemoveUserRequest> toRemoveUserRequest(const VehiclePropValue& propValue) {
231 auto ret = verifyPropValue(propValue, VehicleProperty::REMOVE_USER, 1);
232 if (!ret.ok()) {
233 return ret.error();
234 }
235 RemoveUserRequest request;
236 request.requestId = propValue.value.int32Values[0];
237 ret = parseUserInfo(propValue.value.int32Values, 1, &request.removedUserInfo);
238 if (!ret.ok()) {
239 return Error() << "Failed to parse removed user info: " << ret.error();
240 }
241 ret = parseUsersInfo(propValue.value.int32Values, 3, &request.usersInfo);
242 if (!ret.ok()) {
243 return Error() << "Failed to parse users info: " << ret.error();
244 }
245 return request;
246 }
247
toUserIdentificationGetRequest(const VehiclePropValue & propValue)248 Result<UserIdentificationGetRequest> toUserIdentificationGetRequest(
249 const VehiclePropValue& propValue) {
250 auto ret = verifyPropValue(propValue, VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 4);
251 if (!ret.ok()) {
252 return ret.error();
253 }
254 UserIdentificationGetRequest request;
255 request.requestId = propValue.value.int32Values[0];
256 ret = parseUserInfo(propValue.value.int32Values, 1, &request.userInfo);
257 if (!ret.ok()) {
258 return Error() << "Failed to parse user info: " << ret.error();
259 }
260 request.numberAssociationTypes = propValue.value.int32Values[3];
261 ret = parseUserAssociationTypes(propValue.value.int32Values, 4, request.numberAssociationTypes,
262 &request.associationTypes);
263 if (!ret.ok()) {
264 return Error() << "Failed to parse UserIdentificationAssociationType: " << ret.error();
265 }
266 return request;
267 }
268
toUserIdentificationSetRequest(const VehiclePropValue & propValue)269 Result<UserIdentificationSetRequest> toUserIdentificationSetRequest(
270 const VehiclePropValue& propValue) {
271 auto ret = verifyPropValue(propValue, VehicleProperty::USER_IDENTIFICATION_ASSOCIATION, 4);
272 if (!ret.ok()) {
273 return ret.error();
274 }
275 UserIdentificationSetRequest request;
276 request.requestId = propValue.value.int32Values[0];
277 ret = parseUserInfo(propValue.value.int32Values, 1, &request.userInfo);
278 if (!ret.ok()) {
279 return Error() << "Failed to parse user info: " << ret.error();
280 }
281 request.numberAssociations = propValue.value.int32Values[3];
282 ret = parseUserAssociations(propValue.value.int32Values, 4, request.numberAssociations,
283 &request.associations);
284 if (!ret.ok()) {
285 return Error() << "Failed to parse UserIdentificationSetAssociation: " << ret.error();
286 }
287 return request;
288 }
289
toVehiclePropValue(const SwitchUserRequest & request)290 std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserRequest& request) {
291 if (request.messageType != SwitchUserMessageType::VEHICLE_REQUEST) {
292 ALOGE("Invalid %s message type %s from HAL", toString(VehicleProperty::SWITCH_USER).c_str(),
293 toString(request.messageType).c_str());
294 return nullptr;
295 }
296 auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
297 propValue->prop = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
298 propValue->timestamp = elapsedRealtimeNano();
299 propValue->value.int32Values.resize(3);
300 propValue->value.int32Values[0] = static_cast<int32_t>(request.requestId);
301 propValue->value.int32Values[1] = static_cast<int32_t>(request.messageType);
302 propValue->value.int32Values[2] = static_cast<int32_t>(request.targetUser.userId);
303 return propValue;
304 }
305
toVehiclePropValue(const InitialUserInfoResponse & response)306 std::unique_ptr<VehiclePropValue> toVehiclePropValue(const InitialUserInfoResponse& response) {
307 auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
308 propValue->prop = static_cast<int32_t>(VehicleProperty::INITIAL_USER_INFO);
309 propValue->timestamp = elapsedRealtimeNano();
310 propValue->value.int32Values.resize(4);
311 propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
312 propValue->value.int32Values[1] = static_cast<int32_t>(response.action);
313 propValue->value.int32Values[2] = static_cast<int32_t>(response.userToSwitchOrCreate.userId);
314 propValue->value.int32Values[3] = static_cast<int32_t>(response.userToSwitchOrCreate.flags);
315 propValue->value.stringValue = std::string(response.userLocales) + std::string(kSeparator) +
316 std::string(response.userNameToCreate);
317 return propValue;
318 }
319
toVehiclePropValue(const SwitchUserResponse & response)320 std::unique_ptr<VehiclePropValue> toVehiclePropValue(const SwitchUserResponse& response) {
321 auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
322 propValue->prop = static_cast<int32_t>(VehicleProperty::SWITCH_USER);
323 propValue->timestamp = elapsedRealtimeNano();
324 propValue->value.int32Values.resize(3);
325 propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
326 propValue->value.int32Values[1] = static_cast<int32_t>(response.messageType);
327 propValue->value.int32Values[2] = static_cast<int32_t>(response.status);
328 if (response.status == SwitchUserStatus::FAILURE) {
329 propValue->value.stringValue = response.errorMessage;
330 }
331 return propValue;
332 }
333
toVehiclePropValue(const CreateUserResponse & response)334 std::unique_ptr<VehiclePropValue> toVehiclePropValue(const CreateUserResponse& response) {
335 auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
336 propValue->prop = static_cast<int32_t>(VehicleProperty::CREATE_USER);
337 propValue->timestamp = elapsedRealtimeNano();
338 propValue->value.int32Values.resize(2);
339 propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
340 propValue->value.int32Values[1] = static_cast<int32_t>(response.status);
341 if (response.status == CreateUserStatus::FAILURE) {
342 propValue->value.stringValue = response.errorMessage;
343 }
344 return propValue;
345 }
346
toVehiclePropValue(const UserIdentificationResponse & response)347 std::unique_ptr<VehiclePropValue> toVehiclePropValue(const UserIdentificationResponse& response) {
348 auto propValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue());
349 propValue->prop = static_cast<int32_t>(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
350 propValue->timestamp = elapsedRealtimeNano();
351 propValue->value.int32Values.resize(2 + (response.numberAssociation * 2));
352 propValue->value.int32Values[0] = static_cast<int32_t>(response.requestId);
353 propValue->value.int32Values[1] = static_cast<int32_t>(response.numberAssociation);
354 for (size_t i = 0; i < static_cast<size_t>(response.numberAssociation); ++i) {
355 size_t int32ValuesPos = 2 + (2 * i);
356 propValue->value.int32Values[int32ValuesPos] =
357 static_cast<int32_t>(response.associations[i].type);
358 propValue->value.int32Values[int32ValuesPos + 1] =
359 static_cast<int32_t>(response.associations[i].value);
360 }
361 if (!response.errorMessage.empty()) {
362 propValue->value.stringValue = response.errorMessage;
363 }
364 return propValue;
365 }
366
367 } // namespace user_hal_helper
368
369 } // namespace V2_0
370 } // namespace vehicle
371 } // namespace automotive
372 } // namespace hardware
373 } // namespace android
374