• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "FakeUserHal"
17 
18 #include "FakeUserHal.h"
19 
20 #include "UserHalHelper.h"
21 
22 #include <VehicleUtils.h>
23 #include <utils/Log.h>
24 #include <utils/SystemClock.h>
25 
26 namespace android {
27 namespace hardware {
28 namespace automotive {
29 namespace vehicle {
30 namespace fake {
31 
32 namespace {
33 
34 using ::aidl::android::hardware::automotive::vehicle::CreateUserResponse;
35 using ::aidl::android::hardware::automotive::vehicle::CreateUserStatus;
36 using ::aidl::android::hardware::automotive::vehicle::InitialUserInfoResponse;
37 using ::aidl::android::hardware::automotive::vehicle::InitialUserInfoResponseAction;
38 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
39 using ::aidl::android::hardware::automotive::vehicle::SwitchUserMessageType;
40 using ::aidl::android::hardware::automotive::vehicle::SwitchUserResponse;
41 using ::aidl::android::hardware::automotive::vehicle::SwitchUserStatus;
42 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
43 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
44 using ::android::base::Error;
45 using ::android::base::Result;
46 
47 constexpr int32_t INITIAL_USER_INFO = toInt(VehicleProperty::INITIAL_USER_INFO);
48 constexpr int32_t SWITCH_USER = toInt(VehicleProperty::SWITCH_USER);
49 constexpr int32_t CREATE_USER = toInt(VehicleProperty::CREATE_USER);
50 constexpr int32_t REMOVE_USER = toInt(VehicleProperty::REMOVE_USER);
51 constexpr int32_t USER_IDENTIFICATION_ASSOCIATION =
52         toInt(VehicleProperty::USER_IDENTIFICATION_ASSOCIATION);
53 
getRequestId(const VehiclePropValue & value)54 VhalResult<int32_t> getRequestId(const VehiclePropValue& value) {
55     if (value.value.int32Values.size() < 1) {
56         return StatusError(StatusCode::INVALID_ARG)
57                << "no int32Values on property: " << value.toString();
58     }
59     return value.value.int32Values[0];
60 }
61 
getSwitchUserMessageType(const VehiclePropValue & value)62 VhalResult<SwitchUserMessageType> getSwitchUserMessageType(const VehiclePropValue& value) {
63     if (value.value.int32Values.size() < 2) {
64         return StatusError(StatusCode::INVALID_ARG)
65                << "missing switch user message type on property: " << value.toString();
66     }
67     auto result = user_hal_helper::verifyAndCast<SwitchUserMessageType>(value.value.int32Values[1]);
68     if (!result.ok()) {
69         return StatusError(StatusCode::INVALID_ARG) << result.error().message();
70     }
71     return result.value();
72 }
73 
74 }  // namespace
75 
isSupported(int32_t prop)76 bool FakeUserHal::isSupported(int32_t prop) {
77     switch (prop) {
78         case INITIAL_USER_INFO:
79         case SWITCH_USER:
80         case CREATE_USER:
81         case REMOVE_USER:
82         case USER_IDENTIFICATION_ASSOCIATION:
83             return true;
84         default:
85             return false;
86     }
87 }
88 
onSetProperty(const VehiclePropValue & value)89 FakeUserHal::ValueResultType FakeUserHal::onSetProperty(const VehiclePropValue& value) {
90     ALOGV("onSetProperty(): %s", value.toString().c_str());
91 
92     switch (value.prop) {
93         case INITIAL_USER_INFO:
94             return onSetInitialUserInfoResponse(value);
95         case SWITCH_USER:
96             return onSetSwitchUserResponse(value);
97         case CREATE_USER:
98             return onSetCreateUserResponse(value);
99         case REMOVE_USER:
100             ALOGI("REMOVE_USER is FYI only, nothing to do...");
101             return nullptr;
102         case USER_IDENTIFICATION_ASSOCIATION:
103             return onSetUserIdentificationAssociation(value);
104         default:
105             return StatusError(StatusCode::INVALID_ARG)
106                    << "Unsupported property: " << value.toString();
107     }
108 }
109 
onGetProperty(const VehiclePropValue & value) const110 FakeUserHal::ValueResultType FakeUserHal::onGetProperty(const VehiclePropValue& value) const {
111     ALOGV("onGetProperty(%s)", value.toString().c_str());
112     switch (value.prop) {
113         case INITIAL_USER_INFO:
114         case SWITCH_USER:
115         case CREATE_USER:
116         case REMOVE_USER:
117             ALOGE("onGetProperty(): %d is only supported on SET", value.prop);
118             return StatusError(StatusCode::INVALID_ARG) << "only supported on SET";
119         case USER_IDENTIFICATION_ASSOCIATION:
120             return onGetUserIdentificationAssociation(value);
121         default:
122             ALOGE("onGetProperty(): %d is not supported", value.prop);
123             return StatusError(StatusCode::INVALID_ARG) << "not supported by User HAL";
124     }
125 }
126 
onGetUserIdentificationAssociation(const VehiclePropValue & value) const127 FakeUserHal::ValueResultType FakeUserHal::onGetUserIdentificationAssociation(
128         const VehiclePropValue& value) const {
129     std::scoped_lock<std::mutex> lockGuard(mLock);
130 
131     if (mSetUserIdentificationAssociationResponseFromCmd == nullptr) {
132         return defaultUserIdentificationAssociation(value);
133     }
134     ALOGI("get(USER_IDENTIFICATION_ASSOCIATION): returning %s",
135           mSetUserIdentificationAssociationResponseFromCmd->toString().c_str());
136     auto newValue = mValuePool->obtain(*mSetUserIdentificationAssociationResponseFromCmd);
137     auto requestId = getRequestId(value);
138     if (requestId.ok()) {
139         // Must use the same requestId
140         newValue->value.int32Values[0] = *requestId;
141     } else {
142         ALOGE("get(USER_IDENTIFICATION_ASSOCIATION): no requestId on %s", value.toString().c_str());
143         return requestId.error();
144     }
145     return newValue;
146 }
147 
onSetInitialUserInfoResponse(const VehiclePropValue & value)148 FakeUserHal::ValueResultType FakeUserHal::onSetInitialUserInfoResponse(
149         const VehiclePropValue& value) {
150     std::scoped_lock<std::mutex> lockGuard(mLock);
151 
152     auto requestId = getRequestId(value);
153     if (!requestId.ok()) {
154         ALOGE("Failed to get requestId on set(INITIAL_USER_INFO): %s",
155               requestId.error().message().c_str());
156         return requestId.error();
157     }
158 
159     if (value.areaId != 0) {
160         ALOGD("set(INITIAL_USER_INFO) called from lshal; storing it: %s", value.toString().c_str());
161         mInitialUserResponseFromCmd = mValuePool->obtain(value);
162         return nullptr;
163     }
164 
165     ALOGD("set(INITIAL_USER_INFO) called from Android: %s", value.toString().c_str());
166     if (mInitialUserResponseFromCmd != nullptr) {
167         ALOGI("replying INITIAL_USER_INFO with lshal value: %s",
168               mInitialUserResponseFromCmd->toString().c_str());
169         return sendUserHalResponse(std::move(mInitialUserResponseFromCmd), *requestId);
170     }
171 
172     // Returns default response
173     auto updatedValue = user_hal_helper::toVehiclePropValue(
174             *mValuePool, InitialUserInfoResponse{
175                                  .requestId = *requestId,
176                                  .action = InitialUserInfoResponseAction::DEFAULT,
177                          });
178     ALOGI("no lshal response; replying with InitialUserInfoResponseAction::DEFAULT: %s",
179           updatedValue->toString().c_str());
180     return updatedValue;
181 }
182 
onSetSwitchUserResponse(const VehiclePropValue & value)183 FakeUserHal::ValueResultType FakeUserHal::onSetSwitchUserResponse(const VehiclePropValue& value) {
184     std::scoped_lock<std::mutex> lockGuard(mLock);
185 
186     auto requestId = getRequestId(value);
187     if (!requestId.ok()) {
188         ALOGE("Failed to get requestId on set(SWITCH_USER): %s",
189               requestId.error().message().c_str());
190         return requestId.error();
191     }
192 
193     auto messageType = getSwitchUserMessageType(value);
194     if (!messageType.ok()) {
195         ALOGE("Failed to get messageType on set(SWITCH_USER): %s",
196               messageType.error().message().c_str());
197         return messageType.error();
198     }
199 
200     if (value.areaId != 0) {
201         if (*messageType == SwitchUserMessageType::VEHICLE_REQUEST) {
202             // User HAL can also request a user switch, so we need to check it first
203             ALOGD("set(SWITCH_USER) called from lshal to emulate a vehicle request: %s",
204                   value.toString().c_str());
205             return mValuePool->obtain(value);
206         }
207         // Otherwise, we store it
208         ALOGD("set(SWITCH_USER) called from lshal; storing it: %s", value.toString().c_str());
209         mSwitchUserResponseFromCmd = mValuePool->obtain(value);
210         return nullptr;
211     }
212     ALOGD("set(SWITCH_USER) called from Android: %s", value.toString().c_str());
213 
214     if (mSwitchUserResponseFromCmd != nullptr) {
215         ALOGI("replying SWITCH_USER with lshal value:  %s",
216               mSwitchUserResponseFromCmd->toString().c_str());
217         return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), *requestId);
218     }
219 
220     if (*messageType == SwitchUserMessageType::LEGACY_ANDROID_SWITCH ||
221         *messageType == SwitchUserMessageType::ANDROID_POST_SWITCH) {
222         ALOGI("request is %s; ignoring it", toString(*messageType).c_str());
223         return nullptr;
224     }
225 
226     // Returns default response
227     auto updatedValue = user_hal_helper::toVehiclePropValue(
228             *mValuePool, SwitchUserResponse{
229                                  .requestId = *requestId,
230                                  .messageType = SwitchUserMessageType::VEHICLE_RESPONSE,
231                                  .status = SwitchUserStatus::SUCCESS,
232                          });
233     ALOGI("no lshal response; replying with VEHICLE_RESPONSE / SUCCESS: %s",
234           updatedValue->toString().c_str());
235     return updatedValue;
236 }
237 
onSetCreateUserResponse(const VehiclePropValue & value)238 FakeUserHal::ValueResultType FakeUserHal::onSetCreateUserResponse(const VehiclePropValue& value) {
239     std::scoped_lock<std::mutex> lockGuard(mLock);
240 
241     auto requestId = getRequestId(value);
242     if (!requestId.ok()) {
243         ALOGE("Failed to get requestId on set(CREATE_USER): %s",
244               requestId.error().message().c_str());
245         return requestId.error();
246     }
247 
248     if (value.areaId != 0) {
249         ALOGD("set(CREATE_USER) called from lshal; storing it: %s", value.toString().c_str());
250         mCreateUserResponseFromCmd = mValuePool->obtain(value);
251         return nullptr;
252     }
253     ALOGD("set(CREATE_USER) called from Android: %s", value.toString().c_str());
254 
255     if (mCreateUserResponseFromCmd != nullptr) {
256         ALOGI("replying CREATE_USER with lshal value:  %s",
257               mCreateUserResponseFromCmd->toString().c_str());
258         return sendUserHalResponse(std::move(mCreateUserResponseFromCmd), *requestId);
259     }
260 
261     // Returns default response
262     auto updatedValue = user_hal_helper::toVehiclePropValue(
263             *mValuePool, CreateUserResponse{
264                                  .requestId = *requestId,
265                                  .status = CreateUserStatus::SUCCESS,
266                          });
267     ALOGI("no lshal response; replying with SUCCESS: %s", updatedValue->toString().c_str());
268     return updatedValue;
269 }
270 
onSetUserIdentificationAssociation(const VehiclePropValue & value)271 FakeUserHal::ValueResultType FakeUserHal::onSetUserIdentificationAssociation(
272         const VehiclePropValue& value) {
273     std::scoped_lock<std::mutex> lockGuard(mLock);
274 
275     auto requestId = getRequestId(value);
276     if (!requestId.ok()) {
277         ALOGE("Failed to get requestId on set(USER_IDENTIFICATION_ASSOCIATION): %s",
278               requestId.error().message().c_str());
279         return requestId.error();
280     }
281 
282     if (value.areaId != 0) {
283         ALOGD("set(USER_IDENTIFICATION_ASSOCIATION) called from lshal; storing it: %s",
284               value.toString().c_str());
285         mSetUserIdentificationAssociationResponseFromCmd = mValuePool->obtain(value);
286         return nullptr;
287     }
288     ALOGD("set(USER_IDENTIFICATION_ASSOCIATION) called from Android: %s", value.toString().c_str());
289 
290     if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
291         ALOGI("replying USER_IDENTIFICATION_ASSOCIATION with lshal value:  %s",
292               mSetUserIdentificationAssociationResponseFromCmd->toString().c_str());
293         // Not moving response so it can be used on GET requests
294         auto copy = mValuePool->obtain(*mSetUserIdentificationAssociationResponseFromCmd);
295         return sendUserHalResponse(std::move(copy), *requestId);
296     }
297     // Returns default response
298     return defaultUserIdentificationAssociation(value);
299 }
300 
defaultUserIdentificationAssociation(const VehiclePropValue & request)301 FakeUserHal::ValueResultType FakeUserHal::defaultUserIdentificationAssociation(
302         const VehiclePropValue& request) {
303     // TODO(b/159498909): return a response with NOT_ASSOCIATED_ANY_USER for all requested types
304     ALOGE("no lshal response for %s; replying with NOT_AVAILABLE", request.toString().c_str());
305     return StatusError(StatusCode::NOT_AVAILABLE) << "not set by lshal";
306 }
307 
sendUserHalResponse(VehiclePropValuePool::RecyclableType response,int32_t requestId)308 FakeUserHal::ValueResultType FakeUserHal::sendUserHalResponse(
309         VehiclePropValuePool::RecyclableType response, int32_t requestId) {
310     switch (response->areaId) {
311         case 1:
312             ALOGD("returning response with right request id");
313             response->value.int32Values[0] = requestId;
314             break;
315         case 2:
316             ALOGD("returning response with wrong request id");
317             response->value.int32Values[0] = -requestId;
318             break;
319         case 3:
320             ALOGD("not generating a property change event because of lshal prop: %s",
321                   response->toString().c_str());
322             return StatusError(StatusCode::NOT_AVAILABLE)
323                    << "not generating a property change event because of lshal prop: "
324                    << response->toString();
325         default:
326             ALOGE("invalid action on lshal response: %s", response->toString().c_str());
327             return StatusError(StatusCode::INTERNAL_ERROR)
328                    << "invalid action on lshal response: " << response->toString();
329     }
330 
331     // Update area ID to 0 since this is a global property (and the area ID was only set to emulate
332     // the request id behavior).
333     response->areaId = 0;
334     ALOGD("updating property to: %s", response->toString().c_str());
335     return response;
336 }
337 
showDumpHelp() const338 std::string FakeUserHal::showDumpHelp() const {
339     return fmt::format("{}: dumps state used for user management\n", kUserHalDumpOption);
340 }
341 
dump() const342 std::string FakeUserHal::dump() const {
343     std::scoped_lock<std::mutex> lockGuard(mLock);
344 
345     std::string info;
346     if (mInitialUserResponseFromCmd != nullptr) {
347         info += fmt::format("InitialUserInfo response: {}\n",
348                             mInitialUserResponseFromCmd->toString());
349     } else {
350         info += "No InitialUserInfo response\n";
351     }
352     if (mSwitchUserResponseFromCmd != nullptr) {
353         info += fmt::format("SwitchUser response: {}\n", mSwitchUserResponseFromCmd->toString());
354     } else {
355         info += "No SwitchUser response\n";
356     }
357     if (mCreateUserResponseFromCmd != nullptr) {
358         info += fmt::format("CreateUser response: {}\n", mCreateUserResponseFromCmd->toString());
359     } else {
360         info += "No CreateUser response\n";
361     }
362     if (mSetUserIdentificationAssociationResponseFromCmd != nullptr) {
363         info += fmt::format("SetUserIdentificationAssociation response: {}\n",
364                             mSetUserIdentificationAssociationResponseFromCmd->toString());
365     } else {
366         info += "No SetUserIdentificationAssociation response\n";
367     }
368     return info;
369 }
370 
371 }  // namespace fake
372 }  // namespace vehicle
373 }  // namespace automotive
374 }  // namespace hardware
375 }  // namespace android
376