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