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/macros.h>
19 #include <android/log.h>
20 #include <sys/system_properties.h>
21 
22 #include "EmulatedVehicleHal.h"
23 #include "JsonFakeValueGenerator.h"
24 #include "LinearFakeValueGenerator.h"
25 #include "Obd2SensorStore.h"
26 
27 namespace android {
28 namespace hardware {
29 namespace automotive {
30 namespace vehicle {
31 namespace V2_0 {
32 
33 namespace impl {
34 
fillDefaultObd2Frame(size_t numVendorIntegerSensors,size_t numVendorFloatSensors)35 static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorIntegerSensors,
36                                                              size_t numVendorFloatSensors) {
37     std::unique_ptr<Obd2SensorStore> sensorStore(
38         new Obd2SensorStore(numVendorIntegerSensors, numVendorFloatSensors));
39 
40     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS,
41                                   toInt(Obd2FuelSystemStatus::CLOSED_LOOP));
42     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0);
43     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_MONITORS_SUPPORTED,
44                                   toInt(Obd2IgnitionMonitorKind::SPARK));
45     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_SPECIFIC_MONITORS,
46                                   Obd2CommonIgnitionMonitors::COMPONENTS_AVAILABLE |
47                                       Obd2CommonIgnitionMonitors::MISFIRE_AVAILABLE |
48                                       Obd2SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE |
49                                       Obd2SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE);
50     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35);
51     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS,
52                                   toInt(Obd2SecondaryAirStatus::FROM_OUTSIDE_OR_OFF));
53     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1);
54     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500);
55     sensorStore->setIntegerSensor(
56         DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0);
57     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51);
58     sensorStore->setIntegerSensor(
59         DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365);
60     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30);
61     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12);
62     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18);
63     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1);
64     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_TYPE,
65                                   toInt(Obd2FuelType::GASOLINE));
66     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153);
67     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16);
68     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16);
69     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16);
70     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16);
71     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5);
72     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ENGINE_RPM, 1250.);
73     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::VEHICLE_SPEED, 40.);
74     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::TIMING_ADVANCE, 2.5);
75     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::THROTTLE_POSITION, 19.75);
76     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265);
77     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824);
78     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE,
79                                 -0.373);
80     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1,
81                                 190.);
82     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.);
83     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306);
84     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188);
85     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094);
86     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024);
87 
88     return sensorStore;
89 }
90 
EmulatedVehicleHal(VehiclePropertyStore * propStore)91 EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
92     : mPropStore(propStore),
93       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
94       mRecurrentTimer(
95           std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
96       mGeneratorHub(
97           std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1)) {
98     initStaticConfig();
99     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
100         mPropStore->registerProperty(kVehicleProperties[i].config);
101     }
102 }
103 
get(const VehiclePropValue & requestedPropValue,StatusCode * outStatus)104 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
105         const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
106     auto propId = requestedPropValue.prop;
107     auto& pool = *getValuePool();
108     VehiclePropValuePtr v = nullptr;
109 
110     switch (propId) {
111         case OBD2_FREEZE_FRAME:
112             v = pool.obtainComplex();
113             *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
114             break;
115         case OBD2_FREEZE_FRAME_INFO:
116             v = pool.obtainComplex();
117             *outStatus = fillObd2DtcInfo(v.get());
118             break;
119         default:
120             auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
121             if (internalPropValue != nullptr) {
122                 v = getValuePool()->obtain(*internalPropValue);
123             }
124 
125             *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
126             break;
127     }
128 
129     return v;
130 }
131 
set(const VehiclePropValue & propValue)132 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
133     static constexpr bool shouldUpdateStatus = false;
134 
135     if (propValue.prop == kGenerateFakeDataControllingProperty) {
136         StatusCode status = handleGenerateFakeDataRequest(propValue);
137         if (status != StatusCode::OK) {
138             return status;
139         }
140     } else if (mHvacPowerProps.count(propValue.prop)) {
141         auto hvacPowerOn = mPropStore->readValueOrNull(
142             toInt(VehicleProperty::HVAC_POWER_ON),
143             (VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_1_RIGHT |
144              VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER |
145              VehicleAreaSeat::ROW_2_RIGHT));
146 
147         if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
148                 && hvacPowerOn->value.int32Values[0] == 0) {
149             return StatusCode::NOT_AVAILABLE;
150         }
151     } else {
152         // Handle property specific code
153         switch (propValue.prop) {
154             case OBD2_FREEZE_FRAME_CLEAR:
155                 return clearObd2FreezeFrames(propValue);
156             case VEHICLE_MAP_SERVICE:
157                 // Placeholder for future implementation of VMS property in the default hal. For
158                 // now, just returns OK; otherwise, hal clients crash with property not supported.
159                 return StatusCode::OK;
160             case AP_POWER_STATE_REPORT:
161                 switch (propValue.value.int32Values[0]) {
162                     case toInt(VehicleApPowerStateReport::DEEP_SLEEP_EXIT):
163                     case toInt(VehicleApPowerStateReport::SHUTDOWN_CANCELLED):
164                     case toInt(VehicleApPowerStateReport::WAIT_FOR_VHAL):
165                         // CPMS is in WAIT_FOR_VHAL state, simply move to ON
166                         doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::ON, 0));
167                         break;
168                     case toInt(VehicleApPowerStateReport::DEEP_SLEEP_ENTRY):
169                     case toInt(VehicleApPowerStateReport::SHUTDOWN_START):
170                         // CPMS is in WAIT_FOR_FINISH state, send the FINISHED command
171                         doHalEvent(createApPowerStateReq(VehicleApPowerStateReq::FINISHED, 0));
172                         break;
173                     case toInt(VehicleApPowerStateReport::ON):
174                     case toInt(VehicleApPowerStateReport::SHUTDOWN_POSTPONE):
175                     case toInt(VehicleApPowerStateReport::SHUTDOWN_PREPARE):
176                         // Do nothing
177                         break;
178                     default:
179                         // Unknown state
180                         break;
181                 }
182                 break;
183         }
184     }
185 
186     if (propValue.status != VehiclePropertyStatus::AVAILABLE) {
187         // Android side cannot set property status - this value is the
188         // purview of the HAL implementation to reflect the state of
189         // its underlying hardware
190         return StatusCode::INVALID_ARG;
191     }
192     auto currentPropValue = mPropStore->readValueOrNull(propValue);
193 
194     if (currentPropValue == nullptr) {
195         return StatusCode::INVALID_ARG;
196     }
197     if (currentPropValue->status != VehiclePropertyStatus::AVAILABLE) {
198         // do not allow Android side to set() a disabled/error property
199         return StatusCode::NOT_AVAILABLE;
200     }
201 
202     if (!mPropStore->writeValue(propValue, shouldUpdateStatus)) {
203         return StatusCode::INVALID_ARG;
204     }
205 
206     getEmulatorOrDie()->doSetValueFromClient(propValue);
207 
208     if (mInEmulator && propValue.prop == toInt(VehicleProperty::DISPLAY_BRIGHTNESS)) {
209         // Emulator does not support remote brightness control, b/139959479
210         // do not send it down so that it does not bring unnecessary property change event
211         // return other error code, such NOT_AVAILABLE, causes Emulator to be freezing
212         // TODO: return StatusCode::NOT_AVAILABLE once the above issue is fixed
213         return StatusCode::OK;
214     }
215 
216     doHalEvent(getValuePool()->obtain(propValue));
217     return StatusCode::OK;
218 }
219 
isDiagnosticProperty(VehiclePropConfig propConfig)220 static bool isDiagnosticProperty(VehiclePropConfig propConfig) {
221     switch (propConfig.prop) {
222         case OBD2_LIVE_FRAME:
223         case OBD2_FREEZE_FRAME:
224         case OBD2_FREEZE_FRAME_CLEAR:
225         case OBD2_FREEZE_FRAME_INFO:
226             return true;
227     }
228     return false;
229 }
230 
231 // determine if it's running inside Android Emulator
isInEmulator()232 static bool isInEmulator() {
233     char propValue[PROP_VALUE_MAX];
234     bool isEmulator = (__system_property_get("ro.kernel.qemu", propValue) != 0);
235     if (!isEmulator) {
236         isEmulator = (__system_property_get("ro.hardware", propValue) != 0) &&
237                      (!strcmp(propValue, "ranchu") || !strcmp(propValue, "goldfish"));
238     }
239     return isEmulator;
240 }
241 
242 // Parse supported properties list and generate vector of property values to hold current values.
onCreate()243 void EmulatedVehicleHal::onCreate() {
244     static constexpr bool shouldUpdateStatus = true;
245 
246     for (auto& it : kVehicleProperties) {
247         VehiclePropConfig cfg = it.config;
248         int32_t numAreas = cfg.areaConfigs.size();
249 
250         if (isDiagnosticProperty(cfg)) {
251             // do not write an initial empty value for the diagnostic properties
252             // as we will initialize those separately.
253             continue;
254         }
255 
256         // A global property will have only a single area
257         if (isGlobalProp(cfg.prop)) {
258             numAreas = 1;
259         }
260 
261         for (int i = 0; i < numAreas; i++) {
262             int32_t curArea;
263 
264             if (isGlobalProp(cfg.prop)) {
265                 curArea = 0;
266             } else {
267                 curArea = cfg.areaConfigs[i].areaId;
268             }
269 
270             // Create a separate instance for each individual zone
271             VehiclePropValue prop = {
272                     .areaId = curArea,
273                     .prop = cfg.prop,
274             };
275 
276             if (it.initialAreaValues.size() > 0) {
277                 auto valueForAreaIt = it.initialAreaValues.find(curArea);
278                 if (valueForAreaIt != it.initialAreaValues.end()) {
279                     prop.value = valueForAreaIt->second;
280                 } else {
281                     ALOGW("%s failed to get default value for prop 0x%x area 0x%x",
282                             __func__, cfg.prop, curArea);
283                 }
284             } else {
285                 prop.value = it.initialValue;
286             }
287             mPropStore->writeValue(prop, shouldUpdateStatus);
288         }
289     }
290     initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
291     initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
292     mInEmulator = isInEmulator();
293     ALOGD("mInEmulator=%s", mInEmulator ? "true" : "false");
294 }
295 
listProperties()296 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties()  {
297     return mPropStore->getAllConfigs();
298 }
299 
onContinuousPropertyTimer(const std::vector<int32_t> & properties)300 void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
301     VehiclePropValuePtr v;
302 
303     auto& pool = *getValuePool();
304 
305     for (int32_t property : properties) {
306         if (isContinuousProperty(property)) {
307             auto internalPropValue = mPropStore->readValueOrNull(property);
308             if (internalPropValue != nullptr) {
309                 v = pool.obtain(*internalPropValue);
310             }
311         } else {
312             ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
313         }
314 
315         if (v.get()) {
316             v->timestamp = elapsedRealtimeNano();
317             doHalEvent(std::move(v));
318         }
319     }
320 }
321 
subscribe(int32_t property,float sampleRate)322 StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
323     ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
324 
325     if (isContinuousProperty(property)) {
326         mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
327     }
328     return StatusCode::OK;
329 }
330 
unsubscribe(int32_t property)331 StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
332     ALOGI("%s propId: 0x%x", __func__, property);
333     if (isContinuousProperty(property)) {
334         mRecurrentTimer.unregisterRecurrentEvent(property);
335     }
336     return StatusCode::OK;
337 }
338 
isContinuousProperty(int32_t propId) const339 bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
340     const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId);
341     if (config == nullptr) {
342         ALOGW("Config not found for property: 0x%x", propId);
343         return false;
344     }
345     return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
346 }
347 
setPropertyFromVehicle(const VehiclePropValue & propValue)348 bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
349     static constexpr bool shouldUpdateStatus = true;
350 
351     if (propValue.prop == kGenerateFakeDataControllingProperty) {
352         StatusCode status = handleGenerateFakeDataRequest(propValue);
353         if (status != StatusCode::OK) {
354             return false;
355         }
356     }
357 
358     if (mPropStore->writeValue(propValue, shouldUpdateStatus)) {
359         doHalEvent(getValuePool()->obtain(propValue));
360         return true;
361     } else {
362         return false;
363     }
364 }
365 
getAllProperties() const366 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const  {
367     return mPropStore->readAllValues();
368 }
369 
handleGenerateFakeDataRequest(const VehiclePropValue & request)370 StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
371     ALOGI("%s", __func__);
372     const auto& v = request.value;
373     if (!v.int32Values.size()) {
374         ALOGE("%s: expected at least \"command\" field in int32Values", __func__);
375         return StatusCode::INVALID_ARG;
376     }
377 
378     FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
379 
380     switch (command) {
381         case FakeDataCommand::StartLinear: {
382             ALOGI("%s, FakeDataCommand::StartLinear", __func__);
383             if (v.int32Values.size() < 2) {
384                 ALOGE("%s: expected property ID in int32Values", __func__);
385                 return StatusCode::INVALID_ARG;
386             }
387             if (!v.int64Values.size()) {
388                 ALOGE("%s: interval is not provided in int64Values", __func__);
389                 return StatusCode::INVALID_ARG;
390             }
391             if (v.floatValues.size() < 3) {
392                 ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
393                       v.floatValues.size());
394                 return StatusCode::INVALID_ARG;
395             }
396             int32_t cookie = v.int32Values[1];
397             mGeneratorHub.registerGenerator(cookie,
398                                             std::make_unique<LinearFakeValueGenerator>(request));
399             break;
400         }
401         case FakeDataCommand::StartJson: {
402             ALOGI("%s, FakeDataCommand::StartJson", __func__);
403             if (v.stringValue.empty()) {
404                 ALOGE("%s: path to JSON file is missing", __func__);
405                 return StatusCode::INVALID_ARG;
406             }
407             int32_t cookie = std::hash<std::string>()(v.stringValue);
408             mGeneratorHub.registerGenerator(cookie,
409                                             std::make_unique<JsonFakeValueGenerator>(request));
410             break;
411         }
412         case FakeDataCommand::StopLinear: {
413             ALOGI("%s, FakeDataCommand::StopLinear", __func__);
414             if (v.int32Values.size() < 2) {
415                 ALOGE("%s: expected property ID in int32Values", __func__);
416                 return StatusCode::INVALID_ARG;
417             }
418             int32_t cookie = v.int32Values[1];
419             mGeneratorHub.unregisterGenerator(cookie);
420             break;
421         }
422         case FakeDataCommand::StopJson: {
423             ALOGI("%s, FakeDataCommand::StopJson", __func__);
424             if (v.stringValue.empty()) {
425                 ALOGE("%s: path to JSON file is missing", __func__);
426                 return StatusCode::INVALID_ARG;
427             }
428             int32_t cookie = std::hash<std::string>()(v.stringValue);
429             mGeneratorHub.unregisterGenerator(cookie);
430             break;
431         }
432         case FakeDataCommand::KeyPress: {
433             ALOGI("%s, FakeDataCommand::KeyPress", __func__);
434             int32_t keyCode = request.value.int32Values[2];
435             int32_t display = request.value.int32Values[3];
436             doHalEvent(
437                 createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_DOWN, keyCode, display));
438             doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
439             break;
440         }
441         default: {
442             ALOGE("%s: unexpected command: %d", __func__, command);
443             return StatusCode::INVALID_ARG;
444         }
445     }
446     return StatusCode::OK;
447 }
448 
createApPowerStateReq(VehicleApPowerStateReq state,int32_t param)449 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createApPowerStateReq(
450     VehicleApPowerStateReq state, int32_t param) {
451     auto req = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 2);
452     req->prop = toInt(VehicleProperty::AP_POWER_STATE_REQ);
453     req->areaId = 0;
454     req->timestamp = elapsedRealtimeNano();
455     req->status = VehiclePropertyStatus::AVAILABLE;
456     req->value.int32Values[0] = toInt(state);
457     req->value.int32Values[1] = param;
458     return req;
459 }
460 
createHwInputKeyProp(VehicleHwKeyInputAction action,int32_t keyCode,int32_t targetDisplay)461 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
462     VehicleHwKeyInputAction action, int32_t keyCode, int32_t targetDisplay) {
463     auto keyEvent = getValuePool()->obtain(VehiclePropertyType::INT32_VEC, 3);
464     keyEvent->prop = toInt(VehicleProperty::HW_KEY_INPUT);
465     keyEvent->areaId = 0;
466     keyEvent->timestamp = elapsedRealtimeNano();
467     keyEvent->status = VehiclePropertyStatus::AVAILABLE;
468     keyEvent->value.int32Values[0] = toInt(action);
469     keyEvent->value.int32Values[1] = keyCode;
470     keyEvent->value.int32Values[2] = targetDisplay;
471     return keyEvent;
472 }
473 
onFakeValueGenerated(const VehiclePropValue & value)474 void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) {
475     ALOGD("%s: %s", __func__, toString(value).c_str());
476     static constexpr bool shouldUpdateStatus = false;
477 
478     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
479     if (updatedPropValue) {
480         updatedPropValue->timestamp = elapsedRealtimeNano();
481         updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
482         mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
483         auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
484         if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
485             doHalEvent(std::move(updatedPropValue));
486         }
487     }
488 }
489 
initStaticConfig()490 void EmulatedVehicleHal::initStaticConfig() {
491     for (auto&& it = std::begin(kVehicleProperties); it != std::end(kVehicleProperties); ++it) {
492         const auto& cfg = it->config;
493         VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
494 
495         switch (cfg.prop) {
496             case OBD2_FREEZE_FRAME: {
497                 tokenFunction = [](const VehiclePropValue& propValue) {
498                     return propValue.timestamp;
499                 };
500                 break;
501             }
502             default:
503                 break;
504         }
505 
506         mPropStore->registerProperty(cfg, tokenFunction);
507     }
508 }
509 
initObd2LiveFrame(const VehiclePropConfig & propConfig)510 void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) {
511     static constexpr bool shouldUpdateStatus = true;
512 
513     auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
514     auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
515                                             static_cast<size_t>(propConfig.configArray[1]));
516     sensorStore->fillPropValue("", liveObd2Frame.get());
517     liveObd2Frame->prop = OBD2_LIVE_FRAME;
518 
519     mPropStore->writeValue(*liveObd2Frame, shouldUpdateStatus);
520 }
521 
initObd2FreezeFrame(const VehiclePropConfig & propConfig)522 void EmulatedVehicleHal::initObd2FreezeFrame(const VehiclePropConfig& propConfig) {
523     static constexpr bool shouldUpdateStatus = true;
524 
525     auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
526                                             static_cast<size_t>(propConfig.configArray[1]));
527 
528     static std::vector<std::string> sampleDtcs = {"P0070",
529                                                   "P0102"
530                                                   "P0123"};
531     for (auto&& dtc : sampleDtcs) {
532         auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
533         sensorStore->fillPropValue(dtc, freezeFrame.get());
534         freezeFrame->prop = OBD2_FREEZE_FRAME;
535 
536         mPropStore->writeValue(*freezeFrame, shouldUpdateStatus);
537     }
538 }
539 
fillObd2FreezeFrame(const VehiclePropValue & requestedPropValue,VehiclePropValue * outValue)540 StatusCode EmulatedVehicleHal::fillObd2FreezeFrame(const VehiclePropValue& requestedPropValue,
541                                                    VehiclePropValue* outValue) {
542     if (requestedPropValue.value.int64Values.size() != 1) {
543         ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp");
544         return StatusCode::INVALID_ARG;
545     }
546     auto timestamp = requestedPropValue.value.int64Values[0];
547     auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
548     if (freezeFrame == nullptr) {
549         ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
550         return StatusCode::INVALID_ARG;
551     }
552     outValue->prop = OBD2_FREEZE_FRAME;
553     outValue->value.int32Values = freezeFrame->value.int32Values;
554     outValue->value.floatValues = freezeFrame->value.floatValues;
555     outValue->value.bytes = freezeFrame->value.bytes;
556     outValue->value.stringValue = freezeFrame->value.stringValue;
557     outValue->timestamp = freezeFrame->timestamp;
558     return StatusCode::OK;
559 }
560 
clearObd2FreezeFrames(const VehiclePropValue & propValue)561 StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
562     if (propValue.value.int64Values.size() == 0) {
563         mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
564         return StatusCode::OK;
565     } else {
566         for (int64_t timestamp : propValue.value.int64Values) {
567             auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
568             if (freezeFrame == nullptr) {
569                 ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
570                 return StatusCode::INVALID_ARG;
571             }
572             mPropStore->removeValue(*freezeFrame);
573         }
574     }
575     return StatusCode::OK;
576 }
577 
fillObd2DtcInfo(VehiclePropValue * outValue)578 StatusCode EmulatedVehicleHal::fillObd2DtcInfo(VehiclePropValue* outValue) {
579     std::vector<int64_t> timestamps;
580     for (const auto& freezeFrame : mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) {
581         timestamps.push_back(freezeFrame.timestamp);
582     }
583     outValue->value.int64Values = timestamps;
584     outValue->prop = OBD2_FREEZE_FRAME_INFO;
585     return StatusCode::OK;
586 }
587 
588 }  // impl
589 
590 }  // namespace V2_0
591 }  // namespace vehicle
592 }  // namespace automotive
593 }  // namespace hardware
594 }  // namespace android
595