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 "FakeVehicleHardware"
18 #define ATRACE_TAG ATRACE_TAG_HAL
19 #define FAKE_VEHICLEHARDWARE_DEBUG false // STOPSHIP if true.
20
21 #include "FakeVehicleHardware.h"
22
23 #include <FakeObd2Frame.h>
24 #include <JsonFakeValueGenerator.h>
25 #include <LinearFakeValueGenerator.h>
26 #include <PropertyUtils.h>
27 #include <VehicleHalTypes.h>
28 #include <VehicleUtils.h>
29
30 #include <android-base/file.h>
31 #include <android-base/parsedouble.h>
32 #include <android-base/properties.h>
33 #include <android-base/strings.h>
34 #include <android/hardware/automotive/vehicle/TestVendorProperty.h>
35 #include <utils/Log.h>
36 #include <utils/SystemClock.h>
37 #include <utils/Trace.h>
38
39 #include <dirent.h>
40 #include <inttypes.h>
41 #include <sys/types.h>
42 #include <regex>
43 #include <unordered_set>
44 #include <vector>
45
46 namespace android {
47 namespace hardware {
48 namespace automotive {
49 namespace vehicle {
50 namespace fake {
51
52 namespace {
53
54 #define PROP_ID_TO_CSTR(A) (propIdToString(A).c_str())
55
56 using ::aidl::android::hardware::automotive::vehicle::CruiseControlCommand;
57 using ::aidl::android::hardware::automotive::vehicle::CruiseControlType;
58 using ::aidl::android::hardware::automotive::vehicle::DriverDistractionState;
59 using ::aidl::android::hardware::automotive::vehicle::DriverDistractionWarning;
60 using ::aidl::android::hardware::automotive::vehicle::DriverDrowsinessAttentionState;
61 using ::aidl::android::hardware::automotive::vehicle::DriverDrowsinessAttentionWarning;
62 using ::aidl::android::hardware::automotive::vehicle::ErrorState;
63 using ::aidl::android::hardware::automotive::vehicle::GetValueRequest;
64 using ::aidl::android::hardware::automotive::vehicle::GetValueResult;
65 using ::aidl::android::hardware::automotive::vehicle::RawPropValues;
66 using ::aidl::android::hardware::automotive::vehicle::SetValueRequest;
67 using ::aidl::android::hardware::automotive::vehicle::SetValueResult;
68 using ::aidl::android::hardware::automotive::vehicle::StatusCode;
69 using ::aidl::android::hardware::automotive::vehicle::SubscribeOptions;
70 using ::aidl::android::hardware::automotive::vehicle::toString;
71 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReport;
72 using ::aidl::android::hardware::automotive::vehicle::VehicleApPowerStateReq;
73 using ::aidl::android::hardware::automotive::vehicle::VehicleArea;
74 using ::aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction;
75 using ::aidl::android::hardware::automotive::vehicle::VehiclePropConfig;
76 using ::aidl::android::hardware::automotive::vehicle::VehicleProperty;
77 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyAccess;
78 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyChangeMode;
79 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyGroup;
80 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyStatus;
81 using ::aidl::android::hardware::automotive::vehicle::VehiclePropertyType;
82 using ::aidl::android::hardware::automotive::vehicle::VehiclePropValue;
83 using ::aidl::android::hardware::automotive::vehicle::VehicleUnit;
84
85 using ::android::hardware::automotive::remoteaccess::GetApPowerBootupReasonRequest;
86 using ::android::hardware::automotive::remoteaccess::GetApPowerBootupReasonResponse;
87 using ::android::hardware::automotive::remoteaccess::IsVehicleInUseRequest;
88 using ::android::hardware::automotive::remoteaccess::IsVehicleInUseResponse;
89 using ::android::hardware::automotive::remoteaccess::PowerController;
90
91 using ::android::base::EqualsIgnoreCase;
92 using ::android::base::Error;
93 using ::android::base::GetIntProperty;
94 using ::android::base::ParseFloat;
95 using ::android::base::Result;
96 using ::android::base::ScopedLockAssertion;
97 using ::android::base::StartsWith;
98 using ::android::base::StringPrintf;
99
100 // In order to test large number of vehicle property configs, we might generate additional fake
101 // property config start from this ID. These fake properties are for getPropertyList,
102 // getPropertiesAsync, and setPropertiesAsync.
103 // 0x21403000
104 constexpr int32_t STARTING_VENDOR_CODE_PROPERTIES_FOR_TEST =
105 0x3000 | toInt(VehiclePropertyGroup::VENDOR) | toInt(VehicleArea::GLOBAL) |
106 toInt(VehiclePropertyType::INT32);
107 // 0x21405000
108 constexpr int32_t ENDING_VENDOR_CODE_PROPERTIES_FOR_TEST =
109 0x5000 | toInt(VehiclePropertyGroup::VENDOR) | toInt(VehicleArea::GLOBAL) |
110 toInt(VehiclePropertyType::INT32);
111 // The directory for default property configuration file.
112 // For config file format, see impl/default_config/config/README.md.
113 constexpr char DEFAULT_CONFIG_DIR[] = "/vendor/etc/automotive/vhalconfig/";
114 // The directory for property configuration file that overrides the default configuration file.
115 // For config file format, see impl/default_config/config/README.md.
116 constexpr char OVERRIDE_CONFIG_DIR[] = "/vendor/etc/automotive/vhaloverride/";
117 // The optional config file for power controller grpc service that provides vehicleInUse and
118 // ApPowerBootupReason property.
119 constexpr char GRPC_SERVICE_CONFIG_FILE[] = "/vendor/etc/automotive/powercontroller/serverconfig";
120 // If OVERRIDE_PROPERTY is set, we will use the configuration files from OVERRIDE_CONFIG_DIR to
121 // overwrite the default configs.
122 constexpr char OVERRIDE_PROPERTY[] = "persist.vendor.vhal_init_value_override";
123 constexpr char POWER_STATE_REQ_CONFIG_PROPERTY[] = "ro.vendor.fake_vhal.ap_power_state_req.config";
124 // The value to be returned if VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING is set as the property
125 constexpr int VENDOR_ERROR_CODE = 0x00ab0005;
126 // A list of supported options for "--set" command.
127 const std::unordered_set<std::string> SET_PROP_OPTIONS = {
128 // integer.
129 "-i",
130 // 64bit integer.
131 "-i64",
132 // float.
133 "-f",
134 // string.
135 "-s",
136 // bytes in hex format, e.g. 0xDEADBEEF.
137 "-b",
138 // Area id in integer.
139 "-a",
140 // Timestamp in int64.
141 "-t"};
142
143 // ADAS _ENABLED property to list of ADAS state properties using ErrorState enum.
144 const std::unordered_map<int32_t, std::vector<int32_t>> mAdasEnabledPropToAdasPropWithErrorState = {
145 // AEB
146 {
147 toInt(VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_ENABLED),
148 {
149 toInt(VehicleProperty::AUTOMATIC_EMERGENCY_BRAKING_STATE),
150 },
151 },
152 // FCW
153 {
154 toInt(VehicleProperty::FORWARD_COLLISION_WARNING_ENABLED),
155 {
156 toInt(VehicleProperty::FORWARD_COLLISION_WARNING_STATE),
157 },
158 },
159 // BSW
160 {
161 toInt(VehicleProperty::BLIND_SPOT_WARNING_ENABLED),
162 {
163 toInt(VehicleProperty::BLIND_SPOT_WARNING_STATE),
164 },
165 },
166 // LDW
167 {
168 toInt(VehicleProperty::LANE_DEPARTURE_WARNING_ENABLED),
169 {
170 toInt(VehicleProperty::LANE_DEPARTURE_WARNING_STATE),
171 },
172 },
173 // LKA
174 {
175 toInt(VehicleProperty::LANE_KEEP_ASSIST_ENABLED),
176 {
177 toInt(VehicleProperty::LANE_KEEP_ASSIST_STATE),
178 },
179 },
180 // LCA
181 {
182 toInt(VehicleProperty::LANE_CENTERING_ASSIST_ENABLED),
183 {
184 toInt(VehicleProperty::LANE_CENTERING_ASSIST_STATE),
185 },
186 },
187 // ELKA
188 {
189 toInt(VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_ENABLED),
190 {
191 toInt(VehicleProperty::EMERGENCY_LANE_KEEP_ASSIST_STATE),
192 },
193 },
194 // CC
195 {
196 toInt(VehicleProperty::CRUISE_CONTROL_ENABLED),
197 {
198 toInt(VehicleProperty::CRUISE_CONTROL_TYPE),
199 toInt(VehicleProperty::CRUISE_CONTROL_STATE),
200 },
201 },
202 // HOD
203 {
204 toInt(VehicleProperty::HANDS_ON_DETECTION_ENABLED),
205 {
206 toInt(VehicleProperty::HANDS_ON_DETECTION_DRIVER_STATE),
207 toInt(VehicleProperty::HANDS_ON_DETECTION_WARNING),
208 },
209 },
210 // Driver Drowsiness and Attention
211 {
212 toInt(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_SYSTEM_ENABLED),
213 {
214 toInt(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_STATE),
215 },
216 },
217 // Driver Drowsiness and Attention Warning
218 {
219 toInt(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING_ENABLED),
220 {
221 toInt(VehicleProperty::DRIVER_DROWSINESS_ATTENTION_WARNING),
222 },
223 },
224 // Driver Distraction
225 {
226 toInt(VehicleProperty::DRIVER_DISTRACTION_SYSTEM_ENABLED),
227 {
228 toInt(VehicleProperty::DRIVER_DISTRACTION_STATE),
229 toInt(VehicleProperty::DRIVER_DISTRACTION_WARNING),
230 },
231 },
232 // Driver Distraction Warning
233 {
234 toInt(VehicleProperty::DRIVER_DISTRACTION_WARNING_ENABLED),
235 {
236 toInt(VehicleProperty::DRIVER_DISTRACTION_WARNING),
237 },
238 },
239 // LSCW
240 {
241 toInt(VehicleProperty::LOW_SPEED_COLLISION_WARNING_ENABLED),
242 {
243 toInt(VehicleProperty::LOW_SPEED_COLLISION_WARNING_STATE),
244 },
245 },
246 // ESC
247 {
248 toInt(VehicleProperty::ELECTRONIC_STABILITY_CONTROL_ENABLED),
249 {
250 toInt(VehicleProperty::ELECTRONIC_STABILITY_CONTROL_STATE),
251 },
252 },
253 // CTMW
254 {
255 toInt(VehicleProperty::CROSS_TRAFFIC_MONITORING_ENABLED),
256 {
257 toInt(VehicleProperty::CROSS_TRAFFIC_MONITORING_WARNING_STATE),
258 },
259 },
260 // LSAEB
261 {
262 toInt(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_ENABLED),
263 {
264 toInt(VehicleProperty::LOW_SPEED_AUTOMATIC_EMERGENCY_BRAKING_STATE),
265 },
266 },
267 };
268
269 // The list of VHAL properties that might be handled by an external power controller.
270 const std::unordered_set<int32_t> mPowerPropIds = {toInt(VehicleProperty::VEHICLE_IN_USE),
271 toInt(VehicleProperty::AP_POWER_BOOTUP_REASON)};
272
maybeGetGrpcServiceInfo(std::string * address)273 void maybeGetGrpcServiceInfo(std::string* address) {
274 std::ifstream ifs(GRPC_SERVICE_CONFIG_FILE);
275 if (!ifs) {
276 ALOGI("Cannot open grpc service config file at: %s, assume no service is available",
277 GRPC_SERVICE_CONFIG_FILE);
278 return;
279 }
280 ifs >> *address;
281 ifs.close();
282 }
283
vecToStringOfHexValues(const std::vector<int32_t> & vec)284 inline std::string vecToStringOfHexValues(const std::vector<int32_t>& vec) {
285 std::stringstream ss;
286 ss << "[";
287 for (size_t i = 0; i < vec.size(); i++) {
288 if (i != 0) {
289 ss << ",";
290 }
291 ss << std::showbase << std::hex << vec[i];
292 }
293 ss << "]";
294 return ss.str();
295 }
296
297 } // namespace
298
storePropInitialValue(const ConfigDeclaration & config)299 void FakeVehicleHardware::storePropInitialValue(const ConfigDeclaration& config) {
300 const VehiclePropConfig& vehiclePropConfig = config.config;
301 int propId = vehiclePropConfig.prop;
302
303 // A global property will have only a single area
304 bool globalProp = isGlobalProp(propId);
305 size_t numAreas = globalProp ? 1 : vehiclePropConfig.areaConfigs.size();
306
307 if (propId == toInt(VehicleProperty::HVAC_POWER_ON)) {
308 const auto& configArray = vehiclePropConfig.configArray;
309 hvacPowerDependentProps.insert(configArray.begin(), configArray.end());
310 }
311
312 for (size_t i = 0; i < numAreas; i++) {
313 int32_t curArea = globalProp ? 0 : vehiclePropConfig.areaConfigs[i].areaId;
314
315 // Create a separate instance for each individual zone
316 VehiclePropValue prop = {
317 .timestamp = elapsedRealtimeNano(),
318 .areaId = curArea,
319 .prop = propId,
320 .value = {},
321 };
322
323 if (config.initialAreaValues.empty()) {
324 if (config.initialValue == RawPropValues{}) {
325 // Skip empty initial values.
326 continue;
327 }
328 prop.value = config.initialValue;
329 } else if (auto valueForAreaIt = config.initialAreaValues.find(curArea);
330 valueForAreaIt != config.initialAreaValues.end()) {
331 prop.value = valueForAreaIt->second;
332 } else {
333 ALOGW("failed to get default value for prop 0x%x area 0x%x", propId, curArea);
334 continue;
335 }
336
337 auto result =
338 mServerSidePropStore->writeValue(mValuePool->obtain(prop), /*updateStatus=*/true);
339 if (!result.ok()) {
340 ALOGE("failed to write default config value, error: %s, status: %d",
341 getErrorMsg(result).c_str(), getIntErrorCode(result));
342 }
343 }
344 }
345
FakeVehicleHardware()346 FakeVehicleHardware::FakeVehicleHardware()
347 : FakeVehicleHardware(DEFAULT_CONFIG_DIR, OVERRIDE_CONFIG_DIR, false) {}
348
FakeVehicleHardware(std::string defaultConfigDir,std::string overrideConfigDir,bool forceOverride)349 FakeVehicleHardware::FakeVehicleHardware(std::string defaultConfigDir,
350 std::string overrideConfigDir, bool forceOverride)
351 : mValuePool(std::make_unique<VehiclePropValuePool>()),
352 mServerSidePropStore(new VehiclePropertyStore(mValuePool)),
353 mDefaultConfigDir(defaultConfigDir),
354 mOverrideConfigDir(overrideConfigDir),
355 mFakeObd2Frame(new obd2frame::FakeObd2Frame(mServerSidePropStore)),
356 mFakeUserHal(new FakeUserHal(mValuePool)),
357 mRecurrentTimer(new RecurrentTimer()),
358 mGeneratorHub(new GeneratorHub(
359 [this](const VehiclePropValue& value) { eventFromVehicleBus(value); })),
360 mPendingGetValueRequests(this),
361 mPendingSetValueRequests(this),
362 mForceOverride(forceOverride) {
363 init();
364 }
365
~FakeVehicleHardware()366 FakeVehicleHardware::~FakeVehicleHardware() {
367 mPendingGetValueRequests.stop();
368 mPendingSetValueRequests.stop();
369 mGeneratorHub.reset();
370 }
371
UseOverrideConfigDir()372 bool FakeVehicleHardware::UseOverrideConfigDir() {
373 return mForceOverride ||
374 android::base::GetBoolProperty(OVERRIDE_PROPERTY, /*default_value=*/false);
375 }
376
loadConfigDeclarations()377 std::unordered_map<int32_t, ConfigDeclaration> FakeVehicleHardware::loadConfigDeclarations() {
378 std::unordered_map<int32_t, ConfigDeclaration> configsByPropId;
379 bool defaultConfigLoaded = loadPropConfigsFromDir(mDefaultConfigDir, &configsByPropId);
380 if (!defaultConfigLoaded) {
381 // This cannot work without a valid default config.
382 ALOGE("Failed to load default config, exiting");
383 exit(1);
384 }
385 if (UseOverrideConfigDir()) {
386 loadPropConfigsFromDir(mOverrideConfigDir, &configsByPropId);
387 }
388 return configsByPropId;
389 }
390
init()391 void FakeVehicleHardware::init() {
392 maybeGetGrpcServiceInfo(&mPowerControllerServiceAddress);
393
394 for (auto& [_, configDeclaration] : loadConfigDeclarations()) {
395 VehiclePropConfig cfg = configDeclaration.config;
396 VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
397
398 if (cfg.prop == toInt(VehicleProperty::AP_POWER_STATE_REQ)) {
399 int config = GetIntProperty(POWER_STATE_REQ_CONFIG_PROPERTY, /*default_value=*/0);
400 cfg.configArray[0] = config;
401 } else if (cfg.prop == OBD2_FREEZE_FRAME) {
402 tokenFunction = [](const VehiclePropValue& propValue) { return propValue.timestamp; };
403 }
404
405 mServerSidePropStore->registerProperty(cfg, tokenFunction);
406 if (obd2frame::FakeObd2Frame::isDiagnosticProperty(cfg)) {
407 // Ignore storing default value for diagnostic property. They have special get/set
408 // logic.
409 continue;
410 }
411 storePropInitialValue(configDeclaration);
412 }
413
414 // OBD2_LIVE_FRAME and OBD2_FREEZE_FRAME must be configured in default configs.
415 auto maybeObd2LiveFrame = mServerSidePropStore->getPropConfig(OBD2_LIVE_FRAME);
416 if (maybeObd2LiveFrame.has_value()) {
417 mFakeObd2Frame->initObd2LiveFrame(maybeObd2LiveFrame.value());
418 }
419 auto maybeObd2FreezeFrame = mServerSidePropStore->getPropConfig(OBD2_FREEZE_FRAME);
420 if (maybeObd2FreezeFrame.has_value()) {
421 mFakeObd2Frame->initObd2FreezeFrame(maybeObd2FreezeFrame.value());
422 }
423
424 mServerSidePropStore->setOnValuesChangeCallback([this](std::vector<VehiclePropValue> values) {
425 return onValuesChangeCallback(std::move(values));
426 });
427 }
428
getAllPropertyConfigs() const429 std::vector<VehiclePropConfig> FakeVehicleHardware::getAllPropertyConfigs() const {
430 std::vector<VehiclePropConfig> allConfigs = mServerSidePropStore->getAllConfigs();
431 if (mAddExtraTestVendorConfigs) {
432 generateVendorConfigs(/* outAllConfigs= */ allConfigs);
433 }
434 return allConfigs;
435 }
436
createApPowerStateReq(VehicleApPowerStateReq state)437 VehiclePropValuePool::RecyclableType FakeVehicleHardware::createApPowerStateReq(
438 VehicleApPowerStateReq state) {
439 auto req = mValuePool->obtain(VehiclePropertyType::INT32_VEC, 2);
440 req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
441 req->areaId = 0;
442 req->timestamp = elapsedRealtimeNano();
443 req->status = VehiclePropertyStatus::AVAILABLE;
444 req->value.int32Values[0] = toInt(state);
445 // Param = 0.
446 req->value.int32Values[1] = 0;
447 return req;
448 }
449
createAdasStateReq(int32_t propertyId,int32_t areaId,int32_t state)450 VehiclePropValuePool::RecyclableType FakeVehicleHardware::createAdasStateReq(int32_t propertyId,
451 int32_t areaId,
452 int32_t state) {
453 auto req = mValuePool->obtain(VehiclePropertyType::INT32);
454 req->prop = propertyId;
455 req->areaId = areaId;
456 req->timestamp = elapsedRealtimeNano();
457 req->status = VehiclePropertyStatus::AVAILABLE;
458 req->value.int32Values[0] = state;
459 return req;
460 }
461
setApPowerStateReqShutdown(const VehiclePropValue & value)462 VhalResult<void> FakeVehicleHardware::setApPowerStateReqShutdown(const VehiclePropValue& value) {
463 if (value.value.int32Values.size() != 1) {
464 return StatusError(StatusCode::INVALID_ARG)
465 << "Failed to set SHUTDOWN_REQUEST, expect 1 int value: "
466 << "VehicleApPowerStateShutdownParam";
467 }
468 int powerStateShutdownParam = value.value.int32Values[0];
469 auto prop = createApPowerStateReq(VehicleApPowerStateReq::SHUTDOWN_PREPARE);
470 prop->value.int32Values[1] = powerStateShutdownParam;
471 if (auto writeResult = mServerSidePropStore->writeValue(
472 std::move(prop), /*updateStatus=*/true, VehiclePropertyStore::EventMode::ALWAYS);
473 !writeResult.ok()) {
474 return StatusError(getErrorCode(writeResult))
475 << "failed to write AP_POWER_STATE_REQ into property store, error: "
476 << getErrorMsg(writeResult);
477 }
478 return {};
479 }
480
setApPowerStateReport(const VehiclePropValue & value)481 VhalResult<void> FakeVehicleHardware::setApPowerStateReport(const VehiclePropValue& value) {
482 auto updatedValue = mValuePool->obtain(value);
483 updatedValue->timestamp = elapsedRealtimeNano();
484
485 if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
486 !writeResult.ok()) {
487 return StatusError(getErrorCode(writeResult))
488 << "failed to write value into property store, error: " << getErrorMsg(writeResult);
489 }
490
491 VehiclePropValuePool::RecyclableType prop;
492 int32_t state = value.value.int32Values[0];
493 switch (state) {
494 case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
495 [[fallthrough]];
496 case toInt(VehicleApPowerStateReport::HIBERNATION_EXIT):
497 [[fallthrough]];
498 case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
499 [[fallthrough]];
500 case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
501 // CPMS is in WAIT_FOR_VHAL state, simply move to ON and send back to HAL.
502 prop = createApPowerStateReq(VehicleApPowerStateReq::ON);
503
504 // ALWAYS update status for generated property value, and force a property update event
505 // because in the case when Car Service crashes, the power state would already be ON
506 // when we receive WAIT_FOR_VHAL and thus new property change event would be generated.
507 // However, Car Service always expect a property change event even though there is no
508 // actual state change.
509 if (auto writeResult =
510 mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true,
511 VehiclePropertyStore::EventMode::ALWAYS);
512 !writeResult.ok()) {
513 return StatusError(getErrorCode(writeResult))
514 << "failed to write AP_POWER_STATE_REQ into property store, error: "
515 << getErrorMsg(writeResult);
516 }
517 break;
518 case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
519 [[fallthrough]];
520 case toInt(VehicleApPowerStateReport::HIBERNATION_ENTRY):
521 [[fallthrough]];
522 case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
523 // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
524 // Send back to HAL
525 // ALWAYS update status for generated property value
526 prop = createApPowerStateReq(VehicleApPowerStateReq::FINISHED);
527 if (auto writeResult =
528 mServerSidePropStore->writeValue(std::move(prop), /*updateStatus=*/true);
529 !writeResult.ok()) {
530 return StatusError(getErrorCode(writeResult))
531 << "failed to write AP_POWER_STATE_REQ into property store, error: "
532 << getErrorMsg(writeResult);
533 }
534 break;
535 default:
536 ALOGE("Unknown VehicleApPowerStateReport: %d", state);
537 break;
538 }
539 return {};
540 }
541
getHvacTempNumIncrements(int requestedTemp,int minTemp,int maxTemp,int increment)542 int FakeVehicleHardware::getHvacTempNumIncrements(int requestedTemp, int minTemp, int maxTemp,
543 int increment) {
544 requestedTemp = std::max(requestedTemp, minTemp);
545 requestedTemp = std::min(requestedTemp, maxTemp);
546 int numIncrements = std::round((requestedTemp - minTemp) / static_cast<float>(increment));
547 return numIncrements;
548 }
549
updateHvacTemperatureValueSuggestionInput(const std::vector<int> & hvacTemperatureSetConfigArray,std::vector<float> * hvacTemperatureValueSuggestionInput)550 void FakeVehicleHardware::updateHvacTemperatureValueSuggestionInput(
551 const std::vector<int>& hvacTemperatureSetConfigArray,
552 std::vector<float>* hvacTemperatureValueSuggestionInput) {
553 int minTempInCelsius = hvacTemperatureSetConfigArray[0];
554 int maxTempInCelsius = hvacTemperatureSetConfigArray[1];
555 int incrementInCelsius = hvacTemperatureSetConfigArray[2];
556
557 int minTempInFahrenheit = hvacTemperatureSetConfigArray[3];
558 int maxTempInFahrenheit = hvacTemperatureSetConfigArray[4];
559 int incrementInFahrenheit = hvacTemperatureSetConfigArray[5];
560
561 // The HVAC_TEMPERATURE_SET config array values are temperature values that have been multiplied
562 // by 10 and converted to integers. Therefore, requestedTemp must also be multiplied by 10 and
563 // converted to an integer in order for them to be the same units.
564 int requestedTemp = static_cast<int>((*hvacTemperatureValueSuggestionInput)[0] * 10.0f);
565 int numIncrements =
566 (*hvacTemperatureValueSuggestionInput)[1] == toInt(VehicleUnit::CELSIUS)
567 ? getHvacTempNumIncrements(requestedTemp, minTempInCelsius, maxTempInCelsius,
568 incrementInCelsius)
569 : getHvacTempNumIncrements(requestedTemp, minTempInFahrenheit,
570 maxTempInFahrenheit, incrementInFahrenheit);
571
572 int suggestedTempInCelsius = minTempInCelsius + incrementInCelsius * numIncrements;
573 int suggestedTempInFahrenheit = minTempInFahrenheit + incrementInFahrenheit * numIncrements;
574 // HVAC_TEMPERATURE_VALUE_SUGGESTION specifies the temperature values to be in the original
575 // floating point form so we divide by 10 and convert to float.
576 (*hvacTemperatureValueSuggestionInput)[2] = static_cast<float>(suggestedTempInCelsius) / 10.0f;
577 (*hvacTemperatureValueSuggestionInput)[3] =
578 static_cast<float>(suggestedTempInFahrenheit) / 10.0f;
579 }
580
setHvacTemperatureValueSuggestion(const VehiclePropValue & hvacTemperatureValueSuggestion)581 VhalResult<void> FakeVehicleHardware::setHvacTemperatureValueSuggestion(
582 const VehiclePropValue& hvacTemperatureValueSuggestion) {
583 auto hvacTemperatureSetConfigResult =
584 mServerSidePropStore->getPropConfig(toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
585
586 if (!hvacTemperatureSetConfigResult.ok()) {
587 return StatusError(getErrorCode(hvacTemperatureSetConfigResult)) << StringPrintf(
588 "Failed to set HVAC_TEMPERATURE_VALUE_SUGGESTION because"
589 " HVAC_TEMPERATURE_SET could not be retrieved. Error: %s",
590 getErrorMsg(hvacTemperatureSetConfigResult).c_str());
591 }
592
593 const auto& originalInput = hvacTemperatureValueSuggestion.value.floatValues;
594 if (originalInput.size() != 4) {
595 return StatusError(StatusCode::INVALID_ARG) << StringPrintf(
596 "Failed to set HVAC_TEMPERATURE_VALUE_SUGGESTION because float"
597 " array value is not size 4.");
598 }
599
600 bool isTemperatureUnitSpecified = originalInput[1] == toInt(VehicleUnit::CELSIUS) ||
601 originalInput[1] == toInt(VehicleUnit::FAHRENHEIT);
602 if (!isTemperatureUnitSpecified) {
603 return StatusError(StatusCode::INVALID_ARG) << StringPrintf(
604 "Failed to set HVAC_TEMPERATURE_VALUE_SUGGESTION because float"
605 " value at index 1 is not any of %d or %d, which corresponds to"
606 " VehicleUnit#CELSIUS and VehicleUnit#FAHRENHEIT respectively.",
607 toInt(VehicleUnit::CELSIUS), toInt(VehicleUnit::FAHRENHEIT));
608 }
609
610 auto updatedValue = mValuePool->obtain(hvacTemperatureValueSuggestion);
611 const auto& hvacTemperatureSetConfigArray = hvacTemperatureSetConfigResult.value().configArray;
612 auto& hvacTemperatureValueSuggestionInput = updatedValue->value.floatValues;
613
614 updateHvacTemperatureValueSuggestionInput(hvacTemperatureSetConfigArray,
615 &hvacTemperatureValueSuggestionInput);
616
617 updatedValue->timestamp = elapsedRealtimeNano();
618 auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue),
619 /* updateStatus = */ true,
620 VehiclePropertyStore::EventMode::ALWAYS);
621 if (!writeResult.ok()) {
622 return StatusError(getErrorCode(writeResult))
623 << StringPrintf("failed to write value into property store, error: %s",
624 getErrorMsg(writeResult).c_str());
625 }
626
627 return {};
628 }
629
isHvacPropAndHvacNotAvailable(int32_t propId,int32_t areaId) const630 bool FakeVehicleHardware::isHvacPropAndHvacNotAvailable(int32_t propId, int32_t areaId) const {
631 if (hvacPowerDependentProps.count(propId)) {
632 auto hvacPowerOnResults =
633 mServerSidePropStore->readValuesForProperty(toInt(VehicleProperty::HVAC_POWER_ON));
634 if (!hvacPowerOnResults.ok()) {
635 ALOGW("failed to get HVAC_POWER_ON 0x%x, error: %s",
636 toInt(VehicleProperty::HVAC_POWER_ON), getErrorMsg(hvacPowerOnResults).c_str());
637 return false;
638 }
639 auto& hvacPowerOnValues = hvacPowerOnResults.value();
640 for (size_t j = 0; j < hvacPowerOnValues.size(); j++) {
641 auto hvacPowerOnValue = std::move(hvacPowerOnValues[j]);
642 if ((hvacPowerOnValue->areaId & areaId) == areaId) {
643 if (hvacPowerOnValue->value.int32Values.size() == 1 &&
644 hvacPowerOnValue->value.int32Values[0] == 0) {
645 return true;
646 }
647 break;
648 }
649 }
650 }
651 return false;
652 }
653
isAdasPropertyAvailable(int32_t adasStatePropertyId) const654 VhalResult<void> FakeVehicleHardware::isAdasPropertyAvailable(int32_t adasStatePropertyId) const {
655 auto adasStateResult = mServerSidePropStore->readValue(adasStatePropertyId);
656 if (!adasStateResult.ok()) {
657 ALOGW("Failed to get ADAS ENABLED property 0x%x, error: %s", adasStatePropertyId,
658 getErrorMsg(adasStateResult).c_str());
659 return {};
660 }
661
662 if (adasStateResult.value()->value.int32Values.size() == 1 &&
663 adasStateResult.value()->value.int32Values[0] < 0) {
664 auto errorState = adasStateResult.value()->value.int32Values[0];
665 switch (errorState) {
666 case toInt(ErrorState::NOT_AVAILABLE_DISABLED):
667 return StatusError(StatusCode::NOT_AVAILABLE_DISABLED)
668 << "ADAS feature is disabled.";
669 case toInt(ErrorState::NOT_AVAILABLE_SPEED_LOW):
670 return StatusError(StatusCode::NOT_AVAILABLE_SPEED_LOW)
671 << "ADAS feature is disabled because the vehicle speed is too low.";
672 case toInt(ErrorState::NOT_AVAILABLE_SPEED_HIGH):
673 return StatusError(StatusCode::NOT_AVAILABLE_SPEED_HIGH)
674 << "ADAS feature is disabled because the vehicle speed is too high.";
675 case toInt(ErrorState::NOT_AVAILABLE_POOR_VISIBILITY):
676 return StatusError(StatusCode::NOT_AVAILABLE_POOR_VISIBILITY)
677 << "ADAS feature is disabled because the visibility is too poor.";
678 case toInt(ErrorState::NOT_AVAILABLE_SAFETY):
679 return StatusError(StatusCode::NOT_AVAILABLE_SAFETY)
680 << "ADAS feature is disabled because of safety reasons.";
681 default:
682 return StatusError(StatusCode::NOT_AVAILABLE) << "ADAS feature is not available.";
683 }
684 }
685
686 return {};
687 }
688
setUserHalProp(const VehiclePropValue & value)689 VhalResult<void> FakeVehicleHardware::setUserHalProp(const VehiclePropValue& value) {
690 auto result = mFakeUserHal->onSetProperty(value);
691 if (!result.ok()) {
692 return StatusError(getErrorCode(result))
693 << "onSetProperty(): HAL returned error: " << getErrorMsg(result);
694 }
695 auto& updatedValue = result.value();
696 if (updatedValue != nullptr) {
697 ALOGI("onSetProperty(): updating property returned by HAL: %s",
698 updatedValue->toString().c_str());
699 // Update timestamp otherwise writeValue might fail because the timestamp is outdated.
700 updatedValue->timestamp = elapsedRealtimeNano();
701 if (auto writeResult = mServerSidePropStore->writeValue(
702 std::move(result.value()),
703 /*updateStatus=*/true, VehiclePropertyStore::EventMode::ALWAYS);
704 !writeResult.ok()) {
705 return StatusError(getErrorCode(writeResult))
706 << "failed to write value into property store, error: "
707 << getErrorMsg(writeResult);
708 }
709 }
710 return {};
711 }
712
synchronizeHvacTemp(int32_t hvacDualOnAreaId,std::optional<float> newTempC) const713 VhalResult<void> FakeVehicleHardware::synchronizeHvacTemp(int32_t hvacDualOnAreaId,
714 std::optional<float> newTempC) const {
715 auto hvacTemperatureSetResults = mServerSidePropStore->readValuesForProperty(
716 toInt(VehicleProperty::HVAC_TEMPERATURE_SET));
717 if (!hvacTemperatureSetResults.ok()) {
718 return StatusError(StatusCode::NOT_AVAILABLE)
719 << "Failed to get HVAC_TEMPERATURE_SET, error: "
720 << getErrorMsg(hvacTemperatureSetResults);
721 }
722 auto& hvacTemperatureSetValues = hvacTemperatureSetResults.value();
723 std::optional<float> tempCToSynchronize = newTempC;
724 for (size_t i = 0; i < hvacTemperatureSetValues.size(); i++) {
725 int32_t areaId = hvacTemperatureSetValues[i]->areaId;
726 if ((hvacDualOnAreaId & areaId) != areaId) {
727 continue;
728 }
729 if (hvacTemperatureSetValues[i]->status != VehiclePropertyStatus::AVAILABLE) {
730 continue;
731 }
732 // When HVAC_DUAL_ON is initially enabled, synchronize all area IDs
733 // to the temperature of the first area ID, which is the driver's.
734 if (!tempCToSynchronize.has_value()) {
735 tempCToSynchronize = hvacTemperatureSetValues[i]->value.floatValues[0];
736 continue;
737 }
738 auto updatedValue = std::move(hvacTemperatureSetValues[i]);
739 updatedValue->value.floatValues[0] = tempCToSynchronize.value();
740 updatedValue->timestamp = elapsedRealtimeNano();
741 // This will trigger a property change event for the current hvac property value.
742 auto writeResult =
743 mServerSidePropStore->writeValue(std::move(updatedValue), /*updateStatus=*/true,
744 VehiclePropertyStore::EventMode::ALWAYS);
745 if (!writeResult.ok()) {
746 return StatusError(getErrorCode(writeResult))
747 << "Failed to write value into property store, error: "
748 << getErrorMsg(writeResult);
749 }
750 }
751 return {};
752 }
753
getSyncedAreaIdIfHvacDualOn(int32_t hvacTemperatureSetAreaId) const754 std::optional<int32_t> FakeVehicleHardware::getSyncedAreaIdIfHvacDualOn(
755 int32_t hvacTemperatureSetAreaId) const {
756 auto hvacDualOnResults =
757 mServerSidePropStore->readValuesForProperty(toInt(VehicleProperty::HVAC_DUAL_ON));
758 if (!hvacDualOnResults.ok()) {
759 return std::nullopt;
760 }
761 auto& hvacDualOnValues = hvacDualOnResults.value();
762 for (size_t i = 0; i < hvacDualOnValues.size(); i++) {
763 if ((hvacDualOnValues[i]->areaId & hvacTemperatureSetAreaId) == hvacTemperatureSetAreaId &&
764 hvacDualOnValues[i]->value.int32Values.size() == 1 &&
765 hvacDualOnValues[i]->value.int32Values[0] == 1) {
766 return hvacDualOnValues[i]->areaId;
767 }
768 }
769 return std::nullopt;
770 }
771
getUserHalProp(const VehiclePropValue & value) const772 FakeVehicleHardware::ValueResultType FakeVehicleHardware::getUserHalProp(
773 const VehiclePropValue& value) const {
774 auto propId = value.prop;
775 ALOGI("get(): getting value for prop %s from User HAL", PROP_ID_TO_CSTR(propId));
776
777 auto result = mFakeUserHal->onGetProperty(value);
778 if (!result.ok()) {
779 return StatusError(getErrorCode(result))
780 << "get(): User HAL returned error: " << getErrorMsg(result);
781 } else {
782 auto& gotValue = result.value();
783 if (gotValue != nullptr) {
784 ALOGI("get(): User HAL returned value: %s", gotValue->toString().c_str());
785 gotValue->timestamp = elapsedRealtimeNano();
786 return result;
787 } else {
788 return StatusError(StatusCode::INTERNAL_ERROR) << "get(): User HAL returned null value";
789 }
790 }
791 }
792
isCruiseControlTypeStandard() const793 VhalResult<bool> FakeVehicleHardware::isCruiseControlTypeStandard() const {
794 auto isCruiseControlTypeAvailableResult =
795 isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_TYPE));
796 if (!isCruiseControlTypeAvailableResult.ok()) {
797 return isCruiseControlTypeAvailableResult.error();
798 }
799 auto cruiseControlTypeValue =
800 mServerSidePropStore->readValue(toInt(VehicleProperty::CRUISE_CONTROL_TYPE));
801 return cruiseControlTypeValue.value()->value.int32Values[0] ==
802 toInt(CruiseControlType::STANDARD);
803 }
804
maybeGetSpecialValue(const VehiclePropValue & value,bool * isSpecialValue) const805 FakeVehicleHardware::ValueResultType FakeVehicleHardware::maybeGetSpecialValue(
806 const VehiclePropValue& value, bool* isSpecialValue) const {
807 *isSpecialValue = false;
808 int32_t propId = value.prop;
809 ValueResultType result;
810
811 if (mPowerControllerServiceAddress != "") {
812 if (mPowerPropIds.find(propId) != mPowerPropIds.end()) {
813 *isSpecialValue = true;
814 return getPowerPropFromExternalService(propId);
815 }
816 }
817
818 if (propId >= STARTING_VENDOR_CODE_PROPERTIES_FOR_TEST &&
819 propId < ENDING_VENDOR_CODE_PROPERTIES_FOR_TEST) {
820 *isSpecialValue = true;
821 result = mValuePool->obtainInt32(/* value= */ 5);
822
823 result.value()->prop = propId;
824 result.value()->areaId = 0;
825 result.value()->timestamp = elapsedRealtimeNano();
826 return result;
827 }
828
829 if (mFakeUserHal->isSupported(propId)) {
830 *isSpecialValue = true;
831 return getUserHalProp(value);
832 }
833
834 if (isHvacPropAndHvacNotAvailable(propId, value.areaId)) {
835 *isSpecialValue = true;
836 return StatusError(StatusCode::NOT_AVAILABLE_DISABLED) << "hvac not available";
837 }
838
839 VhalResult<void> isAdasPropertyAvailableResult;
840 switch (propId) {
841 case OBD2_FREEZE_FRAME:
842 *isSpecialValue = true;
843 result = mFakeObd2Frame->getObd2FreezeFrame(value);
844 if (result.ok()) {
845 result.value()->timestamp = elapsedRealtimeNano();
846 }
847 return result;
848 case OBD2_FREEZE_FRAME_INFO:
849 *isSpecialValue = true;
850 result = mFakeObd2Frame->getObd2DtcInfo();
851 if (result.ok()) {
852 result.value()->timestamp = elapsedRealtimeNano();
853 }
854 return result;
855 case toInt(TestVendorProperty::ECHO_REVERSE_BYTES):
856 *isSpecialValue = true;
857 return getEchoReverseBytes(value);
858 case toInt(TestVendorProperty::VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING):
859 *isSpecialValue = true;
860 return StatusError((StatusCode)VENDOR_ERROR_CODE);
861 case toInt(VehicleProperty::CRUISE_CONTROL_TARGET_SPEED):
862 isAdasPropertyAvailableResult =
863 isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_STATE));
864 if (!isAdasPropertyAvailableResult.ok()) {
865 *isSpecialValue = true;
866 return isAdasPropertyAvailableResult.error();
867 }
868 return nullptr;
869 case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP):
870 [[fallthrough]];
871 case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_LEAD_VEHICLE_MEASURED_DISTANCE): {
872 isAdasPropertyAvailableResult =
873 isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_STATE));
874 if (!isAdasPropertyAvailableResult.ok()) {
875 *isSpecialValue = true;
876 return isAdasPropertyAvailableResult.error();
877 }
878 auto isCruiseControlTypeStandardResult = isCruiseControlTypeStandard();
879 if (!isCruiseControlTypeStandardResult.ok()) {
880 *isSpecialValue = true;
881 return isCruiseControlTypeStandardResult.error();
882 }
883 if (isCruiseControlTypeStandardResult.value()) {
884 *isSpecialValue = true;
885 return StatusError(StatusCode::NOT_AVAILABLE_DISABLED)
886 << "tried to get target time gap or lead vehicle measured distance value "
887 << "while on a standard CC setting";
888 }
889 return nullptr;
890 }
891 default:
892 // Do nothing.
893 break;
894 }
895
896 return nullptr;
897 }
898
getPowerPropFromExternalService(int32_t propId) const899 FakeVehicleHardware::ValueResultType FakeVehicleHardware::getPowerPropFromExternalService(
900 int32_t propId) const {
901 auto channel =
902 grpc::CreateChannel(mPowerControllerServiceAddress, grpc::InsecureChannelCredentials());
903 auto clientStub = PowerController::NewStub(channel);
904 switch (propId) {
905 case toInt(VehicleProperty::VEHICLE_IN_USE):
906 return getVehicleInUse(clientStub.get());
907 case toInt(VehicleProperty::AP_POWER_BOOTUP_REASON):
908 return getApPowerBootupReason(clientStub.get());
909 default:
910 return StatusError(StatusCode::INTERNAL_ERROR)
911 << "Unsupported power property ID: " << propId;
912 }
913 }
914
getVehicleInUse(PowerController::Stub * clientStub) const915 FakeVehicleHardware::ValueResultType FakeVehicleHardware::getVehicleInUse(
916 PowerController::Stub* clientStub) const {
917 IsVehicleInUseRequest request = {};
918 IsVehicleInUseResponse response = {};
919 grpc::ClientContext context;
920 auto status = clientStub->IsVehicleInUse(&context, request, &response);
921 if (!status.ok()) {
922 return StatusError(StatusCode::TRY_AGAIN) << "Cannot connect to GRPC service "
923 << ", error: " << status.error_message();
924 }
925 auto result = mValuePool->obtainBoolean(response.isvehicleinuse());
926 result->prop = toInt(VehicleProperty::VEHICLE_IN_USE);
927 result->areaId = 0;
928 result->status = VehiclePropertyStatus::AVAILABLE;
929 result->timestamp = elapsedRealtimeNano();
930 return result;
931 }
932
getApPowerBootupReason(PowerController::Stub * clientStub) const933 FakeVehicleHardware::ValueResultType FakeVehicleHardware::getApPowerBootupReason(
934 PowerController::Stub* clientStub) const {
935 GetApPowerBootupReasonRequest request = {};
936 GetApPowerBootupReasonResponse response = {};
937 grpc::ClientContext context;
938 auto status = clientStub->GetApPowerBootupReason(&context, request, &response);
939 if (!status.ok()) {
940 return StatusError(StatusCode::TRY_AGAIN) << "Cannot connect to GRPC service "
941 << ", error: " << status.error_message();
942 }
943 auto result = mValuePool->obtainInt32(response.bootupreason());
944 result->prop = toInt(VehicleProperty::AP_POWER_BOOTUP_REASON);
945 result->areaId = 0;
946 result->status = VehiclePropertyStatus::AVAILABLE;
947 result->timestamp = elapsedRealtimeNano();
948 return result;
949 }
950
getEchoReverseBytes(const VehiclePropValue & value) const951 FakeVehicleHardware::ValueResultType FakeVehicleHardware::getEchoReverseBytes(
952 const VehiclePropValue& value) const {
953 auto readResult = mServerSidePropStore->readValue(value);
954 if (!readResult.ok()) {
955 return readResult;
956 }
957 auto& gotValue = readResult.value();
958 gotValue->timestamp = elapsedRealtimeNano();
959 std::vector<uint8_t> byteValues = gotValue->value.byteValues;
960 size_t byteSize = byteValues.size();
961 for (size_t i = 0; i < byteSize; i++) {
962 gotValue->value.byteValues[i] = byteValues[byteSize - 1 - i];
963 }
964 return std::move(gotValue);
965 }
966
sendHvacPropertiesCurrentValues(int32_t areaId,int32_t hvacPowerOnVal)967 void FakeVehicleHardware::sendHvacPropertiesCurrentValues(int32_t areaId, int32_t hvacPowerOnVal) {
968 for (auto& powerPropId : hvacPowerDependentProps) {
969 auto powerPropResults = mServerSidePropStore->readValuesForProperty(powerPropId);
970 if (!powerPropResults.ok()) {
971 ALOGW("failed to get power prop 0x%x, error: %s", powerPropId,
972 getErrorMsg(powerPropResults).c_str());
973 continue;
974 }
975 auto& powerPropValues = powerPropResults.value();
976 for (size_t j = 0; j < powerPropValues.size(); j++) {
977 auto powerPropValue = std::move(powerPropValues[j]);
978 if ((powerPropValue->areaId & areaId) == powerPropValue->areaId) {
979 powerPropValue->status = hvacPowerOnVal ? VehiclePropertyStatus::AVAILABLE
980 : VehiclePropertyStatus::UNAVAILABLE;
981 powerPropValue->timestamp = elapsedRealtimeNano();
982 // This will trigger a property change event for the current hvac property value.
983 mServerSidePropStore->writeValue(std::move(powerPropValue), /*updateStatus=*/true,
984 VehiclePropertyStore::EventMode::ALWAYS);
985 }
986 }
987 }
988 }
989
sendAdasPropertiesState(int32_t propertyId,int32_t state)990 void FakeVehicleHardware::sendAdasPropertiesState(int32_t propertyId, int32_t state) {
991 auto& adasDependentPropIds = mAdasEnabledPropToAdasPropWithErrorState.find(propertyId)->second;
992 for (auto dependentPropId : adasDependentPropIds) {
993 auto dependentPropConfigResult = mServerSidePropStore->getPropConfig(dependentPropId);
994 if (!dependentPropConfigResult.ok()) {
995 ALOGW("Failed to get config for ADAS property 0x%x, error: %s", dependentPropId,
996 getErrorMsg(dependentPropConfigResult).c_str());
997 continue;
998 }
999 auto& dependentPropConfig = dependentPropConfigResult.value();
1000 for (auto& areaConfig : dependentPropConfig.areaConfigs) {
1001 int32_t hardcoded_state = state;
1002 // TODO: restore old/initial values here instead of hardcoded value (b/295542701)
1003 if (state == 1 && dependentPropId == toInt(VehicleProperty::CRUISE_CONTROL_TYPE)) {
1004 hardcoded_state = toInt(CruiseControlType::ADAPTIVE);
1005 }
1006 auto propValue =
1007 createAdasStateReq(dependentPropId, areaConfig.areaId, hardcoded_state);
1008 // This will trigger a property change event for the current ADAS property value.
1009 mServerSidePropStore->writeValue(std::move(propValue), /*updateStatus=*/true,
1010 VehiclePropertyStore::EventMode::ALWAYS);
1011 }
1012 }
1013 }
1014
maybeSetSpecialValue(const VehiclePropValue & value,bool * isSpecialValue)1015 VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
1016 bool* isSpecialValue) {
1017 *isSpecialValue = false;
1018 VehiclePropValuePool::RecyclableType updatedValue;
1019 int32_t propId = value.prop;
1020
1021 if (propId >= STARTING_VENDOR_CODE_PROPERTIES_FOR_TEST &&
1022 propId < ENDING_VENDOR_CODE_PROPERTIES_FOR_TEST) {
1023 *isSpecialValue = true;
1024 return {};
1025 }
1026
1027 if (mFakeUserHal->isSupported(propId)) {
1028 *isSpecialValue = true;
1029 return setUserHalProp(value);
1030 }
1031
1032 if (isHvacPropAndHvacNotAvailable(propId, value.areaId)) {
1033 *isSpecialValue = true;
1034 return StatusError(StatusCode::NOT_AVAILABLE_DISABLED) << "hvac not available";
1035 }
1036
1037 if (mAdasEnabledPropToAdasPropWithErrorState.count(propId) &&
1038 value.value.int32Values.size() == 1) {
1039 if (value.value.int32Values[0] == 1) {
1040 // Set default state to 1 when ADAS feature is enabled.
1041 sendAdasPropertiesState(propId, /* state = */ 1);
1042 } else {
1043 sendAdasPropertiesState(propId, toInt(ErrorState::NOT_AVAILABLE_DISABLED));
1044 }
1045 }
1046
1047 VhalResult<void> isAdasPropertyAvailableResult;
1048 VhalResult<bool> isCruiseControlTypeStandardResult;
1049 switch (propId) {
1050 case toInt(VehicleProperty::AP_POWER_STATE_REPORT):
1051 *isSpecialValue = true;
1052 return setApPowerStateReport(value);
1053 case toInt(VehicleProperty::SHUTDOWN_REQUEST):
1054 // If we receive SHUTDOWN_REQUEST, we should send this to an external component which
1055 // should shutdown Android system via sending an AP_POWER_STATE_REQ event. Here we have
1056 // no external components to notify, so we just send the event.
1057 *isSpecialValue = true;
1058 return setApPowerStateReqShutdown(value);
1059 case toInt(VehicleProperty::VEHICLE_MAP_SERVICE):
1060 // Placeholder for future implementation of VMS property in the default hal. For
1061 // now, just returns OK; otherwise, hal clients crash with property not supported.
1062 *isSpecialValue = true;
1063 return {};
1064 case OBD2_FREEZE_FRAME_CLEAR:
1065 *isSpecialValue = true;
1066 return mFakeObd2Frame->clearObd2FreezeFrames(value);
1067 case toInt(TestVendorProperty::VENDOR_PROPERTY_FOR_ERROR_CODE_TESTING):
1068 *isSpecialValue = true;
1069 return StatusError((StatusCode)VENDOR_ERROR_CODE);
1070 case toInt(VehicleProperty::HVAC_POWER_ON):
1071 if (value.value.int32Values.size() != 1) {
1072 *isSpecialValue = true;
1073 return StatusError(StatusCode::INVALID_ARG)
1074 << "HVAC_POWER_ON requires only one int32 value";
1075 }
1076 // When changing HVAC power state, send current hvac property values
1077 // through on change event.
1078 sendHvacPropertiesCurrentValues(value.areaId, value.value.int32Values[0]);
1079 return {};
1080 case toInt(VehicleProperty::HVAC_TEMPERATURE_VALUE_SUGGESTION):
1081 *isSpecialValue = true;
1082 return setHvacTemperatureValueSuggestion(value);
1083 case toInt(VehicleProperty::HVAC_TEMPERATURE_SET):
1084 if (value.value.floatValues.size() != 1) {
1085 *isSpecialValue = true;
1086 return StatusError(StatusCode::INVALID_ARG)
1087 << "HVAC_DUAL_ON requires only one float value";
1088 }
1089 if (auto hvacDualOnAreaId = getSyncedAreaIdIfHvacDualOn(value.areaId);
1090 hvacDualOnAreaId.has_value()) {
1091 *isSpecialValue = true;
1092 return synchronizeHvacTemp(hvacDualOnAreaId.value(), value.value.floatValues[0]);
1093 }
1094 return {};
1095 case toInt(VehicleProperty::HVAC_DUAL_ON):
1096 if (value.value.int32Values.size() != 1) {
1097 *isSpecialValue = true;
1098 return StatusError(StatusCode::INVALID_ARG)
1099 << "HVAC_DUAL_ON requires only one int32 value";
1100 }
1101 if (value.value.int32Values[0] == 1) {
1102 synchronizeHvacTemp(value.areaId, std::nullopt);
1103 }
1104 return {};
1105 case toInt(VehicleProperty::LANE_CENTERING_ASSIST_COMMAND): {
1106 isAdasPropertyAvailableResult =
1107 isAdasPropertyAvailable(toInt(VehicleProperty::LANE_CENTERING_ASSIST_STATE));
1108 if (!isAdasPropertyAvailableResult.ok()) {
1109 *isSpecialValue = true;
1110 }
1111 return isAdasPropertyAvailableResult;
1112 }
1113 case toInt(VehicleProperty::CRUISE_CONTROL_COMMAND):
1114 isAdasPropertyAvailableResult =
1115 isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_STATE));
1116 if (!isAdasPropertyAvailableResult.ok()) {
1117 *isSpecialValue = true;
1118 return isAdasPropertyAvailableResult;
1119 }
1120 isCruiseControlTypeStandardResult = isCruiseControlTypeStandard();
1121 if (!isCruiseControlTypeStandardResult.ok()) {
1122 *isSpecialValue = true;
1123 return isCruiseControlTypeStandardResult.error();
1124 }
1125 if (isCruiseControlTypeStandardResult.value() &&
1126 (value.value.int32Values[0] ==
1127 toInt(CruiseControlCommand::INCREASE_TARGET_TIME_GAP) ||
1128 value.value.int32Values[0] ==
1129 toInt(CruiseControlCommand::DECREASE_TARGET_TIME_GAP))) {
1130 *isSpecialValue = true;
1131 return StatusError(StatusCode::NOT_AVAILABLE_DISABLED)
1132 << "tried to use a change target time gap command while on a standard CC "
1133 << "setting";
1134 }
1135 return {};
1136 case toInt(VehicleProperty::ADAPTIVE_CRUISE_CONTROL_TARGET_TIME_GAP): {
1137 isAdasPropertyAvailableResult =
1138 isAdasPropertyAvailable(toInt(VehicleProperty::CRUISE_CONTROL_STATE));
1139 if (!isAdasPropertyAvailableResult.ok()) {
1140 *isSpecialValue = true;
1141 return isAdasPropertyAvailableResult;
1142 }
1143 isCruiseControlTypeStandardResult = isCruiseControlTypeStandard();
1144 if (!isCruiseControlTypeStandardResult.ok()) {
1145 *isSpecialValue = true;
1146 return isCruiseControlTypeStandardResult.error();
1147 }
1148 if (isCruiseControlTypeStandardResult.value()) {
1149 *isSpecialValue = true;
1150 return StatusError(StatusCode::NOT_AVAILABLE_DISABLED)
1151 << "tried to set target time gap or lead vehicle measured distance value "
1152 << "while on a standard CC setting";
1153 }
1154 return {};
1155 }
1156
1157 #ifdef ENABLE_VEHICLE_HAL_TEST_PROPERTIES
1158 case toInt(VehicleProperty::CLUSTER_REPORT_STATE):
1159 [[fallthrough]];
1160 case toInt(VehicleProperty::CLUSTER_REQUEST_DISPLAY):
1161 [[fallthrough]];
1162 case toInt(VehicleProperty::CLUSTER_NAVIGATION_STATE):
1163 [[fallthrough]];
1164 case toInt(TestVendorProperty::VENDOR_CLUSTER_SWITCH_UI):
1165 [[fallthrough]];
1166 case toInt(TestVendorProperty::VENDOR_CLUSTER_DISPLAY_STATE):
1167 *isSpecialValue = true;
1168 updatedValue = mValuePool->obtain(getPropType(value.prop));
1169 updatedValue->prop = value.prop & ~toInt(VehiclePropertyGroup::MASK);
1170 if (getPropGroup(value.prop) == VehiclePropertyGroup::SYSTEM) {
1171 updatedValue->prop |= toInt(VehiclePropertyGroup::VENDOR);
1172 } else {
1173 updatedValue->prop |= toInt(VehiclePropertyGroup::SYSTEM);
1174 }
1175 updatedValue->value = value.value;
1176 updatedValue->timestamp = elapsedRealtimeNano();
1177 updatedValue->areaId = value.areaId;
1178 if (auto writeResult = mServerSidePropStore->writeValue(std::move(updatedValue));
1179 !writeResult.ok()) {
1180 return StatusError(getErrorCode(writeResult))
1181 << "failed to write value into property store, error: "
1182 << getErrorMsg(writeResult);
1183 }
1184 return {};
1185 #endif // ENABLE_VEHICLE_HAL_TEST_PROPERTIES
1186
1187 default:
1188 break;
1189 }
1190 return {};
1191 }
1192
setValues(std::shared_ptr<const SetValuesCallback> callback,const std::vector<SetValueRequest> & requests)1193 StatusCode FakeVehicleHardware::setValues(std::shared_ptr<const SetValuesCallback> callback,
1194 const std::vector<SetValueRequest>& requests) {
1195 for (auto& request : requests) {
1196 if (FAKE_VEHICLEHARDWARE_DEBUG) {
1197 ALOGD("Set value for property ID: %s", PROP_ID_TO_CSTR(request.value.prop));
1198 }
1199
1200 // In a real VHAL implementation, you could either send the setValue request to vehicle bus
1201 // here in the binder thread, or you could send the request in setValue which runs in
1202 // the handler thread. If you decide to send the setValue request here, you should not
1203 // wait for the response here and the handler thread should handle the setValue response.
1204 mPendingSetValueRequests.addRequest(request, callback);
1205 }
1206
1207 return StatusCode::OK;
1208 }
1209
setValue(const VehiclePropValue & value)1210 VhalResult<void> FakeVehicleHardware::setValue(const VehiclePropValue& value) {
1211 // In a real VHAL implementation, this will send the request to vehicle bus if not already
1212 // sent in setValues, and wait for the response from vehicle bus.
1213 // Here we are just updating mValuePool.
1214 bool isSpecialValue = false;
1215 auto setSpecialValueResult = maybeSetSpecialValue(value, &isSpecialValue);
1216 if (isSpecialValue) {
1217 if (!setSpecialValueResult.ok()) {
1218 return StatusError(getErrorCode(setSpecialValueResult)) << StringPrintf(
1219 "failed to set special value for property ID: %s, error: %s",
1220 PROP_ID_TO_CSTR(value.prop), getErrorMsg(setSpecialValueResult).c_str());
1221 }
1222 return {};
1223 }
1224
1225 auto updatedValue = mValuePool->obtain(value);
1226
1227 auto writeResult = mServerSidePropStore->writeValue(
1228 std::move(updatedValue),
1229 /*updateStatus=*/false, /*mode=*/VehiclePropertyStore::EventMode::ON_VALUE_CHANGE,
1230 /*useCurrentTimestamp=*/true);
1231 if (!writeResult.ok()) {
1232 return StatusError(getErrorCode(writeResult))
1233 << StringPrintf("failed to write value into property store, error: %s",
1234 getErrorMsg(writeResult).c_str());
1235 }
1236
1237 return {};
1238 }
1239
handleSetValueRequest(const SetValueRequest & request)1240 SetValueResult FakeVehicleHardware::handleSetValueRequest(const SetValueRequest& request) {
1241 SetValueResult setValueResult;
1242 setValueResult.requestId = request.requestId;
1243
1244 if (auto result = setValue(request.value); !result.ok()) {
1245 ALOGE("failed to set value, error: %s, code: %d", getErrorMsg(result).c_str(),
1246 getIntErrorCode(result));
1247 setValueResult.status = getErrorCode(result);
1248 } else {
1249 setValueResult.status = StatusCode::OK;
1250 }
1251
1252 return setValueResult;
1253 }
1254
getValues(std::shared_ptr<const GetValuesCallback> callback,const std::vector<GetValueRequest> & requests) const1255 StatusCode FakeVehicleHardware::getValues(std::shared_ptr<const GetValuesCallback> callback,
1256 const std::vector<GetValueRequest>& requests) const {
1257 for (auto& request : requests) {
1258 if (FAKE_VEHICLEHARDWARE_DEBUG) {
1259 ALOGD("getValues(%s)", PROP_ID_TO_CSTR(request.prop.prop));
1260 }
1261
1262 // In a real VHAL implementation, you could either send the getValue request to vehicle bus
1263 // here in the binder thread, or you could send the request in getValue which runs in
1264 // the handler thread. If you decide to send the getValue request here, you should not
1265 // wait for the response here and the handler thread should handle the getValue response.
1266 mPendingGetValueRequests.addRequest(request, callback);
1267 }
1268
1269 return StatusCode::OK;
1270 }
1271
handleGetValueRequest(const GetValueRequest & request)1272 GetValueResult FakeVehicleHardware::handleGetValueRequest(const GetValueRequest& request) {
1273 GetValueResult getValueResult;
1274 getValueResult.requestId = request.requestId;
1275
1276 auto result = getValue(request.prop);
1277 if (!result.ok()) {
1278 ALOGE("failed to get value, error: %s, code: %d", getErrorMsg(result).c_str(),
1279 getIntErrorCode(result));
1280 getValueResult.status = getErrorCode(result);
1281 } else {
1282 getValueResult.status = StatusCode::OK;
1283 getValueResult.prop = *result.value();
1284 }
1285 return getValueResult;
1286 }
1287
getValue(const VehiclePropValue & value) const1288 FakeVehicleHardware::ValueResultType FakeVehicleHardware::getValue(
1289 const VehiclePropValue& value) const {
1290 // In a real VHAL implementation, this will send the request to vehicle bus if not already
1291 // sent in getValues, and wait for the response from vehicle bus.
1292 // Here we are just reading value from mValuePool.
1293 bool isSpecialValue = false;
1294 auto result = maybeGetSpecialValue(value, &isSpecialValue);
1295 if (isSpecialValue) {
1296 if (!result.ok()) {
1297 return StatusError(getErrorCode(result))
1298 << StringPrintf("failed to get special value: %s, error: %s",
1299 PROP_ID_TO_CSTR(value.prop), getErrorMsg(result).c_str());
1300 } else {
1301 return result;
1302 }
1303 }
1304
1305 auto readResult = mServerSidePropStore->readValue(value);
1306 if (!readResult.ok()) {
1307 StatusCode errorCode = getErrorCode(readResult);
1308 if (errorCode == StatusCode::NOT_AVAILABLE) {
1309 return StatusError(errorCode) << "value has not been set yet";
1310 } else {
1311 return StatusError(errorCode)
1312 << "failed to get value, error: " << getErrorMsg(readResult);
1313 }
1314 }
1315
1316 return readResult;
1317 }
1318
dump(const std::vector<std::string> & options)1319 DumpResult FakeVehicleHardware::dump(const std::vector<std::string>& options) {
1320 DumpResult result;
1321 result.callerShouldDumpState = false;
1322 if (options.size() == 0) {
1323 // We only want caller to dump default state when there is no options.
1324 result.callerShouldDumpState = true;
1325 result.buffer = dumpAllProperties();
1326 return result;
1327 }
1328 std::string option = options[0];
1329 if (EqualsIgnoreCase(option, "--help")) {
1330 result.buffer = dumpHelp();
1331 return result;
1332 } else if (EqualsIgnoreCase(option, "--list")) {
1333 result.buffer = dumpListProperties();
1334 } else if (EqualsIgnoreCase(option, "--get")) {
1335 result.buffer = dumpSpecificProperty(options);
1336 } else if (EqualsIgnoreCase(option, "--getWithArg")) {
1337 result.buffer = dumpGetPropertyWithArg(options);
1338 } else if (EqualsIgnoreCase(option, "--set")) {
1339 result.buffer = dumpSetProperties(options);
1340 } else if (EqualsIgnoreCase(option, "--save-prop")) {
1341 result.buffer = dumpSaveProperty(options);
1342 } else if (EqualsIgnoreCase(option, "--restore-prop")) {
1343 result.buffer = dumpRestoreProperty(options);
1344 } else if (EqualsIgnoreCase(option, "--inject-event")) {
1345 result.buffer = dumpInjectEvent(options);
1346 } else if (EqualsIgnoreCase(option, kUserHalDumpOption)) {
1347 result.buffer = mFakeUserHal->dump();
1348 } else if (EqualsIgnoreCase(option, "--genfakedata")) {
1349 result.buffer = genFakeDataCommand(options);
1350 } else if (EqualsIgnoreCase(option, "--genTestVendorConfigs")) {
1351 mAddExtraTestVendorConfigs = true;
1352 result.refreshPropertyConfigs = true;
1353 result.buffer = "successfully generated vendor configs";
1354 } else if (EqualsIgnoreCase(option, "--restoreVendorConfigs")) {
1355 mAddExtraTestVendorConfigs = false;
1356 result.refreshPropertyConfigs = true;
1357 result.buffer = "successfully restored vendor configs";
1358 } else if (EqualsIgnoreCase(option, "--dumpSub")) {
1359 result.buffer = dumpSubscriptions();
1360 } else {
1361 result.buffer = StringPrintf("Invalid option: %s\n", option.c_str());
1362 }
1363 return result;
1364 }
1365
genFakeDataHelp()1366 std::string FakeVehicleHardware::genFakeDataHelp() {
1367 return R"(
1368 Generate Fake Data Usage:
1369 --genfakedata --startlinear [propID] [mValue] [cValue] [dispersion] [increment] [interval]: "
1370 Start a linear generator that generates event with floatValue within range:
1371 [mValue - disperson, mValue + dispersion].
1372 propID(int32): ID for the property to generate event for.
1373 mValue(float): The middle of the possible values for the property.
1374 cValue(float): The start value for the property, must be within the range.
1375 dispersion(float): The range the value can change.
1376 increment(float): The step the value would increase by for each generated event,
1377 if exceed the range, the value would loop back.
1378 interval(int64): The interval in nanoseconds the event would generate by.
1379
1380 --genfakedata --stoplinear [propID(int32)]: Stop a linear generator
1381
1382 --genfakedata --startjson --path [jsonFilePath] [repetition]:
1383 Start a JSON generator that would generate events according to a JSON file.
1384 jsonFilePath(string): The path to a JSON file. The JSON content must be in the format of
1385 [{
1386 "timestamp": 1000000,
1387 "areaId": 0,
1388 "value": 8,
1389 "prop": 289408000
1390 }, {...}]
1391 Each event in the JSON file would be generated by the same interval their timestamp is relative to
1392 the first event's timestamp.
1393 repetition(int32, optional): how many iterations the events would be generated. If it is not
1394 provided, it would iterate indefinitely.
1395
1396 --genfakedata --startjson --content [jsonContent]: Start a JSON generator using the content.
1397
1398 --genfakedata --stopjson [generatorID(string)]: Stop a JSON generator.
1399
1400 --genfakedata --keypress [keyCode(int32)] [display[int32]]: Generate key press.
1401
1402 --genfakedata --keyinputv2 [area(int32)] [display(int32)] [keyCode[int32]] [action[int32]]
1403 [repeatCount(int32)]
1404
1405 --genfakedata --motioninput [area(int32)] [display(int32)] [inputType[int32]] [action[int32]]
1406 [buttonState(int32)] --pointer [pointerId(int32)] [toolType(int32)] [xData(float)] [yData(float)]
1407 [pressure(float)] [size(float)]
1408 Generate a motion input event. --pointer option can be specified multiple times.
1409
1410 --genTestVendorConfigs: Generates fake VehiclePropConfig ranging from 0x5000 to 0x8000 all with
1411 vendor property group, global vehicle area, and int32 vehicle property type. This is mainly used
1412 for testing
1413
1414 --restoreVendorConfigs: Restores to to the default state if genTestVendorConfigs was used.
1415 Otherwise this will do nothing.
1416
1417 )";
1418 }
1419
1420 std::string FakeVehicleHardware::parseErrMsg(std::string fieldName, std::string value,
1421 std::string type) {
1422 return StringPrintf("failed to parse %s as %s: \"%s\"\n%s", fieldName.c_str(), type.c_str(),
1423 value.c_str(), genFakeDataHelp().c_str());
1424 }
1425
1426 void FakeVehicleHardware::generateVendorConfigs(
1427 std::vector<VehiclePropConfig>& outAllConfigs) const {
1428 for (int i = STARTING_VENDOR_CODE_PROPERTIES_FOR_TEST;
1429 i < ENDING_VENDOR_CODE_PROPERTIES_FOR_TEST; i++) {
1430 VehiclePropConfig config;
1431 config.prop = i;
1432 config.access = VehiclePropertyAccess::READ_WRITE;
1433 outAllConfigs.push_back(config);
1434 }
1435 }
1436
1437 std::string FakeVehicleHardware::genFakeDataCommand(const std::vector<std::string>& options) {
1438 if (options.size() < 2) {
1439 return "No subcommand specified for genfakedata\n" + genFakeDataHelp();
1440 }
1441
1442 std::string command = options[1];
1443 if (command == "--startlinear") {
1444 // --genfakedata --startlinear [propID(int32)] [middleValue(float)]
1445 // [currentValue(float)] [dispersion(float)] [increment(float)] [interval(int64)]
1446 if (options.size() != 8) {
1447 return "incorrect argument count, need 8 arguments for --genfakedata --startlinear\n" +
1448 genFakeDataHelp();
1449 }
1450 int32_t propId;
1451 float middleValue;
1452 float currentValue;
1453 float dispersion;
1454 float increment;
1455 int64_t interval;
1456 if (!android::base::ParseInt(options[2], &propId)) {
1457 return parseErrMsg("propId", options[2], "int");
1458 }
1459 if (!android::base::ParseFloat(options[3], &middleValue)) {
1460 return parseErrMsg("middleValue", options[3], "float");
1461 }
1462 if (!android::base::ParseFloat(options[4], ¤tValue)) {
1463 return parseErrMsg("currentValue", options[4], "float");
1464 }
1465 if (!android::base::ParseFloat(options[5], &dispersion)) {
1466 return parseErrMsg("dispersion", options[5], "float");
1467 }
1468 if (!android::base::ParseFloat(options[6], &increment)) {
1469 return parseErrMsg("increment", options[6], "float");
1470 }
1471 if (!android::base::ParseInt(options[7], &interval)) {
1472 return parseErrMsg("interval", options[7], "int");
1473 }
1474 auto generator = std::make_unique<LinearFakeValueGenerator>(
1475 propId, middleValue, currentValue, dispersion, increment, interval);
1476 mGeneratorHub->registerGenerator(propId, std::move(generator));
1477 return "Linear event generator started successfully";
1478 } else if (command == "--stoplinear") {
1479 // --genfakedata --stoplinear [propID(int32)]
1480 if (options.size() != 3) {
1481 return "incorrect argument count, need 3 arguments for --genfakedata --stoplinear\n" +
1482 genFakeDataHelp();
1483 }
1484 int32_t propId;
1485 if (!android::base::ParseInt(options[2], &propId)) {
1486 return parseErrMsg("propId", options[2], "int");
1487 }
1488 if (mGeneratorHub->unregisterGenerator(propId)) {
1489 return "Linear event generator stopped successfully";
1490 }
1491 return StringPrintf("No linear event generator found for property: %s",
1492 PROP_ID_TO_CSTR(propId));
1493 } else if (command == "--startjson") {
1494 // --genfakedata --startjson --path path repetition
1495 // or
1496 // --genfakedata --startjson --content content repetition.
1497 if (options.size() != 4 && options.size() != 5) {
1498 return "incorrect argument count, need 4 or 5 arguments for --genfakedata "
1499 "--startjson\n";
1500 }
1501 // Iterate infinitely if repetition number is not provided
1502 int32_t repetition = -1;
1503 if (options.size() == 5) {
1504 if (!android::base::ParseInt(options[4], &repetition)) {
1505 return parseErrMsg("repetition", options[4], "int");
1506 }
1507 }
1508 std::unique_ptr<JsonFakeValueGenerator> generator;
1509 if (options[2] == "--path") {
1510 const std::string& fileName = options[3];
1511 generator = std::make_unique<JsonFakeValueGenerator>(fileName, repetition);
1512 if (!generator->hasNext()) {
1513 return "invalid JSON file, no events";
1514 }
1515 } else if (options[2] == "--content") {
1516 const std::string& content = options[3];
1517 generator =
1518 std::make_unique<JsonFakeValueGenerator>(/*unused=*/true, content, repetition);
1519 if (!generator->hasNext()) {
1520 return "invalid JSON content, no events";
1521 }
1522 }
1523 int32_t cookie = std::hash<std::string>()(options[3]);
1524 mGeneratorHub->registerGenerator(cookie, std::move(generator));
1525 return StringPrintf("JSON event generator started successfully, ID: %" PRId32, cookie);
1526 } else if (command == "--stopjson") {
1527 // --genfakedata --stopjson [generatorID(string)]
1528 if (options.size() != 3) {
1529 return "incorrect argument count, need 3 arguments for --genfakedata --stopjson\n";
1530 }
1531 int32_t cookie;
1532 if (!android::base::ParseInt(options[2], &cookie)) {
1533 return parseErrMsg("cookie", options[2], "int");
1534 }
1535 if (mGeneratorHub->unregisterGenerator(cookie)) {
1536 return "JSON event generator stopped successfully";
1537 } else {
1538 return StringPrintf("No JSON event generator found for ID: %s", options[2].c_str());
1539 }
1540 } else if (command == "--keypress") {
1541 int32_t keyCode;
1542 int32_t display;
1543 // --genfakedata --keypress [keyCode(int32)] [display[int32]]
1544 if (options.size() != 4) {
1545 return "incorrect argument count, need 4 arguments for --genfakedata --keypress\n";
1546 }
1547 if (!android::base::ParseInt(options[2], &keyCode)) {
1548 return parseErrMsg("keyCode", options[2], "int");
1549 }
1550 if (!android::base::ParseInt(options[3], &display)) {
1551 return parseErrMsg("display", options[3], "int");
1552 }
1553 // Send back to HAL
1554 onValueChangeCallback(
1555 createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
1556 onValueChangeCallback(
1557 createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
1558 return "keypress event generated successfully";
1559 } else if (command == "--keyinputv2") {
1560 int32_t area;
1561 int32_t display;
1562 int32_t keyCode;
1563 int32_t action;
1564 int32_t repeatCount;
1565 // --genfakedata --keyinputv2 [area(int32)] [display(int32)] [keyCode[int32]]
1566 // [action[int32]] [repeatCount(int32)]
1567 if (options.size() != 7) {
1568 return "incorrect argument count, need 7 arguments for --genfakedata --keyinputv2\n";
1569 }
1570 if (!android::base::ParseInt(options[2], &area)) {
1571 return parseErrMsg("area", options[2], "int");
1572 }
1573 if (!android::base::ParseInt(options[3], &display)) {
1574 return parseErrMsg("display", options[3], "int");
1575 }
1576 if (!android::base::ParseInt(options[4], &keyCode)) {
1577 return parseErrMsg("keyCode", options[4], "int");
1578 }
1579 if (!android::base::ParseInt(options[5], &action)) {
1580 return parseErrMsg("action", options[5], "int");
1581 }
1582 if (!android::base::ParseInt(options[6], &repeatCount)) {
1583 return parseErrMsg("repeatCount", options[6], "int");
1584 }
1585 // Send back to HAL
1586 onValueChangeCallback(createHwKeyInputV2Prop(area, display, keyCode, action, repeatCount));
1587 return StringPrintf(
1588 "keyinputv2 event generated successfully with area:%d, display:%d,"
1589 " keyCode:%d, action:%d, repeatCount:%d",
1590 area, display, keyCode, action, repeatCount);
1591
1592 } else if (command == "--motioninput") {
1593 int32_t area;
1594 int32_t display;
1595 int32_t inputType;
1596 int32_t action;
1597 int32_t buttonState;
1598 int32_t pointerCount;
1599
1600 // --genfakedata --motioninput [area(int32)] [display(int32)] [inputType[int32]]
1601 // [action[int32]] [buttonState(int32)] [pointerCount(int32)]
1602 // --pointer [pointerId(int32)] [toolType(int32)] [xData(float)] [yData(float)]
1603 // [pressure(float)] [size(float)]
1604 int optionsSize = (int)options.size();
1605 if (optionsSize / 7 < 2) {
1606 return "incorrect argument count, need at least 14 arguments for --genfakedata "
1607 "--motioninput including at least 1 --pointer\n";
1608 }
1609
1610 if (optionsSize % 7 != 0) {
1611 return "incorrect argument count, need 6 arguments for every --pointer\n";
1612 }
1613 pointerCount = (int)optionsSize / 7 - 1;
1614
1615 if (!android::base::ParseInt(options[2], &area)) {
1616 return parseErrMsg("area", options[2], "int");
1617 }
1618 if (!android::base::ParseInt(options[3], &display)) {
1619 return parseErrMsg("display", options[3], "int");
1620 }
1621 if (!android::base::ParseInt(options[4], &inputType)) {
1622 return parseErrMsg("inputType", options[4], "int");
1623 }
1624 if (!android::base::ParseInt(options[5], &action)) {
1625 return parseErrMsg("action", options[5], "int");
1626 }
1627 if (!android::base::ParseInt(options[6], &buttonState)) {
1628 return parseErrMsg("buttonState", options[6], "int");
1629 }
1630
1631 int32_t pointerId[pointerCount];
1632 int32_t toolType[pointerCount];
1633 float xData[pointerCount];
1634 float yData[pointerCount];
1635 float pressure[pointerCount];
1636 float size[pointerCount];
1637
1638 for (int i = 7, pc = 0; i < optionsSize; i += 7, pc += 1) {
1639 int offset = i;
1640 if (options[offset] != "--pointer") {
1641 return "--pointer is needed for the motion input\n";
1642 }
1643 offset += 1;
1644 if (!android::base::ParseInt(options[offset], &pointerId[pc])) {
1645 return parseErrMsg("pointerId", options[offset], "int");
1646 }
1647 offset += 1;
1648 if (!android::base::ParseInt(options[offset], &toolType[pc])) {
1649 return parseErrMsg("toolType", options[offset], "int");
1650 }
1651 offset += 1;
1652 if (!android::base::ParseFloat(options[offset], &xData[pc])) {
1653 return parseErrMsg("xData", options[offset], "float");
1654 }
1655 offset += 1;
1656 if (!android::base::ParseFloat(options[offset], &yData[pc])) {
1657 return parseErrMsg("yData", options[offset], "float");
1658 }
1659 offset += 1;
1660 if (!android::base::ParseFloat(options[offset], &pressure[pc])) {
1661 return parseErrMsg("pressure", options[offset], "float");
1662 }
1663 offset += 1;
1664 if (!android::base::ParseFloat(options[offset], &size[pc])) {
1665 return parseErrMsg("size", options[offset], "float");
1666 }
1667 }
1668
1669 // Send back to HAL
1670 onValueChangeCallback(createHwMotionInputProp(area, display, inputType, action, buttonState,
1671 pointerCount, pointerId, toolType, xData,
1672 yData, pressure, size));
1673
1674 std::string successMessage = StringPrintf(
1675 "motion event generated successfully with area:%d, display:%d,"
1676 " inputType:%d, action:%d, buttonState:%d, pointerCount:%d\n",
1677 area, display, inputType, action, buttonState, pointerCount);
1678 for (int i = 0; i < pointerCount; i++) {
1679 successMessage += StringPrintf(
1680 "Pointer #%d {\n"
1681 " id:%d , tooltype:%d \n"
1682 " x:%f , y:%f\n"
1683 " pressure: %f, data: %f\n"
1684 "}\n",
1685 i, pointerId[i], toolType[i], xData[i], yData[i], pressure[i], size[i]);
1686 }
1687 return successMessage;
1688 }
1689
1690 return StringPrintf("Unknown command: \"%s\"\n%s", command.c_str(), genFakeDataHelp().c_str());
1691 }
1692
1693 VehiclePropValue FakeVehicleHardware::createHwInputKeyProp(VehicleHwKeyInputAction action,
1694 int32_t keyCode, int32_t targetDisplay) {
1695 VehiclePropValue value = {
1696 .timestamp = elapsedRealtimeNano(),
1697 .areaId = 0,
1698 .prop = toInt(VehicleProperty::HW_KEY_INPUT),
1699 .status = VehiclePropertyStatus::AVAILABLE,
1700 .value.int32Values = {toInt(action), keyCode, targetDisplay},
1701 };
1702 return value;
1703 }
1704
1705 VehiclePropValue FakeVehicleHardware::createHwKeyInputV2Prop(int32_t area, int32_t targetDisplay,
1706 int32_t keyCode, int32_t action,
1707 int32_t repeatCount) {
1708 VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
1709 .areaId = area,
1710 .prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
1711 .status = VehiclePropertyStatus::AVAILABLE,
1712 .value.int32Values = {targetDisplay, keyCode, action, repeatCount},
1713 .value.int64Values = {elapsedRealtimeNano()}};
1714 return value;
1715 }
1716
1717 VehiclePropValue FakeVehicleHardware::createHwMotionInputProp(
1718 int32_t area, int32_t display, int32_t inputType, int32_t action, int32_t buttonState,
1719 int32_t pointerCount, int32_t pointerId[], int32_t toolType[], float xData[], float yData[],
1720 float pressure[], float size[]) {
1721 std::vector<int> intValues;
1722 intValues.push_back(display);
1723 intValues.push_back(inputType);
1724 intValues.push_back(action);
1725 intValues.push_back(buttonState);
1726 intValues.push_back(pointerCount);
1727 for (int i = 0; i < pointerCount; i++) {
1728 intValues.push_back(pointerId[i]);
1729 }
1730 for (int i = 0; i < pointerCount; i++) {
1731 intValues.push_back(toolType[i]);
1732 }
1733
1734 std::vector<float> floatValues;
1735 for (int i = 0; i < pointerCount; i++) {
1736 floatValues.push_back(xData[i]);
1737 }
1738 for (int i = 0; i < pointerCount; i++) {
1739 floatValues.push_back(yData[i]);
1740 }
1741 for (int i = 0; i < pointerCount; i++) {
1742 floatValues.push_back(pressure[i]);
1743 }
1744 for (int i = 0; i < pointerCount; i++) {
1745 floatValues.push_back(size[i]);
1746 }
1747
1748 VehiclePropValue value = {.timestamp = elapsedRealtimeNano(),
1749 .areaId = area,
1750 .prop = toInt(VehicleProperty::HW_MOTION_INPUT),
1751 .status = VehiclePropertyStatus::AVAILABLE,
1752 .value.int32Values = intValues,
1753 .value.floatValues = floatValues,
1754 .value.int64Values = {elapsedRealtimeNano()}};
1755 return value;
1756 }
1757
1758 void FakeVehicleHardware::eventFromVehicleBus(const VehiclePropValue& value) {
1759 mServerSidePropStore->writeValue(mValuePool->obtain(value));
1760 }
1761
1762 std::string FakeVehicleHardware::dumpSubscriptions() {
1763 std::scoped_lock<std::mutex> lockGuard(mLock);
1764 std::string result = "Subscriptions: \n";
1765 for (const auto& [interval, actionForInterval] : mActionByIntervalInNanos) {
1766 for (const auto& propIdAreaId : actionForInterval.propIdAreaIdsToRefresh) {
1767 const auto& refreshInfo = mRefreshInfoByPropIdAreaId[propIdAreaId];
1768 bool vur = (refreshInfo.eventMode == VehiclePropertyStore::EventMode::ON_VALUE_CHANGE);
1769 float sampleRateHz = 1'000'000'000. / refreshInfo.intervalInNanos;
1770 result += StringPrintf("Continuous{property: %s, areaId: %d, rate: %lf hz, vur: %b}\n",
1771 PROP_ID_TO_CSTR(propIdAreaId.propId), propIdAreaId.areaId,
1772 sampleRateHz, vur);
1773 }
1774 }
1775 for (const auto& propIdAreaId : mSubOnChangePropIdAreaIds) {
1776 result += StringPrintf("OnChange{property: %s, areaId: %d}\n",
1777 PROP_ID_TO_CSTR(propIdAreaId.propId), propIdAreaId.areaId);
1778 }
1779 return result;
1780 }
1781
dumpHelp()1782 std::string FakeVehicleHardware::dumpHelp() {
1783 return "Usage: \n\n"
1784 "[no args]: dumps (id and value) all supported properties \n"
1785 "--help: shows this help\n"
1786 "--list: lists the property IDs and their supported area IDs for all supported "
1787 "properties\n"
1788 "--get <PROP_ID_1> [PROP_ID_2] [PROP_ID_N]: dumps the value of specific properties. \n"
1789 "--getWithArg <PROP_ID> [ValueArguments]: gets the value for a specific property. "
1790 "The value arguments constructs a VehiclePropValue used in the getValue request. \n"
1791 "--set <PROP_ID> [ValueArguments]: sets the value of property PROP_ID, the value "
1792 "arguments constructs a VehiclePropValue used in the setValue request. \n"
1793 "--save-prop <PROP_ID> [-a AREA_ID]: saves the current value for PROP_ID, integration "
1794 "tests that modify prop value must call this before test and restore-prop after test. \n"
1795 "--restore-prop <PROP_ID> [-a AREA_ID]: restores a previously saved property value. \n"
1796 "--inject-event <PROP_ID> [ValueArguments]: inject a property update event from car\n\n"
1797 "ValueArguments are in the format of [-a OPTIONAL_AREA_ID] "
1798 "[-i INT_VALUE_1 [INT_VALUE_2 ...]] "
1799 "[-i64 INT64_VALUE_1 [INT64_VALUE_2 ...]] "
1800 "[-f FLOAT_VALUE_1 [FLOAT_VALUE_2 ...]] "
1801 "[-s STR_VALUE] "
1802 "[-b BYTES_VALUE].\n"
1803 "For example: to set property ID 0x1234, areaId 0x1 to int32 values: [1, 2, 3], "
1804 "use \"--set 0x1234 -a 0x1 -i 1 2 3\"\n"
1805 "Note that the string, bytes and area value can be set just once, while the other can"
1806 " have multiple values (so they're used in the respective array), "
1807 "BYTES_VALUE is in the form of 0xXXXX, e.g. 0xdeadbeef.\n" +
1808 genFakeDataHelp() + "Fake user HAL usage: \n" + mFakeUserHal->showDumpHelp();
1809 }
1810
dumpAllProperties()1811 std::string FakeVehicleHardware::dumpAllProperties() {
1812 auto configs = mServerSidePropStore->getAllConfigs();
1813 if (configs.size() == 0) {
1814 return "no properties to dump\n";
1815 }
1816 std::string msg = StringPrintf("dumping %zu properties\n", configs.size());
1817 int rowNumber = 1;
1818 for (const VehiclePropConfig& config : configs) {
1819 msg += dumpOnePropertyByConfig(rowNumber++, config);
1820 }
1821 return msg;
1822 }
1823
dumpOnePropertyByConfig(int rowNumber,const VehiclePropConfig & config)1824 std::string FakeVehicleHardware::dumpOnePropertyByConfig(int rowNumber,
1825 const VehiclePropConfig& config) {
1826 size_t numberAreas = config.areaConfigs.size();
1827 std::string msg = "";
1828 if (numberAreas == 0) {
1829 msg += StringPrintf("%d: ", rowNumber);
1830 msg += dumpOnePropertyById(config.prop, /* areaId= */ 0);
1831 return msg;
1832 }
1833 for (size_t j = 0; j < numberAreas; ++j) {
1834 if (numberAreas > 1) {
1835 msg += StringPrintf("%d-%zu: ", rowNumber, j);
1836 } else {
1837 msg += StringPrintf("%d: ", rowNumber);
1838 }
1839 msg += dumpOnePropertyById(config.prop, config.areaConfigs[j].areaId);
1840 }
1841 return msg;
1842 }
1843
dumpOnePropertyById(int32_t propId,int32_t areaId)1844 std::string FakeVehicleHardware::dumpOnePropertyById(int32_t propId, int32_t areaId) {
1845 VehiclePropValue value = {
1846 .areaId = areaId,
1847 .prop = propId,
1848 .value = {},
1849 };
1850 bool isSpecialValue = false;
1851 auto result = maybeGetSpecialValue(value, &isSpecialValue);
1852 if (!isSpecialValue) {
1853 result = mServerSidePropStore->readValue(value);
1854 }
1855 if (!result.ok()) {
1856 return StringPrintf("failed to read property value: %s, error: %s, code: %d\n",
1857 PROP_ID_TO_CSTR(propId), getErrorMsg(result).c_str(),
1858 getIntErrorCode(result));
1859
1860 } else {
1861 return result.value()->toString() + "\n";
1862 }
1863 }
1864
dumpListProperties()1865 std::string FakeVehicleHardware::dumpListProperties() {
1866 auto configs = mServerSidePropStore->getAllConfigs();
1867 if (configs.size() == 0) {
1868 return "no properties to list\n";
1869 }
1870 int rowNumber = 1;
1871 std::stringstream ss;
1872 ss << "listing " << configs.size() << " properties" << std::endl;
1873 for (const auto& config : configs) {
1874 std::vector<int32_t> areaIds;
1875 for (const auto& areaConfig : config.areaConfigs) {
1876 areaIds.push_back(areaConfig.areaId);
1877 }
1878 ss << rowNumber++ << ": " << PROP_ID_TO_CSTR(config.prop) << ", propID: " << std::showbase
1879 << std::hex << config.prop << std::noshowbase << std::dec
1880 << ", areaIDs: " << vecToStringOfHexValues(areaIds) << std::endl;
1881 }
1882 return ss.str();
1883 }
1884
checkArgumentsSize(const std::vector<std::string> & options,size_t minSize)1885 Result<void> FakeVehicleHardware::checkArgumentsSize(const std::vector<std::string>& options,
1886 size_t minSize) {
1887 size_t size = options.size();
1888 if (size >= minSize) {
1889 return {};
1890 }
1891 return Error() << StringPrintf("Invalid number of arguments: required at least %zu, got %zu\n",
1892 minSize, size);
1893 }
1894
parsePropId(const std::vector<std::string> & options,size_t index)1895 Result<int32_t> FakeVehicleHardware::parsePropId(const std::vector<std::string>& options,
1896 size_t index) {
1897 const std::string& propIdStr = options[index];
1898 auto result = stringToPropId(propIdStr);
1899 if (result.ok()) {
1900 return result;
1901 }
1902 return safelyParseInt<int32_t>(index, propIdStr);
1903 }
1904
dumpSpecificProperty(const std::vector<std::string> & options)1905 std::string FakeVehicleHardware::dumpSpecificProperty(const std::vector<std::string>& options) {
1906 if (auto result = checkArgumentsSize(options, /*minSize=*/2); !result.ok()) {
1907 return getErrorMsg(result);
1908 }
1909
1910 // options[0] is the command itself...
1911 int rowNumber = 1;
1912 size_t size = options.size();
1913 std::string msg = "";
1914 for (size_t i = 1; i < size; ++i) {
1915 auto propResult = parsePropId(options, i);
1916 if (!propResult.ok()) {
1917 msg += getErrorMsg(propResult);
1918 continue;
1919 }
1920 int32_t prop = propResult.value();
1921 auto result = mServerSidePropStore->getPropConfig(prop);
1922 if (!result.ok()) {
1923 msg += StringPrintf("No property %s\n", PROP_ID_TO_CSTR(prop));
1924 continue;
1925 }
1926 msg += dumpOnePropertyByConfig(rowNumber++, result.value());
1927 }
1928 return msg;
1929 }
1930
getOptionValues(const std::vector<std::string> & options,size_t * index)1931 std::vector<std::string> FakeVehicleHardware::getOptionValues(
1932 const std::vector<std::string>& options, size_t* index) {
1933 std::vector<std::string> values;
1934 while (*index < options.size()) {
1935 std::string option = options[*index];
1936 if (SET_PROP_OPTIONS.find(option) != SET_PROP_OPTIONS.end()) {
1937 return values;
1938 }
1939 values.push_back(option);
1940 (*index)++;
1941 }
1942 return values;
1943 }
1944
parsePropOptions(const std::vector<std::string> & options)1945 Result<VehiclePropValue> FakeVehicleHardware::parsePropOptions(
1946 const std::vector<std::string>& options) {
1947 // Options format:
1948 // --set/get/inject-event PROP [-f f1 f2...] [-i i1 i2...] [-i64 i1 i2...] [-s s1 s2...]
1949 // [-b b1 b2...] [-a a] [-t timestamp]
1950 size_t optionIndex = 1;
1951 auto result = parsePropId(options, optionIndex);
1952 if (!result.ok()) {
1953 return Error() << StringPrintf("Property ID/Name: \"%s\" is not valid: %s\n",
1954 options[optionIndex].c_str(), getErrorMsg(result).c_str());
1955 }
1956 VehiclePropValue prop = {};
1957 prop.prop = result.value();
1958 prop.status = VehiclePropertyStatus::AVAILABLE;
1959 optionIndex++;
1960 std::unordered_set<std::string> parsedOptions;
1961
1962 while (optionIndex < options.size()) {
1963 std::string argType = options[optionIndex];
1964 optionIndex++;
1965
1966 size_t currentIndex = optionIndex;
1967 std::vector<std::string> argValues = getOptionValues(options, &optionIndex);
1968 if (parsedOptions.find(argType) != parsedOptions.end()) {
1969 return Error() << StringPrintf("Duplicate \"%s\" options\n", argType.c_str());
1970 }
1971 parsedOptions.insert(argType);
1972 size_t argValuesSize = argValues.size();
1973 if (EqualsIgnoreCase(argType, "-i")) {
1974 if (argValuesSize == 0) {
1975 return Error() << "No values specified when using \"-i\"\n";
1976 }
1977 prop.value.int32Values.resize(argValuesSize);
1978 for (size_t i = 0; i < argValuesSize; i++) {
1979 auto int32Result = safelyParseInt<int32_t>(currentIndex + i, argValues[i]);
1980 if (!int32Result.ok()) {
1981 return Error()
1982 << StringPrintf("Value: \"%s\" is not a valid int: %s\n",
1983 argValues[i].c_str(), getErrorMsg(int32Result).c_str());
1984 }
1985 prop.value.int32Values[i] = int32Result.value();
1986 }
1987 } else if (EqualsIgnoreCase(argType, "-i64")) {
1988 if (argValuesSize == 0) {
1989 return Error() << "No values specified when using \"-i64\"\n";
1990 }
1991 prop.value.int64Values.resize(argValuesSize);
1992 for (size_t i = 0; i < argValuesSize; i++) {
1993 auto int64Result = safelyParseInt<int64_t>(currentIndex + i, argValues[i]);
1994 if (!int64Result.ok()) {
1995 return Error()
1996 << StringPrintf("Value: \"%s\" is not a valid int64: %s\n",
1997 argValues[i].c_str(), getErrorMsg(int64Result).c_str());
1998 }
1999 prop.value.int64Values[i] = int64Result.value();
2000 }
2001 } else if (EqualsIgnoreCase(argType, "-f")) {
2002 if (argValuesSize == 0) {
2003 return Error() << "No values specified when using \"-f\"\n";
2004 }
2005 prop.value.floatValues.resize(argValuesSize);
2006 for (size_t i = 0; i < argValuesSize; i++) {
2007 auto floatResult = safelyParseFloat(currentIndex + i, argValues[i]);
2008 if (!floatResult.ok()) {
2009 return Error()
2010 << StringPrintf("Value: \"%s\" is not a valid float: %s\n",
2011 argValues[i].c_str(), getErrorMsg(floatResult).c_str());
2012 }
2013 prop.value.floatValues[i] = floatResult.value();
2014 }
2015 } else if (EqualsIgnoreCase(argType, "-s")) {
2016 if (argValuesSize != 1) {
2017 return Error() << "Expect exact one value when using \"-s\"\n";
2018 }
2019 prop.value.stringValue = argValues[0];
2020 } else if (EqualsIgnoreCase(argType, "-b")) {
2021 if (argValuesSize != 1) {
2022 return Error() << "Expect exact one value when using \"-b\"\n";
2023 }
2024 auto bytesResult = parseHexString(argValues[0]);
2025 if (!bytesResult.ok()) {
2026 return Error() << StringPrintf("value: \"%s\" is not a valid hex string: %s\n",
2027 argValues[0].c_str(),
2028 getErrorMsg(bytesResult).c_str());
2029 }
2030 prop.value.byteValues = std::move(bytesResult.value());
2031 } else if (EqualsIgnoreCase(argType, "-a")) {
2032 if (argValuesSize != 1) {
2033 return Error() << "Expect exact one value when using \"-a\"\n";
2034 }
2035 auto int32Result = safelyParseInt<int32_t>(currentIndex, argValues[0]);
2036 if (!int32Result.ok()) {
2037 return Error() << StringPrintf("Area ID: \"%s\" is not a valid int: %s\n",
2038 argValues[0].c_str(),
2039 getErrorMsg(int32Result).c_str());
2040 }
2041 prop.areaId = int32Result.value();
2042 } else if (EqualsIgnoreCase(argType, "-t")) {
2043 if (argValuesSize != 1) {
2044 return Error() << "Expect exact one value when using \"-t\"\n";
2045 }
2046 auto int64Result = safelyParseInt<int64_t>(currentIndex, argValues[0]);
2047 if (!int64Result.ok()) {
2048 return Error() << StringPrintf("Timestamp: \"%s\" is not a valid int64: %s\n",
2049 argValues[0].c_str(),
2050 getErrorMsg(int64Result).c_str());
2051 }
2052 prop.timestamp = int64Result.value();
2053 } else {
2054 return Error() << StringPrintf("Unknown option: %s\n", argType.c_str());
2055 }
2056 }
2057
2058 return prop;
2059 }
2060
dumpSetProperties(const std::vector<std::string> & options)2061 std::string FakeVehicleHardware::dumpSetProperties(const std::vector<std::string>& options) {
2062 if (auto result = checkArgumentsSize(options, 3); !result.ok()) {
2063 return getErrorMsg(result);
2064 }
2065
2066 auto parseResult = parsePropOptions(options);
2067 if (!parseResult.ok()) {
2068 return getErrorMsg(parseResult);
2069 }
2070 VehiclePropValue prop = std::move(parseResult.value());
2071 ALOGD("Dump: Setting property: %s", prop.toString().c_str());
2072
2073 bool isSpecialValue = false;
2074 auto setResult = maybeSetSpecialValue(prop, &isSpecialValue);
2075
2076 if (!isSpecialValue) {
2077 auto updatedValue = mValuePool->obtain(prop);
2078 updatedValue->timestamp = elapsedRealtimeNano();
2079 setResult = mServerSidePropStore->writeValue(std::move(updatedValue));
2080 }
2081
2082 if (setResult.ok()) {
2083 return StringPrintf("Set property: %s\n", prop.toString().c_str());
2084 }
2085 return StringPrintf("failed to set property: %s, error: %s\n", prop.toString().c_str(),
2086 getErrorMsg(setResult).c_str());
2087 }
2088
dumpGetPropertyWithArg(const std::vector<std::string> & options)2089 std::string FakeVehicleHardware::dumpGetPropertyWithArg(const std::vector<std::string>& options) {
2090 if (auto result = checkArgumentsSize(options, 3); !result.ok()) {
2091 return getErrorMsg(result);
2092 }
2093
2094 auto parseResult = parsePropOptions(options);
2095 if (!parseResult.ok()) {
2096 return getErrorMsg(parseResult);
2097 }
2098 VehiclePropValue prop = std::move(parseResult.value());
2099 ALOGD("Dump: Getting property: %s", prop.toString().c_str());
2100
2101 bool isSpecialValue = false;
2102 auto result = maybeGetSpecialValue(prop, &isSpecialValue);
2103
2104 if (!isSpecialValue) {
2105 result = mServerSidePropStore->readValue(prop);
2106 }
2107
2108 if (!result.ok()) {
2109 return StringPrintf("failed to read property value: %s, error: %s, code: %d\n",
2110 PROP_ID_TO_CSTR(prop.prop), getErrorMsg(result).c_str(),
2111 getIntErrorCode(result));
2112 }
2113 return StringPrintf("Get property result: %s\n", result.value()->toString().c_str());
2114 }
2115
dumpSaveProperty(const std::vector<std::string> & options)2116 std::string FakeVehicleHardware::dumpSaveProperty(const std::vector<std::string>& options) {
2117 // Format: --save-prop PROP [-a areaID]
2118 if (auto result = checkArgumentsSize(options, 2); !result.ok()) {
2119 return getErrorMsg(result);
2120 }
2121
2122 auto parseResult = parsePropOptions(options);
2123 if (!parseResult.ok()) {
2124 return getErrorMsg(parseResult);
2125 }
2126 // We are only using the prop and areaId option.
2127 VehiclePropValue value = std::move(parseResult.value());
2128 int32_t propId = value.prop;
2129 int32_t areaId = value.areaId;
2130
2131 auto readResult = mServerSidePropStore->readValue(value);
2132 if (!readResult.ok()) {
2133 return StringPrintf("Failed to save current property value, error: %s",
2134 getErrorMsg(readResult).c_str());
2135 }
2136
2137 std::scoped_lock<std::mutex> lockGuard(mLock);
2138 mSavedProps[PropIdAreaId{
2139 .propId = propId,
2140 .areaId = areaId,
2141 }] = std::move(readResult.value());
2142
2143 return StringPrintf("Property: %" PRId32 ", areaID: %" PRId32 " saved", propId, areaId);
2144 }
2145
dumpRestoreProperty(const std::vector<std::string> & options)2146 std::string FakeVehicleHardware::dumpRestoreProperty(const std::vector<std::string>& options) {
2147 // Format: --restore-prop PROP [-a areaID]
2148 if (auto result = checkArgumentsSize(options, 2); !result.ok()) {
2149 return getErrorMsg(result);
2150 }
2151
2152 auto parseResult = parsePropOptions(options);
2153 if (!parseResult.ok()) {
2154 return getErrorMsg(parseResult);
2155 }
2156 // We are only using the prop and areaId option.
2157 VehiclePropValue value = std::move(parseResult.value());
2158 int32_t propId = value.prop;
2159 int32_t areaId = value.areaId;
2160 VehiclePropValuePool::RecyclableType savedValue;
2161
2162 {
2163 std::scoped_lock<std::mutex> lockGuard(mLock);
2164 auto it = mSavedProps.find(PropIdAreaId{
2165 .propId = propId,
2166 .areaId = areaId,
2167 });
2168 if (it == mSavedProps.end()) {
2169 return StringPrintf("No saved property for property: %" PRId32 ", areaID: %" PRId32,
2170 propId, areaId);
2171 }
2172
2173 savedValue = std::move(it->second);
2174 // Remove the saved property after restoring it.
2175 mSavedProps.erase(it);
2176 }
2177
2178 // Update timestamp.
2179 savedValue->timestamp = elapsedRealtimeNano();
2180
2181 auto writeResult = mServerSidePropStore->writeValue(std::move(savedValue));
2182 if (!writeResult.ok()) {
2183 return StringPrintf("Failed to restore property value, error: %s",
2184 getErrorMsg(writeResult).c_str());
2185 }
2186
2187 return StringPrintf("Property: %" PRId32 ", areaID: %" PRId32 " restored", propId, areaId);
2188 }
2189
dumpInjectEvent(const std::vector<std::string> & options)2190 std::string FakeVehicleHardware::dumpInjectEvent(const std::vector<std::string>& options) {
2191 if (auto result = checkArgumentsSize(options, 3); !result.ok()) {
2192 return getErrorMsg(result);
2193 }
2194
2195 auto parseResult = parsePropOptions(options);
2196 if (!parseResult.ok()) {
2197 return getErrorMsg(parseResult);
2198 }
2199 VehiclePropValue prop = std::move(parseResult.value());
2200 ALOGD("Dump: Injecting event from vehicle bus: %s", prop.toString().c_str());
2201
2202 eventFromVehicleBus(prop);
2203
2204 return StringPrintf("Event for property: %s injected", PROP_ID_TO_CSTR(prop.prop));
2205 }
2206
checkHealth()2207 StatusCode FakeVehicleHardware::checkHealth() {
2208 // Always return OK for checkHealth.
2209 return StatusCode::OK;
2210 }
2211
registerOnPropertyChangeEvent(std::unique_ptr<const PropertyChangeCallback> callback)2212 void FakeVehicleHardware::registerOnPropertyChangeEvent(
2213 std::unique_ptr<const PropertyChangeCallback> callback) {
2214 if (mOnPropertyChangeCallback != nullptr) {
2215 ALOGE("registerOnPropertyChangeEvent must only be called once");
2216 return;
2217 }
2218 mOnPropertyChangeCallback = std::move(callback);
2219 }
2220
registerOnPropertySetErrorEvent(std::unique_ptr<const PropertySetErrorCallback> callback)2221 void FakeVehicleHardware::registerOnPropertySetErrorEvent(
2222 std::unique_ptr<const PropertySetErrorCallback> callback) {
2223 // In FakeVehicleHardware, we will never use mOnPropertySetErrorCallback.
2224 if (mOnPropertySetErrorCallback != nullptr) {
2225 ALOGE("registerOnPropertySetErrorEvent must only be called once");
2226 return;
2227 }
2228 mOnPropertySetErrorCallback = std::move(callback);
2229 }
2230
subscribe(SubscribeOptions options)2231 StatusCode FakeVehicleHardware::subscribe(SubscribeOptions options) {
2232 int32_t propId = options.propId;
2233
2234 auto configResult = mServerSidePropStore->getPropConfig(propId);
2235 if (!configResult.ok()) {
2236 ALOGE("subscribe: property: %" PRId32 " is not supported", propId);
2237 return StatusCode::INVALID_ARG;
2238 }
2239
2240 std::scoped_lock<std::mutex> lockGuard(mLock);
2241 for (int areaId : options.areaIds) {
2242 if (StatusCode status = subscribePropIdAreaIdLocked(propId, areaId, options.sampleRate,
2243 options.enableVariableUpdateRate,
2244 configResult.value());
2245 status != StatusCode::OK) {
2246 return status;
2247 }
2248 }
2249 return StatusCode::OK;
2250 }
2251
isVariableUpdateRateSupported(const VehiclePropConfig & vehiclePropConfig,int32_t areaId)2252 bool FakeVehicleHardware::isVariableUpdateRateSupported(const VehiclePropConfig& vehiclePropConfig,
2253 int32_t areaId) {
2254 for (size_t i = 0; i < vehiclePropConfig.areaConfigs.size(); i++) {
2255 const auto& areaConfig = vehiclePropConfig.areaConfigs[i];
2256 if (areaConfig.areaId != areaId) {
2257 continue;
2258 }
2259 if (areaConfig.supportVariableUpdateRate) {
2260 return true;
2261 }
2262 break;
2263 }
2264 return false;
2265 }
2266
refreshTimestampForInterval(int64_t intervalInNanos)2267 void FakeVehicleHardware::refreshTimestampForInterval(int64_t intervalInNanos) {
2268 std::unordered_map<PropIdAreaId, VehiclePropertyStore::EventMode, PropIdAreaIdHash>
2269 eventModeByPropIdAreaId;
2270
2271 {
2272 std::scoped_lock<std::mutex> lockGuard(mLock);
2273
2274 if (mActionByIntervalInNanos.find(intervalInNanos) == mActionByIntervalInNanos.end()) {
2275 ALOGE("No actions scheduled for the interval: %" PRId64 ", ignore the refresh request",
2276 intervalInNanos);
2277 return;
2278 }
2279
2280 ActionForInterval actionForInterval = mActionByIntervalInNanos[intervalInNanos];
2281
2282 // Make a copy so that we don't hold the lock while trying to refresh the timestamp.
2283 // Refreshing the timestamp will inovke onValueChangeCallback which also requires lock, so
2284 // we must not hold lock.
2285 for (const PropIdAreaId& propIdAreaId : actionForInterval.propIdAreaIdsToRefresh) {
2286 const RefreshInfo& refreshInfo = mRefreshInfoByPropIdAreaId[propIdAreaId];
2287 eventModeByPropIdAreaId[propIdAreaId] = refreshInfo.eventMode;
2288 }
2289 }
2290
2291 mServerSidePropStore->refreshTimestamps(eventModeByPropIdAreaId);
2292 }
2293
registerRefreshLocked(PropIdAreaId propIdAreaId,VehiclePropertyStore::EventMode eventMode,float sampleRateHz)2294 void FakeVehicleHardware::registerRefreshLocked(PropIdAreaId propIdAreaId,
2295 VehiclePropertyStore::EventMode eventMode,
2296 float sampleRateHz) {
2297 if (mRefreshInfoByPropIdAreaId.find(propIdAreaId) != mRefreshInfoByPropIdAreaId.end()) {
2298 unregisterRefreshLocked(propIdAreaId);
2299 }
2300
2301 int64_t intervalInNanos = static_cast<int64_t>(1'000'000'000. / sampleRateHz);
2302 RefreshInfo refreshInfo = {
2303 .eventMode = eventMode,
2304 .intervalInNanos = intervalInNanos,
2305 };
2306 mRefreshInfoByPropIdAreaId[propIdAreaId] = refreshInfo;
2307
2308 if (mActionByIntervalInNanos.find(intervalInNanos) != mActionByIntervalInNanos.end()) {
2309 // If we have already registered for this interval, then add the action info to the
2310 // actions list.
2311 mActionByIntervalInNanos[intervalInNanos].propIdAreaIdsToRefresh.insert(propIdAreaId);
2312 return;
2313 }
2314
2315 // This is the first action for the interval, register a timer callback for that interval.
2316 auto action = std::make_shared<RecurrentTimer::Callback>(
2317 [this, intervalInNanos] { refreshTimestampForInterval(intervalInNanos); });
2318 mActionByIntervalInNanos[intervalInNanos] = ActionForInterval{
2319 .propIdAreaIdsToRefresh = {propIdAreaId},
2320 .recurrentAction = action,
2321 };
2322 mRecurrentTimer->registerTimerCallback(intervalInNanos, action);
2323 }
2324
unregisterRefreshLocked(PropIdAreaId propIdAreaId)2325 void FakeVehicleHardware::unregisterRefreshLocked(PropIdAreaId propIdAreaId) {
2326 if (mRefreshInfoByPropIdAreaId.find(propIdAreaId) == mRefreshInfoByPropIdAreaId.end()) {
2327 ALOGW("PropId: %" PRId32 ", areaId: %" PRId32 " was not registered for refresh, ignore",
2328 propIdAreaId.propId, propIdAreaId.areaId);
2329 return;
2330 }
2331
2332 int64_t intervalInNanos = mRefreshInfoByPropIdAreaId[propIdAreaId].intervalInNanos;
2333 auto& actionForInterval = mActionByIntervalInNanos[intervalInNanos];
2334 actionForInterval.propIdAreaIdsToRefresh.erase(propIdAreaId);
2335 if (actionForInterval.propIdAreaIdsToRefresh.empty()) {
2336 mRecurrentTimer->unregisterTimerCallback(actionForInterval.recurrentAction);
2337 mActionByIntervalInNanos.erase(intervalInNanos);
2338 }
2339 mRefreshInfoByPropIdAreaId.erase(propIdAreaId);
2340 }
2341
subscribePropIdAreaIdLocked(int32_t propId,int32_t areaId,float sampleRateHz,bool enableVariableUpdateRate,const VehiclePropConfig & vehiclePropConfig)2342 StatusCode FakeVehicleHardware::subscribePropIdAreaIdLocked(
2343 int32_t propId, int32_t areaId, float sampleRateHz, bool enableVariableUpdateRate,
2344 const VehiclePropConfig& vehiclePropConfig) {
2345 PropIdAreaId propIdAreaId{
2346 .propId = propId,
2347 .areaId = areaId,
2348 };
2349 switch (vehiclePropConfig.changeMode) {
2350 case VehiclePropertyChangeMode::STATIC:
2351 ALOGW("subscribe to a static property, do nothing.");
2352 return StatusCode::OK;
2353 case VehiclePropertyChangeMode::ON_CHANGE:
2354 mSubOnChangePropIdAreaIds.insert(std::move(propIdAreaId));
2355 return StatusCode::OK;
2356 case VehiclePropertyChangeMode::CONTINUOUS:
2357 if (sampleRateHz == 0.f) {
2358 ALOGE("Must not use sample rate 0 for a continuous property");
2359 return StatusCode::INVALID_ARG;
2360 }
2361 // For continuous properties, we must generate a new onPropertyChange event
2362 // periodically according to the sample rate.
2363 auto eventMode = VehiclePropertyStore::EventMode::ALWAYS;
2364 if (isVariableUpdateRateSupported(vehiclePropConfig, areaId) &&
2365 enableVariableUpdateRate) {
2366 eventMode = VehiclePropertyStore::EventMode::ON_VALUE_CHANGE;
2367 }
2368
2369 registerRefreshLocked(propIdAreaId, eventMode, sampleRateHz);
2370 return StatusCode::OK;
2371 }
2372 }
2373
unsubscribe(int32_t propId,int32_t areaId)2374 StatusCode FakeVehicleHardware::unsubscribe(int32_t propId, int32_t areaId) {
2375 std::scoped_lock<std::mutex> lockGuard(mLock);
2376 PropIdAreaId propIdAreaId{
2377 .propId = propId,
2378 .areaId = areaId,
2379 };
2380 if (mRefreshInfoByPropIdAreaId.find(propIdAreaId) != mRefreshInfoByPropIdAreaId.end()) {
2381 unregisterRefreshLocked(propIdAreaId);
2382 }
2383 mSubOnChangePropIdAreaIds.erase(propIdAreaId);
2384 return StatusCode::OK;
2385 }
2386
onValueChangeCallback(const VehiclePropValue & value)2387 void FakeVehicleHardware::onValueChangeCallback(const VehiclePropValue& value) {
2388 ATRACE_CALL();
2389 onValuesChangeCallback({value});
2390 }
2391
onValuesChangeCallback(std::vector<VehiclePropValue> values)2392 void FakeVehicleHardware::onValuesChangeCallback(std::vector<VehiclePropValue> values) {
2393 ATRACE_CALL();
2394 std::vector<VehiclePropValue> subscribedUpdatedValues;
2395
2396 {
2397 std::scoped_lock<std::mutex> lockGuard(mLock);
2398 if (mOnPropertyChangeCallback == nullptr) {
2399 return;
2400 }
2401
2402 for (const auto& value : values) {
2403 PropIdAreaId propIdAreaId{
2404 .propId = value.prop,
2405 .areaId = value.areaId,
2406 };
2407 if (mRefreshInfoByPropIdAreaId.find(propIdAreaId) == mRefreshInfoByPropIdAreaId.end() &&
2408 mSubOnChangePropIdAreaIds.find(propIdAreaId) == mSubOnChangePropIdAreaIds.end()) {
2409 if (FAKE_VEHICLEHARDWARE_DEBUG) {
2410 ALOGD("The updated property value: %s is not subscribed, ignore",
2411 value.toString().c_str());
2412 }
2413 continue;
2414 }
2415
2416 subscribedUpdatedValues.push_back(value);
2417 }
2418 }
2419
2420 (*mOnPropertyChangeCallback)(std::move(subscribedUpdatedValues));
2421 }
2422
loadPropConfigsFromDir(const std::string & dirPath,std::unordered_map<int32_t,ConfigDeclaration> * configsByPropId)2423 bool FakeVehicleHardware::loadPropConfigsFromDir(
2424 const std::string& dirPath,
2425 std::unordered_map<int32_t, ConfigDeclaration>* configsByPropId) {
2426 ALOGI("loading properties from %s", dirPath.c_str());
2427 auto dir = opendir(dirPath.c_str());
2428 if (dir == nullptr) {
2429 ALOGE("Failed to open config directory: %s", dirPath.c_str());
2430 return false;
2431 }
2432
2433 std::regex regJson(".*[.]json", std::regex::icase);
2434 while (auto f = readdir(dir)) {
2435 if (!std::regex_match(f->d_name, regJson)) {
2436 continue;
2437 }
2438 std::string filePath = dirPath + "/" + std::string(f->d_name);
2439 ALOGI("loading properties from %s", filePath.c_str());
2440 auto result = mLoader.loadPropConfig(filePath);
2441 if (!result.ok()) {
2442 ALOGE("failed to load config file: %s, error: %s", filePath.c_str(),
2443 result.error().message().c_str());
2444 continue;
2445 }
2446 for (auto& [propId, configDeclaration] : result.value()) {
2447 (*configsByPropId)[propId] = std::move(configDeclaration);
2448 }
2449 }
2450 closedir(dir);
2451 return true;
2452 }
2453
safelyParseFloat(int index,const std::string & s)2454 Result<float> FakeVehicleHardware::safelyParseFloat(int index, const std::string& s) {
2455 float out;
2456 if (!ParseFloat(s, &out)) {
2457 return Error() << StringPrintf("non-float argument at index %d: %s\n", index, s.c_str());
2458 }
2459 return out;
2460 }
2461
parseHexString(const std::string & s)2462 Result<std::vector<uint8_t>> FakeVehicleHardware::parseHexString(const std::string& s) {
2463 std::vector<uint8_t> bytes;
2464 if (s.size() % 2 != 0) {
2465 return Error() << StringPrintf("invalid hex string: %s, should have even size\n",
2466 s.c_str());
2467 }
2468 if (!StartsWith(s, "0x")) {
2469 return Error() << StringPrintf("hex string should start with \"0x\", got %s\n", s.c_str());
2470 }
2471 std::string subs = s.substr(2);
2472 std::transform(subs.begin(), subs.end(), subs.begin(),
2473 [](unsigned char c) { return std::tolower(c); });
2474
2475 bool highDigit = true;
2476 for (size_t i = 0; i < subs.size(); i++) {
2477 char c = subs[i];
2478 uint8_t v;
2479 if (c >= '0' && c <= '9') {
2480 v = c - '0';
2481 } else if (c >= 'a' && c <= 'f') {
2482 v = c - 'a' + 10;
2483 } else {
2484 return Error() << StringPrintf("invalid character %c in hex string %s\n", c,
2485 subs.c_str());
2486 }
2487 if (highDigit) {
2488 bytes.push_back(v * 16);
2489 } else {
2490 bytes[bytes.size() - 1] += v;
2491 }
2492 highDigit = !highDigit;
2493 }
2494 return bytes;
2495 }
2496
2497 template <class CallbackType, class RequestType>
PendingRequestHandler(FakeVehicleHardware * hardware)2498 FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::PendingRequestHandler(
2499 FakeVehicleHardware* hardware)
2500 : mHardware(hardware) {
2501 // Don't initialize mThread in initialization list because mThread depends on mRequests and we
2502 // want mRequests to be initialized first.
2503 mThread = std::thread([this] {
2504 while (mRequests.waitForItems()) {
2505 handleRequestsOnce();
2506 }
2507 });
2508 }
2509
2510 template <class CallbackType, class RequestType>
addRequest(RequestType request,std::shared_ptr<const CallbackType> callback)2511 void FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::addRequest(
2512 RequestType request, std::shared_ptr<const CallbackType> callback) {
2513 mRequests.push({
2514 request,
2515 callback,
2516 });
2517 }
2518
2519 template <class CallbackType, class RequestType>
stop()2520 void FakeVehicleHardware::PendingRequestHandler<CallbackType, RequestType>::stop() {
2521 mRequests.deactivate();
2522 if (mThread.joinable()) {
2523 mThread.join();
2524 }
2525 }
2526
2527 template <>
2528 void FakeVehicleHardware::PendingRequestHandler<FakeVehicleHardware::GetValuesCallback,
handleRequestsOnce()2529 GetValueRequest>::handleRequestsOnce() {
2530 std::unordered_map<std::shared_ptr<const GetValuesCallback>, std::vector<GetValueResult>>
2531 callbackToResults;
2532 for (const auto& rwc : mRequests.flush()) {
2533 ATRACE_BEGIN("FakeVehicleHardware:handleGetValueRequest");
2534 auto result = mHardware->handleGetValueRequest(rwc.request);
2535 ATRACE_END();
2536 callbackToResults[rwc.callback].push_back(std::move(result));
2537 }
2538 for (const auto& [callback, results] : callbackToResults) {
2539 ATRACE_BEGIN("FakeVehicleHardware:call get value result callback");
2540 (*callback)(std::move(results));
2541 ATRACE_END();
2542 }
2543 }
2544
2545 template <>
2546 void FakeVehicleHardware::PendingRequestHandler<FakeVehicleHardware::SetValuesCallback,
handleRequestsOnce()2547 SetValueRequest>::handleRequestsOnce() {
2548 std::unordered_map<std::shared_ptr<const SetValuesCallback>, std::vector<SetValueResult>>
2549 callbackToResults;
2550 for (const auto& rwc : mRequests.flush()) {
2551 ATRACE_BEGIN("FakeVehicleHardware:handleSetValueRequest");
2552 auto result = mHardware->handleSetValueRequest(rwc.request);
2553 ATRACE_END();
2554 callbackToResults[rwc.callback].push_back(std::move(result));
2555 }
2556 for (const auto& [callback, results] : callbackToResults) {
2557 ATRACE_BEGIN("FakeVehicleHardware:call set value result callback");
2558 (*callback)(std::move(results));
2559 ATRACE_END();
2560 }
2561 }
2562
2563 } // namespace fake
2564 } // namespace vehicle
2565 } // namespace automotive
2566 } // namespace hardware
2567 } // namespace android
2568