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
diff --git a/automotive/vehicle/2.0/default/Android.bp b/automotive/vehicle/2.0/default/Android.bp
index 774bc4f..22ab079 100644
--- a/automotive/vehicle/2.0/default/Android.bp
+++ b/automotive/vehicle/2.0/default/Android.bp
@@ -62,6 +62,8 @@
         "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 @@
         "libprotobuf-cpp-lite",
     ],
     static_libs: [
+        "libjsoncpp",
         "libqemu_pipe",
         "android.hardware.automotive.vehicle@2.0-libproto-native",
     ],
@@ -107,6 +110,7 @@
         "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 56813ce..6236087 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 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.
      */
-    Start = 1,
+    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.
+     */
+    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 2eb905d..fb54195 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 @@
 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 @@
 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 @@
             doHalEvent(createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
             break;
         }
-
         default: {
             ALOGE("%s: unexpected command: %d", __func__, command);
             return StatusCode::INVALID_ARG;
@@ -396,30 +386,16 @@
     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 d291dba..c188aef 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 @@
     }
 
     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 @@
     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 7bbbb08..1eeb88d 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 impl {
 
+using OnHalEvent = std::function<void(const VehiclePropValue& event)>;
+using MuxGuard = std::lock_guard<std::mutex>;
+
 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.
-    };
-
 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 @@
 }  // 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 0000000..88b8f86
--- /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 0000000..51da4c5
--- /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 0000000..8cb9322
--- /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 0000000..fe6d097
--- /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_