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