summaryrefslogtreecommitdiffstats
path: root/automotive
diff options
context:
space:
mode:
authorChao Yan <aceyansf@google.com>2018-04-17 11:32:39 -0700
committerChao Yan <aceyansf@google.com>2018-05-10 11:05:28 -0700
commitf63c2cad23924ec0f62d534bbe88350c5088d579 (patch)
tree16f437859c101b7c8c9871b0cfc83bc6834d9c11 /automotive
parentadf9e18c01c3bf25858aacc380c16aa465b0ef34 (diff)
downloadplatform_hardware_interfaces-f63c2cad23924ec0f62d534bbe88350c5088d579.tar.gz
platform_hardware_interfaces-f63c2cad23924ec0f62d534bbe88350c5088d579.tar.bz2
platform_hardware_interfaces-f63c2cad23924ec0f62d534bbe88350c5088d579.zip
Added fake VHAL value generator based on JSON file
Note: It only supports a single generation task at any time. Mixed value properties like diagnostics frame is not implemented yet. It only supports properties with ON_CHANGE mode for now. Bug: 76017041 Test: lunch bat_land-userdebug & m -j8; adb push <json_data> /data/local/tmp; use python emulator to inject fake value "start" command specifying the JSON data path on device; verify values on KitchenSink app Change-Id: Ic964ef52a19422bab7015fe54c7e4c5ef8b47a55
Diffstat (limited to 'automotive')
-rw-r--r--automotive/vehicle/2.0/default/Android.bp4
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h62
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp80
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h8
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h108
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp174
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h76
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp135
-rw-r--r--automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h70
9 files changed, 557 insertions, 160 deletions
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 774bc4f8cb..22ab079f33 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -62,6 +62,8 @@ cc_library_static {
"impl/vhal_v2_0/VehicleEmulator.cpp",
"impl/vhal_v2_0/PipeComm.cpp",
"impl/vhal_v2_0/SocketComm.cpp",
+ "impl/vhal_v2_0/LinearFakeValueGenerator.cpp",
+ "impl/vhal_v2_0/JsonFakeValueGenerator.cpp",
],
local_include_dirs: ["common/include/vhal_v2_0"],
export_include_dirs: ["impl"],
@@ -71,6 +73,7 @@ cc_library_static {
"libprotobuf-cpp-lite",
],
static_libs: [
+ "libjsoncpp",
"libqemu_pipe",
"android.hardware.automotive.vehicle@2.0-libproto-native",
],
@@ -107,6 +110,7 @@ cc_binary {
"android.hardware.automotive.vehicle@2.0-manager-lib",
"android.hardware.automotive.vehicle@2.0-default-impl-lib",
"android.hardware.automotive.vehicle@2.0-libproto-native",
+ "libjsoncpp",
"libqemu_pipe",
],
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 56813ce414..6236087da2 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -42,38 +42,66 @@ constexpr int WHEEL_TICK = (int)VehicleProperty::WHEEL_TICK;
constexpr int ALL_WHEELS =
(int)(Wheel::LEFT_FRONT | Wheel::RIGHT_FRONT | Wheel::LEFT_REAR | Wheel::RIGHT_REAR);
-/*
- * This property is used for test purpose to generate fake events.
- *
- * It has the following format:
- *
- * int32Values[0] - command (see FakeDataCommand below for possible values)
- * int32Values[1] - VehicleProperty to which command applies
+/**
+ * This property is used for test purpose to generate fake events. Here is the test package that
+ * is referencing this property definition: packages/services/Car/tests/vehiclehal_test
*/
const int32_t kGenerateFakeDataControllingProperty =
0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * FakeDataCommand enum defines the supported command type for kGenerateFakeDataControllingProperty.
+ * All those commands can be send independently with each other. And each will override the one sent
+ * previously.
+ *
+ * The controlling property has the following format:
+ *
+ * int32Values[0] - command enum defined in FakeDataCommand
+ *
+ * The format of the arguments is defined for each command type as below:
+ */
enum class FakeDataCommand : int32_t {
- /** Stops generating of fake data that was triggered by Start command */
- Stop = 0,
-
/**
- * Starts fake data generation. Caller must provide additional data:
+ * Starts linear fake data generation. Caller must provide additional data:
+ * int32Values[1] - VehicleProperty to which command applies
* int64Values[0] - periodic interval in nanoseconds
* floatValues[0] - initial value
- * floatValues[1] - dispersion defines min and max range relative to initial value
+ * floatValues[1] - dispersion defines the min/max value relative to initial value, where
+ * max = initial_value + dispersion, min = initial_value - dispersion.
+ * Dispersion should be non-negative, otherwise the behavior is undefined.
* floatValues[2] - increment, with every timer tick the value will be incremented by this
- * amount
+ * amount. When reaching to max value, the current value will be set to min.
+ * It should be non-negative, otherwise the behavior is undefined.
+ */
+ StartLinear = 0,
+
+ /** Stops generating of fake data that was triggered by Start commands.
+ * int32Values[1] - VehicleProperty to which command applies. VHAL will stop the
+ * corresponding linear generation for that property.
+ */
+ StopLinear = 1,
+
+ /**
+ * Starts JSON-based fake data generation. Caller must provide a string value specifying
+ * the path to fake value JSON file:
+ * stringValue - path to the fake values JSON file
+ */
+ StartJson = 2,
+
+ /**
+ * Stops JSON-based fake data generation. No additional arguments needed.
*/
- Start = 1,
+ StopJson = 3,
/**
* Injects key press event (HAL incorporates UP/DOWN acction and triggers 2 HAL events for every
- * key-press). Caller must provide the following data: int32Values[2] - Android key code
+ * key-press). We set the enum with high number to leave space for future start/stop commands.
+ * Caller must provide the following data:
+ * int32Values[2] - Android key code
* int32Values[3] - target display (0 - for main display, 1 - for instrument cluster, see
- * VehicleDisplay)
+ * VehicleDisplay)
*/
- KeyPress = 2,
+ KeyPress = 100,
};
const int32_t kHvacPowerProperties[] = {
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index 2eb905dce1..fb54195852 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -19,6 +19,8 @@
#include <android-base/macros.h>
#include "EmulatedVehicleHal.h"
+#include "JsonFakeValueGenerator.h"
+#include "LinearFakeValueGenerator.h"
#include "Obd2SensorStore.h"
namespace android {
@@ -88,10 +90,12 @@ static std::unique_ptr<Obd2SensorStore> fillDefaultObd2Frame(size_t numVendorInt
EmulatedVehicleHal::EmulatedVehicleHal(VehiclePropertyStore* propStore)
: mPropStore(propStore),
mHvacPowerProps(std::begin(kHvacPowerProperties), std::end(kHvacPowerProperties)),
- mRecurrentTimer(std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer,
- this, std::placeholders::_1)),
- mFakeValueGenerator(std::bind(&EmulatedVehicleHal::onFakeValueGenerated,
- this, std::placeholders::_1, std::placeholders::_2)) {
+ mRecurrentTimer(
+ std::bind(&EmulatedVehicleHal::onContinuousPropertyTimer, this, std::placeholders::_1)),
+ mLinearFakeValueGenerator(std::make_unique<LinearFakeValueGenerator>(
+ std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))),
+ mJsonFakeValueGenerator(std::make_unique<JsonFakeValueGenerator>(
+ std::bind(&EmulatedVehicleHal::onFakeValueGenerated, this, std::placeholders::_1))) {
initStaticConfig();
for (size_t i = 0; i < arraysize(kVehicleProperties); i++) {
mPropStore->registerProperty(kVehicleProperties[i].config);
@@ -328,42 +332,29 @@ std::vector<VehiclePropValue> EmulatedVehicleHal::getAllProperties() const {
StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropValue& request) {
ALOGI("%s", __func__);
const auto& v = request.value;
- if (v.int32Values.size() < 2) {
- ALOGE("%s: expected at least 2 elements in int32Values, got: %zu", __func__,
- v.int32Values.size());
+ if (!v.int32Values.size()) {
+ ALOGE("%s: expected at least \"command\" field in int32Values", __func__);
return StatusCode::INVALID_ARG;
}
FakeDataCommand command = static_cast<FakeDataCommand>(v.int32Values[0]);
- int32_t propId = v.int32Values[1];
switch (command) {
- case FakeDataCommand::Start: {
- if (!v.int64Values.size()) {
- ALOGE("%s: interval is not provided in int64Values", __func__);
- return StatusCode::INVALID_ARG;
- }
- auto interval = std::chrono::nanoseconds(v.int64Values[0]);
-
- if (v.floatValues.size() < 3) {
- ALOGE("%s: expected at least 3 element sin floatValues, got: %zu", __func__,
- v.floatValues.size());
- return StatusCode::INVALID_ARG;
- }
- float initialValue = v.floatValues[0];
- float dispersion = v.floatValues[1];
- float increment = v.floatValues[2];
-
- ALOGI("%s, propId: %d, initalValue: %f", __func__, propId, initialValue);
- mFakeValueGenerator.startGeneratingHalEvents(
- interval, propId, initialValue, dispersion, increment);
-
- break;
+ case FakeDataCommand::StartLinear: {
+ ALOGI("%s, FakeDataCommand::StartLinear", __func__);
+ return mLinearFakeValueGenerator->start(request);
}
- case FakeDataCommand::Stop: {
- ALOGI("%s, FakeDataCommand::Stop", __func__);
- mFakeValueGenerator.stopGeneratingHalEvents(propId);
- break;
+ case FakeDataCommand::StartJson: {
+ ALOGI("%s, FakeDataCommand::StartJson", __func__);
+ return mJsonFakeValueGenerator->start(request);
+ }
+ case FakeDataCommand::StopLinear: {
+ ALOGI("%s, FakeDataCommand::StopLinear", __func__);
+ return mLinearFakeValueGenerator->stop(request);
+ }
+ case FakeDataCommand::StopJson: {
+ ALOGI("%s, FakeDataCommand::StopJson", __func__);
+ return mJsonFakeValueGenerator->stop(request);
}
case FakeDataCommand::KeyPress: {
ALOGI("%s, FakeDataCommand::KeyPress", __func__);
@@ -374,7 +365,6 @@ StatusCode EmulatedVehicleHal::handleGenerateFakeDataRequest(const VehiclePropVa
doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
break;
}
-
default: {
ALOGE("%s: unexpected command: %d", __func__, command);
return StatusCode::INVALID_ARG;
@@ -396,30 +386,16 @@ VehicleHal::VehiclePropValuePtr EmulatedVehicleHal::createHwInputKeyProp(
return keyEvent;
}
-void EmulatedVehicleHal::onFakeValueGenerated(int32_t propId, float value) {
+void EmulatedVehicleHal::onFakeValueGenerated(const VehiclePropValue& value) {
+ ALOGD("%s: %s", __func__, toString(value).c_str());
static constexpr bool shouldUpdateStatus = false;
- VehiclePropValuePtr updatedPropValue {};
- switch (getPropType(propId)) {
- case VehiclePropertyType::FLOAT:
- updatedPropValue = getValuePool()->obtainFloat(value);
- break;
- case VehiclePropertyType::INT32:
- updatedPropValue = getValuePool()->obtainInt32(static_cast<int32_t>(value));
- break;
- default:
- ALOGE("%s: data type for property: 0x%x not supported", __func__, propId);
- return;
-
- }
-
+ VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(value);
if (updatedPropValue) {
- updatedPropValue->prop = propId;
- updatedPropValue->areaId = 0; // Add area support if necessary.
updatedPropValue->timestamp = elapsedRealtimeNano();
updatedPropValue->status = VehiclePropertyStatus::AVAILABLE;
mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus);
- auto changeMode = mPropStore->getConfigOrDie(propId)->changeMode;
+ auto changeMode = mPropStore->getConfigOrDie(value.prop)->changeMode;
if (VehiclePropertyChangeMode::ON_CHANGE == changeMode) {
doHalEvent(move(updatedPropValue));
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
index d291dbad82..c188aefe20 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.h
@@ -30,9 +30,10 @@
#include "vhal_v2_0/VehiclePropertyStore.h"
#include "DefaultConfig.h"
-#include "VehicleEmulator.h"
#include "FakeValueGenerator.h"
+#include "VehicleEmulator.h"
+
namespace android {
namespace hardware {
namespace automotive {
@@ -66,7 +67,7 @@ private:
}
StatusCode handleGenerateFakeDataRequest(const VehiclePropValue& request);
- void onFakeValueGenerated(int32_t propId, float value);
+ void onFakeValueGenerated(const VehiclePropValue& value);
VehiclePropValuePtr createHwInputKeyProp(VehicleHwKeyInputAction action, int32_t keyCode,
int32_t targetDisplay);
@@ -84,7 +85,8 @@ private:
VehiclePropertyStore* mPropStore;
std::unordered_set<int32_t> mHvacPowerProps;
RecurrentTimer mRecurrentTimer;
- FakeValueGenerator mFakeValueGenerator;
+ std::unique_ptr<FakeValueGenerator> mLinearFakeValueGenerator;
+ std::unique_ptr<FakeValueGenerator> mJsonFakeValueGenerator;
};
} // impl
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
index 7bbbb08f15..1eeb88dffe 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/FakeValueGenerator.h
@@ -14,15 +14,11 @@
* limitations under the License.
*/
-#ifndef android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
-#define android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
-
-#include <chrono>
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_
#include <android/hardware/automotive/vehicle/2.0/types.h>
-#include <vhal_v2_0/RecurrentTimer.h>
-
namespace android {
namespace hardware {
namespace automotive {
@@ -31,89 +27,27 @@ namespace V2_0 {
namespace impl {
-class FakeValueGenerator {
-private:
- // In every timer tick we may want to generate new value based on initial value for debug
- // purpose. It's better to have sequential values to see if events gets delivered in order
- // to the client.
-
- struct GeneratorCfg {
- float initialValue; //
- float currentValue; // Should be in range (initialValue +/- dispersion).
- float dispersion; // Defines minimum and maximum value based on initial value.
- float increment; // Value that we will be added to currentValue with each timer tick.
- };
+using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
+using MuxGuard = std::lock_guard<std::mutex>;
+class FakeValueGenerator {
public:
- using OnHalEvent = std::function<void(int32_t propId, float value)>;
-
- FakeValueGenerator(const OnHalEvent& onHalEvent) :
- mOnHalEvent(onHalEvent),
- mRecurrentTimer(std::bind(&FakeValueGenerator::onTimer, this,
- std::placeholders::_1))
- {}
-
- ~FakeValueGenerator() = default;
-
-
- void startGeneratingHalEvents(std::chrono::nanoseconds interval, int propId, float initialValue,
- float dispersion, float increment) {
- MuxGuard g(mLock);
-
- removeLocked(propId);
-
- mGenCfg.insert({propId, GeneratorCfg {
- .initialValue = initialValue,
- .currentValue = initialValue,
- .dispersion = dispersion,
- .increment = increment,
- }});
-
- mRecurrentTimer.registerRecurrentEvent(interval, propId);
- }
-
- void stopGeneratingHalEvents(int propId) {
- MuxGuard g(mLock);
- if (propId == 0) {
- // Remove all.
- for (auto&& it : mGenCfg) {
- removeLocked(it.first);
- }
- } else {
- removeLocked(propId);
- }
- }
-
-private:
- void removeLocked(int propId) {
- if (mGenCfg.erase(propId)) {
- mRecurrentTimer.unregisterRecurrentEvent(propId);
- }
- }
-
- void onTimer(const std::vector<int32_t>& properties) {
- MuxGuard g(mLock);
-
- for (int32_t propId : properties) {
- auto& cfg = mGenCfg[propId];
- cfg.currentValue += cfg.increment;
- if (cfg.currentValue > cfg.initialValue + cfg.dispersion) {
- cfg.currentValue = cfg.initialValue - cfg.dispersion;
- }
- mOnHalEvent(propId, cfg.currentValue);
- }
- }
-
-private:
- using MuxGuard = std::lock_guard<std::mutex>;
-
- mutable std::mutex mLock;
- OnHalEvent mOnHalEvent;
- RecurrentTimer mRecurrentTimer;
- std::unordered_map<int32_t, GeneratorCfg> mGenCfg;
+ virtual ~FakeValueGenerator() = default;
+ /**
+ * Starts generating VHAL events
+ *
+ * @param request in VehiclePropValue with required information to start fake data generation
+ * @return StatusCode of the start request
+ */
+ virtual StatusCode start(const VehiclePropValue& request) = 0;
+ /**
+ * Stops generating VHAL events
+ * @param request in VehiclePropValue with required information to stop fake data generation
+ * @return StatusCode of the stop request
+ */
+ virtual StatusCode stop(const VehiclePropValue& request) = 0;
};
-
} // impl
} // namespace V2_0
@@ -122,6 +56,4 @@ private:
} // namespace hardware
} // namespace android
-
-
-#endif //android_hardware_automotive_vehicle_V2_0_impl_FakeHalEventGenerator_H_
+#endif // android_hardware_automotive_vehicle_V2_0_impl_FakeValueGenerator_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
new file mode 100644
index 0000000000..88b8f865c5
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.cpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "JsonFakeValueGenerator"
+
+#include <fstream>
+
+#include <log/log.h>
+#include <vhal_v2_0/VehicleUtils.h>
+
+#include "JsonFakeValueGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+JsonFakeValueGenerator::JsonFakeValueGenerator(const OnHalEvent& onHalEvent)
+ : mOnHalEvent(onHalEvent), mThread(&JsonFakeValueGenerator::loop, this) {}
+
+JsonFakeValueGenerator::~JsonFakeValueGenerator() {
+ mStopRequested = true;
+ {
+ MuxGuard g(mLock);
+ mGenCfg.index = 0;
+ mGenCfg.events.clear();
+ }
+ mCond.notify_one();
+ if (mThread.joinable()) {
+ mThread.join();
+ }
+}
+
+StatusCode JsonFakeValueGenerator::start(const VehiclePropValue& request) {
+ const auto& v = request.value;
+ if (v.stringValue.empty()) {
+ ALOGE("%s: path to JSON file is missing", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ const char* file = v.stringValue.c_str();
+ std::ifstream ifs(file);
+ if (!ifs) {
+ ALOGE("%s: couldn't open %s for parsing.", __func__, file);
+ return StatusCode::INTERNAL_ERROR;
+ }
+ std::vector<VehiclePropValue> fakeVhalEvents = parseFakeValueJson(ifs);
+
+ {
+ MuxGuard g(mLock);
+ mGenCfg = {0, fakeVhalEvents};
+ }
+ mCond.notify_one();
+ return StatusCode::OK;
+}
+
+StatusCode JsonFakeValueGenerator::stop(const VehiclePropValue& request) {
+ const auto& v = request.value;
+ if (!v.stringValue.empty()) {
+ ALOGI("%s: %s", __func__, v.stringValue.c_str());
+ }
+
+ {
+ MuxGuard g(mLock);
+ mGenCfg.index = 0;
+ mGenCfg.events.clear();
+ }
+ mCond.notify_one();
+ return StatusCode::OK;
+}
+
+std::vector<VehiclePropValue> JsonFakeValueGenerator::parseFakeValueJson(std::istream& is) {
+ std::vector<VehiclePropValue> fakeVhalEvents;
+
+ Json::Reader reader;
+ Json::Value rawEvents;
+ if (!reader.parse(is, rawEvents)) {
+ ALOGE("%s: Failed to parse fake data JSON file. Error: %s", __func__,
+ reader.getFormattedErrorMessages().c_str());
+ return fakeVhalEvents;
+ }
+
+ for (Json::Value::ArrayIndex i = 0; i < rawEvents.size(); i++) {
+ Json::Value rawEvent = rawEvents[i];
+ if (!rawEvent.isObject()) {
+ ALOGE("%s: VHAL JSON event should be an object, %s", __func__,
+ rawEvent.toStyledString().c_str());
+ continue;
+ }
+ if (rawEvent["prop"].empty() || rawEvent["areaId"].empty() || rawEvent["value"].empty() ||
+ rawEvent["timestamp"].empty()) {
+ ALOGE("%s: VHAL JSON event has missing fields, skip it, %s", __func__,
+ rawEvent.toStyledString().c_str());
+ continue;
+ }
+ VehiclePropValue event = {.prop = rawEvent["prop"].asInt(),
+ .areaId = rawEvent["areaId"].asInt(),
+ .timestamp = rawEvent["timestamp"].asInt64()};
+
+ Json::Value rawEventValue = rawEvent["value"];
+ auto& value = event.value;
+ switch (getPropType(event.prop)) {
+ case VehiclePropertyType::BOOLEAN:
+ case VehiclePropertyType::INT32:
+ value.int32Values.resize(1);
+ value.int32Values[0] = rawEventValue.asInt();
+ break;
+ case VehiclePropertyType::INT64:
+ value.int64Values.resize(1);
+ value.int64Values[0] = rawEventValue.asInt64();
+ break;
+ case VehiclePropertyType::FLOAT:
+ value.floatValues.resize(1);
+ value.floatValues[0] = rawEventValue.asFloat();
+ break;
+ case VehiclePropertyType::STRING:
+ value.stringValue = rawEventValue.asString();
+ break;
+ default:
+ ALOGE("%s: unsupported type for property: 0x%x with value: %s", __func__,
+ event.prop, rawEventValue.asString().c_str());
+ continue;
+ }
+ fakeVhalEvents.push_back(event);
+ }
+ return fakeVhalEvents;
+}
+
+void JsonFakeValueGenerator::loop() {
+ static constexpr auto kInvalidTime = TimePoint(Nanos::max());
+
+ while (!mStopRequested) {
+ auto nextEventTime = kInvalidTime;
+ {
+ MuxGuard g(mLock);
+ if (mGenCfg.index < mGenCfg.events.size()) {
+ mOnHalEvent(mGenCfg.events[mGenCfg.index]);
+ }
+ if (!mGenCfg.events.empty() && mGenCfg.index < mGenCfg.events.size() - 1) {
+ Nanos intervalNano =
+ static_cast<Nanos>(mGenCfg.events[mGenCfg.index + 1].timestamp -
+ mGenCfg.events[mGenCfg.index].timestamp);
+ nextEventTime = Clock::now() + intervalNano;
+ }
+ mGenCfg.index++;
+ }
+
+ std::unique_lock<std::mutex> g(mLock);
+ mCond.wait_until(g, nextEventTime);
+ }
+}
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
new file mode 100644
index 0000000000..51da4c5383
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/JsonFakeValueGenerator.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_
+
+#include <atomic>
+#include <chrono>
+#include <condition_variable>
+#include <iostream>
+#include <thread>
+
+#include <json/json.h>
+
+#include "FakeValueGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class JsonFakeValueGenerator : public FakeValueGenerator {
+private:
+ using Nanos = std::chrono::nanoseconds;
+ using Clock = std::chrono::steady_clock;
+ using TimePoint = std::chrono::time_point<Clock, Nanos>;
+
+ struct GeneratorCfg {
+ size_t index;
+ std::vector<VehiclePropValue> events;
+ };
+
+public:
+ JsonFakeValueGenerator(const OnHalEvent& onHalEvent);
+ ~JsonFakeValueGenerator();
+ StatusCode start(const VehiclePropValue& request) override;
+ StatusCode stop(const VehiclePropValue& request) override;
+
+private:
+ std::vector<VehiclePropValue> parseFakeValueJson(std::istream& is);
+ void loop();
+
+private:
+ OnHalEvent mOnHalEvent;
+ std::thread mThread;
+ mutable std::mutex mLock;
+ std::condition_variable mCond;
+ GeneratorCfg mGenCfg;
+ std::atomic_bool mStopRequested{false};
+};
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_JsonFakeValueGenerator_H_
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
new file mode 100644
index 0000000000..8cb9322fa6
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.cpp
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "LinearFakeValueGenerator"
+
+#include <log/log.h>
+#include <vhal_v2_0/VehicleUtils.h>
+
+#include "LinearFakeValueGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+LinearFakeValueGenerator::LinearFakeValueGenerator(const OnHalEvent& onHalEvent)
+ : mOnHalEvent(onHalEvent),
+ mRecurrentTimer(std::bind(&LinearFakeValueGenerator::onTimer, this, std::placeholders::_1)) {}
+
+StatusCode LinearFakeValueGenerator::start(const VehiclePropValue& request) {
+ const auto& v = request.value;
+ if (v.int32Values.size() < 2) {
+ ALOGE("%s: expected property ID in int32Values", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t propId = v.int32Values[1];
+
+ if (!v.int64Values.size()) {
+ ALOGE("%s: interval is not provided in int64Values", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ auto interval = std::chrono::nanoseconds(v.int64Values[0]);
+
+ if (v.floatValues.size() < 3) {
+ ALOGE("%s: expected at least 3 elements in floatValues, got: %zu", __func__,
+ v.floatValues.size());
+ return StatusCode::INVALID_ARG;
+ }
+ float initialValue = v.floatValues[0];
+ float dispersion = v.floatValues[1];
+ float increment = v.floatValues[2];
+
+ MuxGuard g(mLock);
+ removeLocked(propId);
+ mGenCfg.insert({propId, GeneratorCfg{
+ .initialValue = initialValue,
+ .currentValue = initialValue,
+ .dispersion = dispersion,
+ .increment = increment,}});
+
+ mRecurrentTimer.registerRecurrentEvent(interval, propId);
+ return StatusCode::OK;
+}
+
+StatusCode LinearFakeValueGenerator::stop(const VehiclePropValue& request) {
+ const auto& v = request.value;
+ if (v.int32Values.size() < 2) {
+ ALOGE("%s: expected property ID in int32Values", __func__);
+ return StatusCode::INVALID_ARG;
+ }
+ int32_t propId = v.int32Values[1];
+
+ MuxGuard g(mLock);
+ if (propId == 0) {
+ // Remove all.
+ for (auto&& it : mGenCfg) {
+ removeLocked(it.first);
+ }
+ } else {
+ removeLocked(propId);
+ }
+ return StatusCode::OK;
+}
+
+void LinearFakeValueGenerator::removeLocked(int propId) {
+ if (mGenCfg.erase(propId)) {
+ mRecurrentTimer.unregisterRecurrentEvent(propId);
+ }
+}
+
+void LinearFakeValueGenerator::onTimer(const std::vector<int32_t>& properties) {
+ MuxGuard g(mLock);
+
+ for (int32_t propId : properties) {
+ auto& cfg = mGenCfg[propId];
+ cfg.currentValue += cfg.increment;
+ if (cfg.currentValue > cfg.initialValue + cfg.dispersion) {
+ cfg.currentValue = cfg.initialValue - cfg.dispersion;
+ }
+ VehiclePropValue event = {.prop = propId};
+ auto& value = event.value;
+ switch (getPropType(event.prop)) {
+ case VehiclePropertyType::INT32:
+ value.int32Values.resize(1);
+ value.int32Values[0] = static_cast<int32_t>(cfg.currentValue);
+ break;
+ case VehiclePropertyType::INT64:
+ value.int64Values.resize(1);
+ value.int64Values[0] = static_cast<int64_t>(cfg.currentValue);
+ break;
+ case VehiclePropertyType::FLOAT:
+ value.floatValues.resize(1);
+ value.floatValues[0] = cfg.currentValue;
+ break;
+ default:
+ ALOGE("%s: unsupported property type for 0x%x", __func__, event.prop);
+ continue;
+ }
+ mOnHalEvent(event);
+ }
+}
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
new file mode 100644
index 0000000000..fe6d097962
--- /dev/null
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/LinearFakeValueGenerator.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_
+#define android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_
+
+#include <vhal_v2_0/RecurrentTimer.h>
+
+#include "FakeValueGenerator.h"
+
+namespace android {
+namespace hardware {
+namespace automotive {
+namespace vehicle {
+namespace V2_0 {
+
+namespace impl {
+
+class LinearFakeValueGenerator : public FakeValueGenerator {
+private:
+ // In every timer tick we may want to generate new value based on initial value for debug
+ // purpose. It's better to have sequential values to see if events gets delivered in order
+ // to the client.
+
+ struct GeneratorCfg {
+ float initialValue; //
+ float currentValue; // Should be in range (initialValue +/- dispersion).
+ float dispersion; // Defines minimum and maximum value based on initial value.
+ float increment; // Value that we will be added to currentValue with each timer tick.
+ };
+
+public:
+ LinearFakeValueGenerator(const OnHalEvent& onHalEvent);
+ ~LinearFakeValueGenerator() = default;
+ StatusCode start(const VehiclePropValue& request) override;
+ StatusCode stop(const VehiclePropValue& request) override;
+
+private:
+ void removeLocked(int propId);
+ void onTimer(const std::vector<int32_t>& properties);
+
+private:
+ mutable std::mutex mLock;
+ OnHalEvent mOnHalEvent;
+ RecurrentTimer mRecurrentTimer;
+ std::unordered_map<int32_t, GeneratorCfg> mGenCfg;
+};
+
+} // namespace impl
+
+} // namespace V2_0
+} // namespace vehicle
+} // namespace automotive
+} // namespace hardware
+} // namespace android
+
+#endif // android_hardware_automotive_vehicle_V2_0_impl_LinearFakeValueGenerator_H_