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