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