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