1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define LOG_TAG "DefaultVehicleHal_v2_0"
17
18 #include <android-base/chrono_utils.h>
19 #include <android-base/macros.h>
20 #include <android-base/properties.h>
21 #include <android/log.h>
22 #include <dirent.h>
23 #include <sys/system_properties.h>
24 #include <utils/SystemClock.h>
25 #include <fstream>
26 #include <regex>
27
28 #include "EmulatedVehicleHal.h"
29 #include "JsonFakeValueGenerator.h"
30 #include "LinearFakeValueGenerator.h"
31 #include "Obd2SensorStore.h"
32
33 namespace android {
34 namespace hardware {
35 namespace automotive {
36 namespace vehicle {
37 namespace V2_0 {
38
39 namespace impl {
40
41 static constexpr std::chrono::nanoseconds kHeartBeatIntervalNs = 3s;
42
fillDefaultObd2Frame(size_t numVendorIntegerSensors,size_t numVendorFloatSensors)43 static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorIntegerSensors,
44 size_t numVendorFloatSensors) {
45 std::unique_ptr<Obd2SensorStore> sensorStore(
46 new Obd2SensorStore(numVendorIntegerSensors, numVendorFloatSensors));
47
48 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS,
49 toInt(Obd2FuelSystemStatus::CLOSED_LOOP));
50 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0);
51 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_MONITORS_SUPPORTED,
52 toInt(Obd2IgnitionMonitorKind::SPARK));
53 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_SPECIFIC_MONITORS,
54 Obd2CommonIgnitionMonitors::COMPONENTS_AVAILABLE |
55 Obd2CommonIgnitionMonitors::MISFIRE_AVAILABLE |
56 Obd2SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE |
57 Obd2SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE);
58 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35);
59 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS,
60 toInt(Obd2SecondaryAirStatus::FROM_OUTSIDE_OR_OFF));
61 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1);
62 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500);
63 sensorStore->setIntegerSensor(
64 DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0);
65 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51);
66 sensorStore->setIntegerSensor(
67 DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365);
68 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30);
69 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12);
70 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18);
71 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1);
72 sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_TYPE,
73 toInt(Obd2FuelType::GASOLINE));
74 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153);
75 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16);
76 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16);
77 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16);
78 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16);
79 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5);
80 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ENGINE_RPM, 1250.);
81 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::VEHICLE_SPEED, 40.);
82 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::TIMING_ADVANCE, 2.5);
83 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::THROTTLE_POSITION, 19.75);
84 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265);
85 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824);
86 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE,
87 -0.373);
88 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1,
89 190.);
90 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.);
91 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306);
92 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188);
93 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094);
94 sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024);
95
96 return sensorStore;
97 }
98
EmulatedVehicleHal(VehiclePropertyStore * propStore,VehicleHalClient * client,EmulatedUserHal * emulatedUserHal)99 EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client,
100 EmulatedUserHal* emulatedUserHal)
101 : mPropStore(propStore),
102 mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
103 mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
104 std::placeholders::_1)),
105 mVehicleClient(client),
106 mEmulatedUserHal(emulatedUserHal) {
107 initStaticConfig();
108 mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
109 this, std::placeholders::_1,
110 std::placeholders::_2));
111
112 mInitVhalValueOverride =
113 android::base::GetBoolProperty("persist.vendor.vhal_init_value_override", false);
114 if (mInitVhalValueOverride) {
115 getAllPropertiesOverride();
116 }
117 }
118
getAllPropertiesOverride()119 void EmulatedVehicleHal::getAllPropertiesOverride() {
120 if (auto dir = opendir("/vendor/etc/vhaloverride/")) {
121 std::regex reg_json(".*[.]json", std::regex::icase);
122 while (auto f = readdir(dir)) {
123 if (!regex_match(f->d_name, reg_json)) {
124 continue;
125 }
126 std::string file = "/vendor/etc/vhaloverride/" + std::string(f->d_name);
127 JsonFakeValueGenerator tmpGenerator(file);
128
129 std::vector<VehiclePropValue> propvalues = tmpGenerator.getAllEvents();
130 mVehiclePropertiesOverride.insert(std::end(mVehiclePropertiesOverride),
131 std::begin(propvalues), std::end(propvalues));
132 }
133 closedir(dir);
134 }
135 }
136
get(const VehiclePropValue & requestedPropValue,StatusCode * outStatus)137 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
138 const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
139 auto propId = requestedPropValue.prop;
140 ALOGV("get(%d)", propId);
141
142 auto& pool = *getValuePool();
143 VehiclePropValuePtr v = nullptr;
144
145 switch (propId) {
146 case OBD2_FREEZE_FRAME:
147 v = pool.obtainComplex();
148 *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
149 break;
150 case OBD2_FREEZE_FRAME_INFO:
151 v = pool.obtainComplex();
152 *outStatus = fillObd2DtcInfo(v.get());
153 break;
154 default:
155 if (mEmulatedUserHal != nullptr && mEmulatedUserHal->isSupported(propId)) {
156 ALOGI("get(): getting value for prop %d from User HAL", propId);
157 const auto& ret = mEmulatedUserHal->onGetProperty(requestedPropValue);
158 if (!ret.ok()) {
159 ALOGE("get(): User HAL returned error: %s", ret.error().message().c_str());
160 *outStatus = StatusCode(ret.error().code());
161 } else {
162 auto value = ret.value().get();
163 if (value != nullptr) {
164 ALOGI("get(): User HAL returned value: %s", toString(*value).c_str());
165 v = getValuePool()->obtain(*value);
166 *outStatus = StatusCode::OK;
167 } else {
168 ALOGE("get(): User HAL returned null value");
169 *outStatus = StatusCode::INTERNAL_ERROR;
170 }
171 }
172 break;
173 }
174
175 auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
176 if (internalPropValue != nullptr) {
177 v = getValuePool()->obtain(*internalPropValue);
178 }
179
180 if (!v) {
181 *outStatus = StatusCode::INVALID_ARG;
182 } else if (v->status == VehiclePropertyStatus::AVAILABLE) {
183 *outStatus = StatusCode::OK;
184 } else {
185 *outStatus = StatusCode::TRY_AGAIN;
186 }
187 break;
188 }
189 if (v.get()) {
190 v->timestamp = elapsedRealtimeNano();
191 }
192 return v;
193 }
194
dump(const hidl_handle & fd,const hidl_vec<hidl_string> & options)195 bool EmulatedVehicleHal::dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
196 return mVehicleClient->dump(fd, options);
197 }
198
set(const VehiclePropValue & propValue)199 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
200 constexpr bool updateStatus = false;
201
202 if (propValue.prop == kGenerateFakeDataControllingProperty) {
203 // Send the generator controlling request to the server.
204 // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case)
205 // instead of the generated values triggered by it. 'propValue' works as a control signal
206 // here, since we never send the control signal back, the value of 'updateStatus' flag
207 // does not matter here.
208 auto status = mVehicleClient->setProperty(propValue, updateStatus);
209 return status;
210 } else if (mHvacPowerProps.count(propValue.prop)) {
211 auto hvacPowerOn = mPropStore->readValueOrNull(
212 toInt(VehicleProperty::HVAC_POWER_ON),
213 (VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_1_RIGHT |
214 VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER |
215 VehicleAreaSeat::ROW_2_RIGHT));
216
217 if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
218 && hvacPowerOn->value.int32Values[0] == 0) {
219 return StatusCode::NOT_AVAILABLE;
220 }
221 } else {
222 // Handle property specific code
223 switch (propValue.prop) {
224 case OBD2_FREEZE_FRAME_CLEAR:
225 return clearObd2FreezeFrames(propValue);
226 case VEHICLE_MAP_SERVICE:
227 // Placeholder for future implementation of VMS property in the default hal. For
228 // now, just returns OK; otherwise, hal clients crash with property not supported.
229 return StatusCode::OK;
230 }
231 }
232
233 if (propValue.status != VehiclePropertyStatus::AVAILABLE) {
234 // Android side cannot set property status - this value is the
235 // purview of the HAL implementation to reflect the state of
236 // its underlying hardware
237 return StatusCode::INVALID_ARG;
238 }
239 auto currentPropValue = mPropStore->readValueOrNull(propValue);
240
241 if (currentPropValue == nullptr) {
242 return StatusCode::INVALID_ARG;
243 }
244 if (currentPropValue->status != VehiclePropertyStatus::AVAILABLE) {
245 // do not allow Android side to set() a disabled/error property
246 return StatusCode::NOT_AVAILABLE;
247 }
248
249 if (mInEmulator && propValue.prop == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) {
250 // Emulator does not support remote brightness control, b/139959479
251 // do not send it down so that it does not bring unnecessary property change event
252 // return other error code, such NOT_AVAILABLE, causes Emulator to be freezing
253 // TODO: return StatusCode::NOT_AVAILABLE once the above issue is fixed
254 return StatusCode::OK;
255 }
256
257 /**
258 * After checking all conditions, such as the property is available, a real vhal will
259 * sent the events to Car ECU to take actions.
260 */
261
262 // Send the value to the vehicle server, the server will talk to the (real or emulated) car
263 auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
264 if (setValueStatus != StatusCode::OK) {
265 return setValueStatus;
266 }
267
268 return StatusCode::OK;
269 }
270
isDiagnosticProperty(VehiclePropConfig propConfig)271 static bool isDiagnosticProperty(VehiclePropConfig propConfig) {
272 switch (propConfig.prop) {
273 case OBD2_LIVE_FRAME:
274 case OBD2_FREEZE_FRAME:
275 case OBD2_FREEZE_FRAME_CLEAR:
276 case OBD2_FREEZE_FRAME_INFO:
277 return true;
278 }
279 return false;
280 }
281
282 // Parse supported properties list and generate vector of property values to hold current values.
onCreate()283 void EmulatedVehicleHal::onCreate() {
284 static constexpr bool shouldUpdateStatus = true;
285
286 auto configs = mVehicleClient->getAllPropertyConfig();
287
288 for (const auto& cfg : configs) {
289 if (isDiagnosticProperty(cfg)) {
290 // do not write an initial empty value for the diagnostic properties
291 // as we will initialize those separately.
292 continue;
293 }
294
295 int32_t numAreas = isGlobalProp(cfg.prop) ? 0 : cfg.areaConfigs.size();
296
297 for (int i = 0; i < numAreas; i++) {
298 int32_t curArea = isGlobalProp(cfg.prop) ? 0 : cfg.areaConfigs[i].areaId;
299
300 // Create a separate instance for each individual zone
301 VehiclePropValue prop = {
302 .areaId = curArea,
303 .prop = cfg.prop,
304 .status = VehiclePropertyStatus::UNAVAILABLE,
305 };
306
307 if (mInitVhalValueOverride) {
308 for (auto& itOverride : mVehiclePropertiesOverride) {
309 if (itOverride.prop == cfg.prop) {
310 prop.status = VehiclePropertyStatus::AVAILABLE;
311 prop.value = itOverride.value;
312 }
313 }
314 }
315 mPropStore->writeValue(prop, shouldUpdateStatus);
316 }
317 }
318
319 mVehicleClient->triggerSendAllValues();
320
321 initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
322 initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
323 mInEmulator = isInEmulator();
324 ALOGD("mInEmulator=%s", mInEmulator ? "true" : "false");
325 mRecurrentTimer.registerRecurrentEvent(kHeartBeatIntervalNs,
326 static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT));
327 }
328
listProperties()329 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties() {
330 return mPropStore->getAllConfigs();
331 }
332
onContinuousPropertyTimer(const std::vector<int32_t> & properties)333 void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
334 VehiclePropValuePtr v;
335
336 auto& pool = *getValuePool();
337
338 for (int32_t property : properties) {
339 if (isContinuousProperty(property)) {
340 auto internalPropValue = mPropStore->readValueOrNull(property);
341 if (internalPropValue != nullptr) {
342 v = pool.obtain(*internalPropValue);
343 }
344 } else if (property == static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)) {
345 // VHAL_HEARTBEAT is not a continuous value, but it needs to be updated periodically.
346 // So, the update is done through onContinuousPropertyTimer.
347 v = doInternalHealthCheck();
348 } else {
349 ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
350 }
351
352 if (v.get()) {
353 v->timestamp = elapsedRealtimeNano();
354 doHalEvent(std::move(v));
355 }
356 }
357 }
358
subscribe(int32_t property,float sampleRate)359 StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
360 ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
361
362 if (isContinuousProperty(property)) {
363 mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
364 }
365 return StatusCode::OK;
366 }
367
unsubscribe(int32_t property)368 StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
369 ALOGI("%s propId: 0x%x", __func__, property);
370 if (isContinuousProperty(property)) {
371 mRecurrentTimer.unregisterRecurrentEvent(property);
372 }
373 return StatusCode::OK;
374 }
375
isContinuousProperty(int32_t propId) const376 bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
377 const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId);
378 if (config == nullptr) {
379 ALOGW("Config not found for property: 0x%x", propId);
380 return false;
381 }
382 return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
383 }
384
setPropertyFromVehicle(const VehiclePropValue & propValue)385 bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
386 constexpr bool updateStatus = true;
387 return mVehicleClient->setProperty(propValue, updateStatus) == StatusCode::OK;
388 }
389
getAllProperties() const390 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
391 return mPropStore->readAllValues();
392 }
393
onPropertyValue(const VehiclePropValue & value,bool updateStatus)394 void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
395 VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
396
397 if (mPropStore->writeValue(*updatedPropValue, updateStatus)) {
398 getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
399 doHalEvent(std::move(updatedPropValue));
400 }
401 }
402
initStaticConfig()403 void EmulatedVehicleHal::initStaticConfig() {
404 auto configs = mVehicleClient->getAllPropertyConfig();
405 for (auto&& cfg : configs) {
406 VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
407
408 switch (cfg.prop) {
409 case OBD2_FREEZE_FRAME: {
410 tokenFunction = [](const VehiclePropValue& propValue) {
411 return propValue.timestamp;
412 };
413 break;
414 }
415 default:
416 break;
417 }
418
419 mPropStore->registerProperty(cfg, tokenFunction);
420 }
421 }
422
initObd2LiveFrame(const VehiclePropConfig & propConfig)423 void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) {
424 static constexpr bool shouldUpdateStatus = true;
425
426 auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
427 auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
428 static_cast<size_t>(propConfig.configArray[1]));
429 sensorStore->fillPropValue("", liveObd2Frame.get());
430 liveObd2Frame->prop = OBD2_LIVE_FRAME;
431
432 mPropStore->writeValue(*liveObd2Frame, shouldUpdateStatus);
433 }
434
initObd2FreezeFrame(const VehiclePropConfig & propConfig)435 void EmulatedVehicleHal::initObd2FreezeFrame(const VehiclePropConfig& propConfig) {
436 static constexpr bool shouldUpdateStatus = true;
437
438 auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
439 static_cast<size_t>(propConfig.configArray[1]));
440
441 static std::vector<std::string> sampleDtcs = {"P0070",
442 "P0102"
443 "P0123"};
444 for (auto&& dtc : sampleDtcs) {
445 auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
446 sensorStore->fillPropValue(dtc, freezeFrame.get());
447 freezeFrame->prop = OBD2_FREEZE_FRAME;
448
449 mPropStore->writeValue(*freezeFrame, shouldUpdateStatus);
450 }
451 }
452
fillObd2FreezeFrame(const VehiclePropValue & requestedPropValue,VehiclePropValue * outValue)453 StatusCode EmulatedVehicleHal::fillObd2FreezeFrame(const VehiclePropValue& requestedPropValue,
454 VehiclePropValue* outValue) {
455 if (requestedPropValue.value.int64Values.size() != 1) {
456 ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp");
457 return StatusCode::INVALID_ARG;
458 }
459 auto timestamp = requestedPropValue.value.int64Values[0];
460 auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
461 if (freezeFrame == nullptr) {
462 ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
463 return StatusCode::INVALID_ARG;
464 }
465 outValue->prop = OBD2_FREEZE_FRAME;
466 outValue->value.int32Values = freezeFrame->value.int32Values;
467 outValue->value.floatValues = freezeFrame->value.floatValues;
468 outValue->value.bytes = freezeFrame->value.bytes;
469 outValue->value.stringValue = freezeFrame->value.stringValue;
470 outValue->timestamp = freezeFrame->timestamp;
471 return StatusCode::OK;
472 }
473
clearObd2FreezeFrames(const VehiclePropValue & propValue)474 StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
475 if (propValue.value.int64Values.size() == 0) {
476 mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
477 return StatusCode::OK;
478 } else {
479 for (int64_t timestamp : propValue.value.int64Values) {
480 auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
481 if (freezeFrame == nullptr) {
482 ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
483 return StatusCode::INVALID_ARG;
484 }
485 mPropStore->removeValue(*freezeFrame);
486 }
487 }
488 return StatusCode::OK;
489 }
490
fillObd2DtcInfo(VehiclePropValue * outValue)491 StatusCode EmulatedVehicleHal::fillObd2DtcInfo(VehiclePropValue* outValue) {
492 std::vector<int64_t> timestamps;
493 for (const auto& freezeFrame : mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) {
494 timestamps.push_back(freezeFrame.timestamp);
495 }
496 outValue->value.int64Values = timestamps;
497 outValue->prop = OBD2_FREEZE_FRAME_INFO;
498 return StatusCode::OK;
499 }
500
doInternalHealthCheck()501 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::doInternalHealthCheck() {
502 VehicleHal::VehiclePropValuePtr v = nullptr;
503
504 // This is an example of very simpe health checking. VHAL is considered healthy if we can read
505 // PERF_VEHICLE_SPEED. The more comprehensive health checking is required.
506 VehiclePropValue propValue = {
507 .prop = static_cast<int32_t>(VehicleProperty::PERF_VEHICLE_SPEED),
508 };
509 auto internalPropValue = mPropStore->readValueOrNull(propValue);
510 if (internalPropValue != nullptr) {
511 v = createVhalHeartBeatProp();
512 } else {
513 ALOGW("VHAL health check failed");
514 }
515 return v;
516 }
517
createVhalHeartBeatProp()518 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createVhalHeartBeatProp() {
519 VehicleHal::VehiclePropValuePtr v = getValuePool()->obtainInt64(uptimeMillis());
520 v->prop = static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT);
521 v->areaId = 0;
522 v->status = VehiclePropertyStatus::AVAILABLE;
523 return v;
524 }
525
526 } // impl
527
528 } // namespace V2_0
529 } // namespace vehicle
530 } // namespace automotive
531 } // namespace hardware
532 } // namespace android
533