• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/log.h>
19 #include <android-base/macros.h>
20 
21 #include "EmulatedVehicleHal.h"
22 #include "JsonFakeValueGenerator.h"
23 #include "LinearFakeValueGenerator.h"
24 #include "Obd2SensorStore.h"
25 
26 namespace android {
27 namespace hardware {
28 namespace automotive {
29 namespace vehicle {
30 namespace V2_0 {
31 
32 namespace impl {
33 
fillDefaultObd2Frame(size_t numVendorIntegerSensors,size_t numVendorFloatSensors)34 static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorIntegerSensors,
35                                                              size_t numVendorFloatSensors) {
36     std::unique_ptr<Obd2SensorStore> sensorStore(
37         new Obd2SensorStore(numVendorIntegerSensors, numVendorFloatSensors));
38 
39     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_SYSTEM_STATUS,
40                                   toInt(Obd2FuelSystemStatus::CLOSED_LOOP));
41     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MALFUNCTION_INDICATOR_LIGHT_ON, 0);
42     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_MONITORS_SUPPORTED,
43                                   toInt(Obd2IgnitionMonitorKind::SPARK));
44     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::IGNITION_SPECIFIC_MONITORS,
45                                   Obd2CommonIgnitionMonitors::COMPONENTS_AVAILABLE |
46                                       Obd2CommonIgnitionMonitors::MISFIRE_AVAILABLE |
47                                       Obd2SparkIgnitionMonitors::AC_REFRIGERANT_AVAILABLE |
48                                       Obd2SparkIgnitionMonitors::EVAPORATIVE_SYSTEM_AVAILABLE);
49     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::INTAKE_AIR_TEMPERATURE, 35);
50     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::COMMANDED_SECONDARY_AIR_STATUS,
51                                   toInt(Obd2SecondaryAirStatus::FROM_OUTSIDE_OR_OFF));
52     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::NUM_OXYGEN_SENSORS_PRESENT, 1);
53     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::RUNTIME_SINCE_ENGINE_START, 500);
54     sensorStore->setIntegerSensor(
55         DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_WITH_MALFUNCTION_INDICATOR_LIGHT_ON, 0);
56     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::WARMUPS_SINCE_CODES_CLEARED, 51);
57     sensorStore->setIntegerSensor(
58         DiagnosticIntegerSensorIndex::DISTANCE_TRAVELED_SINCE_CODES_CLEARED, 365);
59     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::ABSOLUTE_BAROMETRIC_PRESSURE, 30);
60     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::CONTROL_MODULE_VOLTAGE, 12);
61     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::AMBIENT_AIR_TEMPERATURE, 18);
62     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::MAX_FUEL_AIR_EQUIVALENCE_RATIO, 1);
63     sensorStore->setIntegerSensor(DiagnosticIntegerSensorIndex::FUEL_TYPE,
64                                   toInt(Obd2FuelType::GASOLINE));
65     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CALCULATED_ENGINE_LOAD, 0.153);
66     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK1, -0.16);
67     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK1, -0.16);
68     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::SHORT_TERM_FUEL_TRIM_BANK2, -0.16);
69     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::LONG_TERM_FUEL_TRIM_BANK2, -0.16);
70     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::INTAKE_MANIFOLD_ABSOLUTE_PRESSURE, 7.5);
71     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ENGINE_RPM, 1250.);
72     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::VEHICLE_SPEED, 40.);
73     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::TIMING_ADVANCE, 2.5);
74     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::THROTTLE_POSITION, 19.75);
75     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::OXYGEN_SENSOR1_VOLTAGE, 0.265);
76     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::FUEL_TANK_LEVEL_INPUT, 0.824);
77     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::EVAPORATION_SYSTEM_VAPOR_PRESSURE,
78                                 -0.373);
79     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::CATALYST_TEMPERATURE_BANK1_SENSOR1,
80                                 190.);
81     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::RELATIVE_THROTTLE_POSITION, 3.);
82     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ABSOLUTE_THROTTLE_POSITION_B, 0.306);
83     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_D, 0.188);
84     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::ACCELERATOR_PEDAL_POSITION_E, 0.094);
85     sensorStore->setFloatSensor(DiagnosticFloatSensorIndex::COMMANDED_THROTTLE_ACTUATOR, 0.024);
86 
87     return sensorStore;
88 }
89 
EmulatedVehicleHal(VehiclePropertyStore * propStore,VehicleHalClient * client,EmulatedUserHal * emulatedUserHal)90 EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore, VehicleHalClient* client,
91                                        EmulatedUserHal* emulatedUserHal)
92     : mPropStore(propStore),
93       mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
94       mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this,
95                                 std::placeholders::_1)),
96       mVehicleClient(client),
97       mEmulatedUserHal(emulatedUserHal) {
98     initStaticConfig();
99     for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
100         mPropStore->registerProperty(kVehicleProperties[i].config);
101     }
102     mVehicleClient->registerPropertyValueCallback(std::bind(&EmulatedVehicleHal::onPropertyValue,
103                                                             this, std::placeholders::_1,
104                                                             std::placeholders::_2));
105 }
106 
get(const VehiclePropValue & requestedPropValue,StatusCode * outStatus)107 VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::get(
108         const VehiclePropValue& requestedPropValue, StatusCode* outStatus) {
109     auto propId = requestedPropValue.prop;
110     ALOGV("get(%d)", propId);
111 
112     auto& pool = *getValuePool();
113     VehiclePropValuePtr v = nullptr;
114 
115     switch (propId) {
116         case OBD2_FREEZE_FRAME:
117             v = pool.obtainComplex();
118             *outStatus = fillObd2FreezeFrame(requestedPropValue, v.get());
119             break;
120         case OBD2_FREEZE_FRAME_INFO:
121             v = pool.obtainComplex();
122             *outStatus = fillObd2DtcInfo(v.get());
123             break;
124         default:
125             if (mEmulatedUserHal != nullptr && mEmulatedUserHal->isSupported(propId)) {
126                 ALOGI("get(): getting value for prop %d from User HAL", propId);
127                 const auto& ret = mEmulatedUserHal->onGetProperty(requestedPropValue);
128                 if (!ret.ok()) {
129                     ALOGE("get(): User HAL returned error: %s", ret.error().message().c_str());
130                     *outStatus = StatusCode(ret.error().code());
131                 } else {
132                     auto value = ret.value().get();
133                     if (value != nullptr) {
134                         ALOGI("get(): User HAL returned value: %s", toString(*value).c_str());
135                         v = getValuePool()->obtain(*value);
136                         *outStatus = StatusCode::OK;
137                     } else {
138                         ALOGE("get(): User HAL returned null value");
139                         *outStatus = StatusCode::INTERNAL_ERROR;
140                     }
141                 }
142                 break;
143             }
144 
145             auto internalPropValue = mPropStore->readValueOrNull(requestedPropValue);
146             if (internalPropValue != nullptr) {
147                 v = getValuePool()->obtain(*internalPropValue);
148             }
149 
150             *outStatus = v != nullptr ? StatusCode::OK : StatusCode::INVALID_ARG;
151             break;
152     }
153     if (v.get()) {
154         v->timestamp = elapsedRealtimeNano();
155     }
156     return v;
157 }
158 
dump(const hidl_handle & fd,const hidl_vec<hidl_string> & options)159 bool EmulatedVehicleHal::dump(const hidl_handle& fd, const hidl_vec<hidl_string>& options) {
160     return mVehicleClient->dump(fd, options);
161 }
162 
set(const VehiclePropValue & propValue)163 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
164     constexpr bool updateStatus = false;
165 
166     if (propValue.prop == kGenerateFakeDataControllingProperty) {
167         // Send the generator controlling request to the server.
168         // 'updateStatus' flag is only for the value sent by setProperty (propValue in this case)
169         // instead of the generated values triggered by it. 'propValue' works as a control signal
170         // here, since we never send the control signal back, the value of 'updateStatus' flag
171         // does not matter here.
172         auto status = mVehicleClient->setProperty(propValue, updateStatus);
173         return status;
174     } else if (mHvacPowerProps.count(propValue.prop)) {
175         auto hvacPowerOn = mPropStore->readValueOrNull(
176             toInt(VehicleProperty::HVAC_POWER_ON),
177             (VehicleAreaSeat::ROW_1_LEFT | VehicleAreaSeat::ROW_1_RIGHT |
178              VehicleAreaSeat::ROW_2_LEFT | VehicleAreaSeat::ROW_2_CENTER |
179              VehicleAreaSeat::ROW_2_RIGHT));
180 
181         if (hvacPowerOn && hvacPowerOn->value.int32Values.size() == 1
182                 && hvacPowerOn->value.int32Values[0] == 0) {
183             return StatusCode::NOT_AVAILABLE;
184         }
185     } else {
186         // Handle property specific code
187         switch (propValue.prop) {
188             case OBD2_FREEZE_FRAME_CLEAR:
189                 return clearObd2FreezeFrames(propValue);
190             case VEHICLE_MAP_SERVICE:
191                 // Placeholder for future implementation of VMS property in the default hal. For
192                 // now, just returns OK; otherwise, hal clients crash with property not supported.
193                 return StatusCode::OK;
194         }
195     }
196 
197     if (propValue.status != VehiclePropertyStatus::AVAILABLE) {
198         // Android side cannot set property status - this value is the
199         // purview of the HAL implementation to reflect the state of
200         // its underlying hardware
201         return StatusCode::INVALID_ARG;
202     }
203     auto currentPropValue = mPropStore->readValueOrNull(propValue);
204 
205     if (currentPropValue == nullptr) {
206         return StatusCode::INVALID_ARG;
207     }
208     if (currentPropValue->status != VehiclePropertyStatus::AVAILABLE) {
209         // do not allow Android side to set() a disabled/error property
210         return StatusCode::NOT_AVAILABLE;
211     }
212 
213     /**
214      * After checking all conditions, such as the property is available, a real vhal will
215      * sent the events to Car ECU to take actions.
216      */
217 
218     // Send the value to the vehicle server, the server will talk to the (real or emulated) car
219     auto setValueStatus = mVehicleClient->setProperty(propValue, updateStatus);
220     if (setValueStatus != StatusCode::OK) {
221         return setValueStatus;
222     }
223 
224     return StatusCode::OK;
225 }
226 
isDiagnosticProperty(VehiclePropConfig propConfig)227 static bool isDiagnosticProperty(VehiclePropConfig propConfig) {
228     switch (propConfig.prop) {
229         case OBD2_LIVE_FRAME:
230         case OBD2_FREEZE_FRAME:
231         case OBD2_FREEZE_FRAME_CLEAR:
232         case OBD2_FREEZE_FRAME_INFO:
233             return true;
234     }
235     return false;
236 }
237 
238 // Parse supported properties list and generate vector of property values to hold current values.
onCreate()239 void EmulatedVehicleHal::onCreate() {
240     static constexpr bool shouldUpdateStatus = true;
241 
242     for (auto& it : kVehicleProperties) {
243         VehiclePropConfig cfg = it.config;
244         int32_t numAreas = cfg.areaConfigs.size();
245 
246         if (isDiagnosticProperty(cfg)) {
247             // do not write an initial empty value for the diagnostic properties
248             // as we will initialize those separately.
249             continue;
250         }
251 
252         // A global property will have only a single area
253         if (isGlobalProp(cfg.prop)) {
254             numAreas = 1;
255         }
256 
257         for (int i = 0; i < numAreas; i++) {
258             int32_t curArea;
259 
260             if (isGlobalProp(cfg.prop)) {
261                 curArea = 0;
262             } else {
263                 curArea = cfg.areaConfigs[i].areaId;
264             }
265 
266             // Create a separate instance for each individual zone
267             VehiclePropValue prop = {
268                     .areaId = curArea,
269                     .prop = cfg.prop,
270             };
271 
272             if (it.initialAreaValues.size() > 0) {
273                 auto valueForAreaIt = it.initialAreaValues.find(curArea);
274                 if (valueForAreaIt != it.initialAreaValues.end()) {
275                     prop.value = valueForAreaIt->second;
276                 } else {
277                     ALOGW("%s failed to get default value for prop 0x%x area 0x%x",
278                             __func__, cfg.prop, curArea);
279                 }
280             } else {
281                 prop.value = it.initialValue;
282             }
283             mPropStore->writeValue(prop, shouldUpdateStatus);
284         }
285     }
286     initObd2LiveFrame(*mPropStore->getConfigOrDie(OBD2_LIVE_FRAME));
287     initObd2FreezeFrame(*mPropStore->getConfigOrDie(OBD2_FREEZE_FRAME));
288 }
289 
listProperties()290 std::vector<VehiclePropConfig> EmulatedVehicleHal::listProperties()  {
291     return mPropStore->getAllConfigs();
292 }
293 
onContinuousPropertyTimer(const std::vector<int32_t> & properties)294 void EmulatedVehicleHal::onContinuousPropertyTimer(const std::vector<int32_t>& properties) {
295     VehiclePropValuePtr v;
296 
297     auto& pool = *getValuePool();
298 
299     for (int32_t property : properties) {
300         if (isContinuousProperty(property)) {
301             auto internalPropValue = mPropStore->readValueOrNull(property);
302             if (internalPropValue != nullptr) {
303                 v = pool.obtain(*internalPropValue);
304             }
305         } else {
306             ALOGE("Unexpected onContinuousPropertyTimer for property: 0x%x", property);
307         }
308 
309         if (v.get()) {
310             v->timestamp = elapsedRealtimeNano();
311             doHalEvent(std::move(v));
312         }
313     }
314 }
315 
subscribe(int32_t property,float sampleRate)316 StatusCode EmulatedVehicleHal::subscribe(int32_t property, float sampleRate) {
317     ALOGI("%s propId: 0x%x, sampleRate: %f", __func__, property, sampleRate);
318 
319     if (isContinuousProperty(property)) {
320         mRecurrentTimer.registerRecurrentEvent(hertzToNanoseconds(sampleRate), property);
321     }
322     return StatusCode::OK;
323 }
324 
unsubscribe(int32_t property)325 StatusCode EmulatedVehicleHal::unsubscribe(int32_t property) {
326     ALOGI("%s propId: 0x%x", __func__, property);
327     if (isContinuousProperty(property)) {
328         mRecurrentTimer.unregisterRecurrentEvent(property);
329     }
330     return StatusCode::OK;
331 }
332 
isContinuousProperty(int32_t propId) const333 bool EmulatedVehicleHal::isContinuousProperty(int32_t propId) const {
334     const VehiclePropConfig* config = mPropStore->getConfigOrNull(propId);
335     if (config == nullptr) {
336         ALOGW("Config not found for property: 0x%x", propId);
337         return false;
338     }
339     return config->changeMode == VehiclePropertyChangeMode::CONTINUOUS;
340 }
341 
setPropertyFromVehicle(const VehiclePropValue & propValue)342 bool EmulatedVehicleHal::setPropertyFromVehicle(const VehiclePropValue& propValue) {
343     constexpr bool updateStatus = true;
344     return mVehicleClient->setProperty(propValue, updateStatus) == StatusCode::OK;
345 }
346 
getAllProperties() const347 std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const  {
348     return mPropStore->readAllValues();
349 }
350 
onPropertyValue(const VehiclePropValue & value,bool updateStatus)351 void EmulatedVehicleHal::onPropertyValue(const VehiclePropValue& value, bool updateStatus) {
352     VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
353 
354     if (mPropStore->writeValue(*updatedPropValue, updateStatus)) {
355         getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
356         doHalEvent(std::move(updatedPropValue));
357     }
358 }
359 
initStaticConfig()360 void EmulatedVehicleHal::initStaticConfig() {
361     for (auto&& it = std::begin(kVehicleProperties); it != std::end(kVehicleProperties); ++it) {
362         const auto& cfg = it->config;
363         VehiclePropertyStore::TokenFunction tokenFunction = nullptr;
364 
365         switch (cfg.prop) {
366             case OBD2_FREEZE_FRAME: {
367                 tokenFunction = [](const VehiclePropValue& propValue) {
368                     return propValue.timestamp;
369                 };
370                 break;
371             }
372             default:
373                 break;
374         }
375 
376         mPropStore->registerProperty(cfg, tokenFunction);
377     }
378 }
379 
initObd2LiveFrame(const VehiclePropConfig & propConfig)380 void EmulatedVehicleHal::initObd2LiveFrame(const VehiclePropConfig& propConfig) {
381     static constexpr bool shouldUpdateStatus = true;
382 
383     auto liveObd2Frame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
384     auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
385                                             static_cast<size_t>(propConfig.configArray[1]));
386     sensorStore->fillPropValue("", liveObd2Frame.get());
387     liveObd2Frame->prop = OBD2_LIVE_FRAME;
388 
389     mPropStore->writeValue(*liveObd2Frame, shouldUpdateStatus);
390 }
391 
initObd2FreezeFrame(const VehiclePropConfig & propConfig)392 void EmulatedVehicleHal::initObd2FreezeFrame(const VehiclePropConfig& propConfig) {
393     static constexpr bool shouldUpdateStatus = true;
394 
395     auto sensorStore = fillDefaultObd2Frame(static_cast<size_t>(propConfig.configArray[0]),
396                                             static_cast<size_t>(propConfig.configArray[1]));
397 
398     static std::vector<std::string> sampleDtcs = {"P0070",
399                                                   "P0102"
400                                                   "P0123"};
401     for (auto&& dtc : sampleDtcs) {
402         auto freezeFrame = createVehiclePropValue(VehiclePropertyType::MIXED, 0);
403         sensorStore->fillPropValue(dtc, freezeFrame.get());
404         freezeFrame->prop = OBD2_FREEZE_FRAME;
405 
406         mPropStore->writeValue(*freezeFrame, shouldUpdateStatus);
407     }
408 }
409 
fillObd2FreezeFrame(const VehiclePropValue & requestedPropValue,VehiclePropValue * outValue)410 StatusCode EmulatedVehicleHal::fillObd2FreezeFrame(const VehiclePropValue& requestedPropValue,
411                                                    VehiclePropValue* outValue) {
412     if (requestedPropValue.value.int64Values.size() != 1) {
413         ALOGE("asked for OBD2_FREEZE_FRAME without valid timestamp");
414         return StatusCode::INVALID_ARG;
415     }
416     auto timestamp = requestedPropValue.value.int64Values[0];
417     auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
418     if (freezeFrame == nullptr) {
419         ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
420         return StatusCode::INVALID_ARG;
421     }
422     outValue->prop = OBD2_FREEZE_FRAME;
423     outValue->value.int32Values = freezeFrame->value.int32Values;
424     outValue->value.floatValues = freezeFrame->value.floatValues;
425     outValue->value.bytes = freezeFrame->value.bytes;
426     outValue->value.stringValue = freezeFrame->value.stringValue;
427     outValue->timestamp = freezeFrame->timestamp;
428     return StatusCode::OK;
429 }
430 
clearObd2FreezeFrames(const VehiclePropValue & propValue)431 StatusCode EmulatedVehicleHal::clearObd2FreezeFrames(const VehiclePropValue& propValue) {
432     if (propValue.value.int64Values.size() == 0) {
433         mPropStore->removeValuesForProperty(OBD2_FREEZE_FRAME);
434         return StatusCode::OK;
435     } else {
436         for (int64_t timestamp : propValue.value.int64Values) {
437             auto freezeFrame = mPropStore->readValueOrNull(OBD2_FREEZE_FRAME, 0, timestamp);
438             if (freezeFrame == nullptr) {
439                 ALOGE("asked for OBD2_FREEZE_FRAME at invalid timestamp");
440                 return StatusCode::INVALID_ARG;
441             }
442             mPropStore->removeValue(*freezeFrame);
443         }
444     }
445     return StatusCode::OK;
446 }
447 
fillObd2DtcInfo(VehiclePropValue * outValue)448 StatusCode EmulatedVehicleHal::fillObd2DtcInfo(VehiclePropValue* outValue) {
449     std::vector<int64_t> timestamps;
450     for (const auto& freezeFrame : mPropStore->readValuesForProperty(OBD2_FREEZE_FRAME)) {
451         timestamps.push_back(freezeFrame.timestamp);
452     }
453     outValue->value.int64Values = timestamps;
454     outValue->prop = OBD2_FREEZE_FRAME_INFO;
455     return StatusCode::OK;
456 }
457 
458 }  // impl
459 
460 }  // namespace V2_0
461 }  // namespace vehicle
462 }  // namespace automotive
463 }  // namespace hardware
464 }  // namespace android
465