Merge "[vts-core] add VtsHalRadioConfigV1_0TargetTest to vts-core"
diff --git a/Android.bp b/Android.bp
index 70e0574..f64968f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -26,7 +26,7 @@
     ],
 
     header_libs: [
-        "libhidl_gtest_helpers",
+        "libhidl_gtest_helper",
     ],
 
     group_static_libs: true,
diff --git a/atrace/1.0/vts/functional/Android.bp b/atrace/1.0/vts/functional/Android.bp
index d3f4276..ae24968 100644
--- a/atrace/1.0/vts/functional/Android.bp
+++ b/atrace/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalAtraceV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.atrace@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp b/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp
index c62c2f0..2eaa03e 100644
--- a/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp
+++ b/atrace/1.0/vts/functional/VtsHalAtraceV1_0TargetTest.cpp
@@ -18,8 +18,9 @@
 
 #include <android/hardware/atrace/1.0/IAtraceDevice.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 using ::android::sp;
 using ::android::hardware::hidl_string;
@@ -28,29 +29,13 @@
 using ::android::hardware::atrace::V1_0::IAtraceDevice;
 using ::android::hardware::atrace::V1_0::Status;
 
-// Test environment for Boot HIDL HAL.
-class AtraceHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static AtraceHidlEnvironment* Instance() {
-        static AtraceHidlEnvironment* instance = new AtraceHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IAtraceDevice>(); }
-
-   private:
-    AtraceHidlEnvironment() {}
-};
-
 /**
  * There is no expected behaviour that can be tested so these tests check the
  * HAL doesn't crash with different execution orders.
  */
-struct AtraceHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+struct AtraceHidlTest : public ::testing::TestWithParam<std::string> {
     virtual void SetUp() override {
-        atrace = ::testing::VtsHalHidlTargetTestBase::getService<IAtraceDevice>(
-            AtraceHidlEnvironment::Instance()->getServiceName<IAtraceDevice>());
+        atrace = IAtraceDevice::getService(GetParam());
         ASSERT_NE(atrace, nullptr);
     }
 
@@ -82,13 +67,13 @@
 }
 
 /* list categories from vendors. */
-TEST_F(AtraceHidlTest, listCategories) {
+TEST_P(AtraceHidlTest, listCategories) {
     hidl_vec<hidl_string> vnd_categories = getVendorCategoryName(atrace);
     EXPECT_NE(0, vnd_categories.size());
 }
 
 /* enable categories. */
-TEST_F(AtraceHidlTest, enableCategories) {
+TEST_P(AtraceHidlTest, enableCategories) {
     hidl_vec<hidl_string> vnd_categories = getVendorCategoryName(atrace);
     // empty Category with ERROR_INVALID_ARGUMENT
     hidl_vec<hidl_string> empty_categories;
@@ -102,17 +87,13 @@
 }
 
 /* enable categories. */
-TEST_F(AtraceHidlTest, disableAllCategories) {
+TEST_P(AtraceHidlTest, disableAllCategories) {
     auto ret = atrace->disableAllCategories();
     ASSERT_TRUE(ret.isOk());
     EXPECT_EQ(Status::SUCCESS, ret);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(AtraceHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    AtraceHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, AtraceHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IAtraceDevice::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/audio/common/all-versions/test/utility/include/utility/AssertOk.h b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
index 5ac2fdc..03a6305 100644
--- a/audio/common/all-versions/test/utility/include/utility/AssertOk.h
+++ b/audio/common/all-versions/test/utility/include/utility/AssertOk.h
@@ -114,6 +114,27 @@
 #define ASSERT_RESULT(expected, ret) ASSERT_PRED_FORMAT2(detail::assertResult, expected, ret)
 #define EXPECT_RESULT(expected, ret) EXPECT_PRED_FORMAT2(detail::assertResult, expected, ret)
 
+/** Unpack the provided result.
+ * If the result is not OK, register a failure and return the default initializer value. */
+template <class R>
+static R extract(const Return<R>& ret) {
+    if (!ret.isOk()) {
+        EXPECT_IS_OK(ret);
+        return R{};
+    }
+    return ret;
+}
+
+template <class Result, class Value>
+static void expectValueOrFailure(Result res, Value expectedValue, Value actualValue,
+                                 Result expectedFailure) {
+    if (res == Result::OK) {
+        ASSERT_EQ(expectedValue, actualValue);
+    } else {
+        ASSERT_EQ(expectedFailure, res) << "Unexpected result " << toString(res);
+    }
+}
+
 }  // namespace utility
 }  // namespace test
 }  // namespace common
diff --git a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
index 0778720..6c51c1b 100644
--- a/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
+++ b/audio/core/all-versions/vts/functional/AudioPrimaryHidlHalTest.h
@@ -408,11 +408,7 @@
 
 class AudioPatchPrimaryHidlTest : public AudioPrimaryHidlTest {
    protected:
-    bool areAudioPatchesSupported() {
-        auto result = device->supportsAudioPatches();
-        EXPECT_IS_OK(result);
-        return result;
-    }
+     bool areAudioPatchesSupported() { return extract(device->supportsAudioPatches()); }
 };
 
 TEST_F(AudioPatchPrimaryHidlTest, AudioPatches) {
@@ -829,17 +825,6 @@
 ////////////////////////////// IStream getters ///////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-/** Unpack the provided result.
- * If the result is not OK, register a failure and return an undefined value. */
-template <class R>
-static R extract(Return<R> ret) {
-    if (!ret.isOk()) {
-        EXPECT_IS_OK(ret);
-        return R{};
-    }
-    return ret;
-}
-
 /* Could not find a way to write a test for two parametrized class fixure
  * thus use this macro do duplicate tests for Input and Output stream */
 #define TEST_IO_STREAM(test_name, documentation, code) \
@@ -1189,11 +1174,7 @@
 struct Capability {
     Capability(IStreamOut* stream) {
         EXPECT_OK(stream->supportsPauseAndResume(returnIn(pause, resume)));
-        auto ret = stream->supportsDrain();
-        EXPECT_IS_OK(ret);
-        if (ret.isOk()) {
-            drain = ret;
-        }
+        drain = extract(stream->supportsDrain());
     }
     bool pause = false;
     bool resume = false;
@@ -1205,19 +1186,6 @@
     Capability(stream.get());
 }
 
-template <class Value>
-static void checkInvalidStateOr0(Result res, Value value) {
-    switch (res) {
-        case Result::INVALID_STATE:
-            break;
-        case Result::OK:
-            ASSERT_EQ(0U, value);
-            break;
-        default:
-            FAIL() << "Unexpected result " << toString(res);
-    }
-}
-
 TEST_P(OutputStreamTest, GetRenderPosition) {
     doc::test("A new stream render position should be 0 or INVALID_STATE");
     uint32_t dspFrames;
@@ -1226,7 +1194,7 @@
         doc::partialTest("getRenderPosition is not supported");
         return;
     }
-    checkInvalidStateOr0(res, dspFrames);
+    expectValueOrFailure(res, 0U, dspFrames, Result::INVALID_STATE);
 }
 
 TEST_P(OutputStreamTest, GetNextWriteTimestamp) {
@@ -1237,7 +1205,7 @@
         doc::partialTest("getNextWriteTimestamp is not supported");
         return;
     }
-    checkInvalidStateOr0(res, timestampUs);
+    expectValueOrFailure(res, uint64_t{0}, timestampUs, Result::INVALID_STATE);
 }
 
 /** Stub implementation of out stream callback. */
diff --git a/camera/device/1.0/default/CameraDevice.cpp b/camera/device/1.0/default/CameraDevice.cpp
index a03bbc8..2dd6094 100644
--- a/camera/device/1.0/default/CameraDevice.cpp
+++ b/camera/device/1.0/default/CameraDevice.cpp
@@ -397,9 +397,11 @@
     CameraDevice* device = mem->handle.mDevice;
     if (device == nullptr) {
         ALOGE("%s: camera HAL return memory for a null device!", __FUNCTION__);
+        return;
     }
     if (device->mDeviceCallback == nullptr) {
         ALOGE("%s: camera HAL return memory while camera is not opened!", __FUNCTION__);
+        return;
     }
     device->mDeviceCallback->unregisterMemory(mem->handle.mId);
     {
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index e6b70d8..9d68264 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -465,6 +465,13 @@
             <instance>default</instance>
         </interface>
     </hal>
+    <hal format="aidl" optional="true">
+        <name>android.hardware.vibrator</name>
+        <interface>
+            <name>IVibrator</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
     <hal format="hidl" optional="true">
         <name>android.hardware.vibrator</name>
         <version>1.0-4</version>
diff --git a/current.txt b/current.txt
index 4c5f155..8953d51 100644
--- a/current.txt
+++ b/current.txt
@@ -586,8 +586,16 @@
 # HALs released in Android R
 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.1::types
+ce8dbe76eb9ee94b46ef98f725be992e760a5751073d4f4912484026541371f3 android.hardware.health@2.1::IHealth
+26f04510a0b57aba5167c5c0a7c2f077c2acbb98b81902a072517829fd9fd67f android.hardware.health@2.1::IHealthInfoCallback
+db47f4ceceb1f06c656f39caa70c557b0f8471ef59fd58611bea667ffca20101 android.hardware.health@2.1::types
 34515afa2bb792d3c6d8495a5f5d907d179c8507ca5e55c10050d02ae1d516ef android.hardware.neuralnetworks@1.3::IDevice
-e2d20d4eb24f40b44a3766d05f77052581cb3f4df35fb48c0cc5d9cdcf5c872e android.hardware.neuralnetworks@1.3::types
+b74fe72cfe438f50e772e6a307657ff449d5bde83c15dd1f140ff2edbe73499c android.hardware.neuralnetworks@1.3::types
 544049dcda3f943ad67d83d5277f06681a3782982a9af5a78b5d4e8d295d061a android.hardware.vibrator@1.4::IVibrator
 5e1c12efbbba89c9143d10b1b90eceff8bc79aa079f5106215b528e104fef101 android.hardware.vibrator@1.4::IVibratorCallback
 033eae03c09ebc75e82db37bc39995dfaa9086745577b44d9e14e9ccb48bd8cc android.hardware.vibrator@1.4::types
+41c602462ccd1b19cfd645994be4de4c07fc197ff58a54e84476b31908e61e21 android.hardware.radio@1.5::types
+a8691c71747c3f14f7a043598e856425077f755e55990507a9132ad62f8ab3f7 android.hardware.radio@1.5::IRadio
+a62a93faf173b14a6175b683ebf61ffa568dc61f81e369d2dce7b1265e86cf2f android.hardware.radio@1.5::IRadioIndication
+15daf260aaf6781b911450bc94e1a164901f9c0fe0bda68f8434f0a903f66e05 android.hardware.radio@1.5::IRadioResponse
+
diff --git a/health/1.0/vts/functional/Android.bp b/health/1.0/vts/functional/Android.bp
index c14dcee..be2d206 100644
--- a/health/1.0/vts/functional/Android.bp
+++ b/health/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalHealthV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.health@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp b/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
index 335d15d..b985a9f 100644
--- a/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
+++ b/health/1.0/vts/functional/VtsHalHealthV1_0TargetTest.cpp
@@ -18,11 +18,11 @@
 
 #include <android/hardware/health/1.0/IHealth.h>
 #include <android/hardware/health/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
 using HealthConfig = ::android::hardware::health::V1_0::HealthConfig;
 using HealthInfo = ::android::hardware::health::V1_0::HealthInfo;
 using IHealth = ::android::hardware::health::V1_0::IHealth;
@@ -30,25 +30,10 @@
 
 using ::android::sp;
 
-// Test environment for Health HIDL HAL.
-class HealthHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static HealthHidlEnvironment* Instance() {
-        static HealthHidlEnvironment* instance = new HealthHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override { registerTestService<IHealth>(); }
-   private:
-    HealthHidlEnvironment() {}
-};
-
-class HealthHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class HealthHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        health = ::testing::VtsHalHidlTargetTestBase::getService<IHealth>(
-            HealthHidlEnvironment::Instance()->getServiceName<IHealth>());
+        health = IHealth::getService(GetParam());
         ASSERT_NE(health, nullptr);
         health->init(config,
                      [&](const auto& halConfigOut) { config = halConfigOut; });
@@ -61,7 +46,7 @@
 /**
  * Ensure EnergyCounter call returns positive energy counter or NOT_SUPPORTED
  */
-TEST_F(HealthHidlTest, TestEnergyCounter) {
+TEST_P(HealthHidlTest, TestEnergyCounter) {
     Result result;
     int64_t energy = 0;
     health->energyCounter([&](Result ret, int64_t energyOut) {
@@ -73,11 +58,7 @@
     ASSERT_TRUE(result != Result::SUCCESS || energy > 0);
 }
 
-int main(int argc, char **argv) {
-    ::testing::AddGlobalTestEnvironment(HealthHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    HealthHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    ALOGI("Test result = %d", status);
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, HealthHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IHealth::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/health/2.0/README.md b/health/2.0/README.md
index 4ecfb9a..8a7c922 100644
--- a/health/2.0/README.md
+++ b/health/2.0/README.md
@@ -1,3 +1,8 @@
+# Implement the 2.1 HAL instead!
+
+It is strongly recommended that you implement the 2.1 HAL directly. See
+`hardware/interfaces/health/2.1/README.md` for more details.
+
 # Upgrading from Health 1.0 HAL
 
 1. Remove `android.hardware.health@1.0*` from `PRODUCT_PACKAGES`
diff --git a/health/2.0/default/Health.cpp b/health/2.0/default/Health.cpp
index c0c5a40..4225fd8 100644
--- a/health/2.0/default/Health.cpp
+++ b/health/2.0/default/Health.cpp
@@ -17,11 +17,15 @@
 #include <android-base/logging.h>
 
 #include <android-base/file.h>
+#include <android/hardware/health/2.0/types.h>
 #include <health2/Health.h>
 
 #include <hal_conversion.h>
 #include <hidl/HidlTransportSupport.h>
 
+using HealthInfo_1_0 = android::hardware::health::V1_0::HealthInfo;
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
+
 extern void healthd_battery_update_internal(bool);
 
 namespace android {
@@ -149,7 +153,9 @@
     // Retrieve all information and call healthd_mode_ops->battery_update, which calls
     // notifyListeners.
     battery_monitor_->updateValues();
-    struct BatteryProperties props = getBatteryProperties(battery_monitor_.get());
+    const HealthInfo_1_0& health_info = battery_monitor_->getHealthInfo_1_0();
+    struct BatteryProperties props;
+    convertFromHealthInfo(health_info, &props);
     bool log = healthd_board_battery_update(&props);
     if (log) {
         battery_monitor_->logValues();
@@ -253,10 +259,7 @@
     using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
 
     updateAndNotify(nullptr);
-    struct android::BatteryProperties p = getBatteryProperties(battery_monitor_.get());
-
-    V1_0::HealthInfo batteryInfo;
-    convertToHealthInfo(&p, batteryInfo);
+    HealthInfo healthInfo = battery_monitor_->getHealthInfo_2_0();
 
     std::vector<StorageInfo> info;
     get_storage_info(info);
@@ -272,8 +275,6 @@
         currentAvg = static_cast<int32_t>(prop.valueInt64);
     }
 
-    V2_0::HealthInfo healthInfo = {};
-    healthInfo.legacy = std::move(batteryInfo);
     healthInfo.batteryCurrentAverage = currentAvg;
     healthInfo.diskStats = stats;
     healthInfo.storageInfos = info;
diff --git a/health/2.1/README.md b/health/2.1/README.md
new file mode 100644
index 0000000..5a19d7b
--- /dev/null
+++ b/health/2.1/README.md
@@ -0,0 +1,245 @@
+# Implementing Health 2.1 HAL
+
+1. Install common binderized service. The binderized service `dlopen()`s
+   passthrough implementations on the device, so there is no need to write
+   your own.
+
+    ```mk
+    # Install default binderized implementation to vendor.
+    PRODUCT_PACKAGES += android.hardware.health@2.1-service
+    ```
+
+1. Delete existing VINTF manifest entry. Search for `android.hardware.health` in
+   your device manifest, and delete the whole `<hal>` entry for older versions
+   of the HAL. Instead, when `android.hardware.health@2.1-service` is installed,
+   a VINTF manifest fragment is installed to `/vendor/etc/vintf`, so there is
+   no need to manually specify it in your device manifest. See
+   [Manifest fragments](https://source.android.com/devices/architecture/vintf/objects#manifest-fragments)
+   for details.
+
+1. Install the proper passthrough implemetation.
+
+    1. If you want to use default implementation:
+
+        ```mk
+        # Install default passthrough implementation to vendor.
+        PRODUCT_PACKAGES += android.hardware.health@2.1-impl
+        ```
+
+        You are done. Otherwise, go to the next step.
+
+    1. If you want to write your own implementation,
+
+        1. Copy skeleton implementation from the [appendix](#impl).
+
+        1. Modify the implementation to suit your needs.
+
+            * If you have a board or device specific `libhealthd`, see
+              [Upgrading with  a customized libhealthd](#update-from-1-0).
+            * If you are upgrading from 1.0 health HAL, see
+              [Upgrading from Health HAL 1.0](#update-from-1-0).
+            * If you are upgrading from a customized 2.0 health HAL
+              implementation, See
+              [Upgrading from Health HAL 2.0](#update-from-2-0).
+
+        1. [Update necessary SELinux permissions](#selinux).
+
+        1. [Fix `/charger` symlink](#charger-symlink).
+
+# Upgrading with a customized libhealthd or from Health HAL 1.0 {#update-from-1-0}
+
+`libhealthd` contains two functions: `healthd_board_init()` and
+`healthd_board_battery_update()`. Similarly, Health HAL 1.0 contains `init()`
+and `update()`, with an additional `energyCounter()` function.
+
+* `healthd_board_init()` / `@1.0::IHealth.init()` should be called before
+  passing the `healthd_config` struct to your `HealthImpl` class. See
+  `HIDL_FETCH_IHealth` in [`HealthImpl.cpp`](#health_impl_cpp).
+
+* `healthd_board_battery_update()` / `@1.0::IHealth.update()` should be called
+  in `HealthImpl::UpdateHealthInfo()`. Example:
+
+  ```c++
+  void HealthImpl::UpdateHealthInfo(HealthInfo* health_info) {
+      struct BatteryProperties props;
+      convertFromHealthInfo(health_info->legacy.legacy, &props);
+      healthd_board_battery_update(&props);
+      convertToHealthInfo(&props, health_info->legacy.legacy);
+  }
+  ```
+  For efficiency, you should move code in `healthd_board_battery_update` to
+  `HealthImpl::UpdateHealthInfo` and modify `health_info` directly to avoid
+  conversion to `BatteryProperties`.
+
+* Code for `@1.0::IHealth.energyCounter()` should be moved to
+  `HealthImpl::getEnergyCounter()`. Example:
+
+  ```c++
+  Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
+      int64_t energy = /* ... */;
+      _hidl_cb(Result::SUCCESS, energy);
+      return Void();
+  }
+  ```
+
+# Upgrading from Health HAL 2.0 {#update-from-2-0}
+
+* If you have implemented `healthd_board_init()` and/or
+  `healthd_board_battery_update()` (instead of using `libhealthd.default`),
+  see [the section above](#update-from-1-0)
+  for instructions to convert them.
+
+* If you have implemented `get_storage_info()` and/or `get_disk_stats()`
+  (instead of using libhealthstoragedefault), implement `HealthImpl::getDiskStats`
+  and/or `HealthImpl::getStorageInfo` directly. There is no need to override
+  `HealthImpl::getHealthInfo` or `HealthImpl::getHealthInfo_2_1` because they call
+  `getDiskStats` and `getStorageInfo` to retrieve storage information.
+
+# Update necessary SELinux permissions {#selinux}
+
+For example (replace `<device>` with the device name):
+```
+# device/<manufacturer>/<device>/sepolicy/vendor/hal_health_default.te
+# Add device specific permissions to hal_health_default domain, especially
+# if a device-specific libhealthd is used and/or device-specific storage related
+# APIs are implemented.
+```
+
+# Fix `/charger` symlink {#charger-symlink}
+If you are using `/charger` in your `init.rc` scripts, it is recommended
+(required for devices running in Android R) that the path is changed to
+`/system/bin/charger` instead.
+
+Search for `service charger` in your device configuration directory to see if
+this change applies to your device. Below is an example of how the script should
+look like:
+
+```
+service charger /system/bin/charger
+    class charger
+    user system
+    group system wakelock input
+    capabilities SYS_BOOT
+    file /dev/kmsg w
+    file /sys/fs/pstore/console-ramoops-0 r
+    file /sys/fs/pstore/console-ramoops r
+    file /proc/last_kmsg r
+```
+
+# Appendix: sample code for the implementation {#impl}
+
+## `device/<manufacturer>/<device>/health/Android.bp` {#android_bp}
+
+```bp
+cc_library_shared {
+    name: "android.hardware.health@2.1-impl-<device>",
+    stem: "android.hardware.health@2.0-impl-2.1-<device>",
+
+    // Install to vendor and recovery.
+    proprietary: true,
+    recovery_available: true,
+
+    relative_install_path: "hw",
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.health@2.1",
+        "android.hardware.health@2.0",
+    ],
+
+    static_libs: [
+        "android.hardware.health@1.0-convert",
+        "libbatterymonitor",
+        "libhealthloop",
+        "libhealth2impl",
+        // "libhealthd.<device>"
+    ],
+
+    srcs: [
+        "HealthImpl.cpp",
+    ],
+
+    // No vintf_fragments because both -impl and -service should have been
+    // installed.
+}
+```
+
+## `device/<manufacturer>/<device>/health/HealthImpl.cpp` {#health_impl_cpp}
+
+```c++
+#include <memory>
+#include <string_view>
+
+#include <health/utils.h>
+#include <health2impl/Health.h>
+#include <hidl/Status.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::health::InitHealthdConfig;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hidl::base::V1_0::IBase;
+
+using namespace std::literals;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// android::hardware::health::V2_1::implementation::Health implements most
+// defaults. Uncomment functions that you need to override.
+class HealthImpl : public Health {
+  public:
+    HealthImpl(std::unique_ptr<healthd_config>&& config)
+        : Health(std::move(config)) {}
+
+    // A subclass can override this if these information should be retrieved
+    // differently.
+    // Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
+    // Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
+    // Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
+    // Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
+    // Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
+    // Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+    // Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
+    // Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+    // Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
+
+    // Functions introduced in Health HAL 2.1.
+    // Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override;
+    // Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override;
+    // Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override;
+
+  protected:
+    // A subclass can override this to modify any health info object before
+    // returning to clients. This is similar to healthd_board_battery_update().
+    // By default, it does nothing.
+    // void UpdateHealthInfo(HealthInfo* health_info) override;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
+
+extern "C" IHealth* HIDL_FETCH_IHealth(const char* instance) {
+    using ::android::hardware::health::V2_1::implementation::HealthImpl;
+    if (instance != "default"sv) {
+        return nullptr;
+    }
+    auto config = std::make_unique<healthd_config>();
+    InitHealthdConfig(config.get());
+
+    // healthd_board_init(config.get());
+
+    return new HealthImpl(std::move(config));
+}
+```
diff --git a/health/2.1/default/Android.bp b/health/2.1/default/Android.bp
new file mode 100644
index 0000000..3649853
--- /dev/null
+++ b/health/2.1/default/Android.bp
@@ -0,0 +1,81 @@
+// Copyright (C) 2019 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.
+
+cc_defaults {
+    name: "android.hardware.health@2.1-impl-defaults",
+    relative_install_path: "hw",
+
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.health@2.1",
+        "android.hardware.health@2.0",
+    ],
+
+    static_libs: [
+        "android.hardware.health@1.0-convert",
+        "libbatterymonitor",
+        "libhealthloop",
+        "libhealth2impl",
+    ],
+}
+
+// Default passthrough implementation of the health@2.1 HAL.
+// Passhtrough implementations of the health@2.1 HAL must be installed in
+// vendor in order to support charger.
+// Passhtrough implementations of the health@2.1 HAL must be installed in
+// recovery in order to allow recovery to check battery status.
+// See README.md for details.
+cc_library_shared {
+    name: "android.hardware.health@2.1-impl",
+    stem: "android.hardware.health@2.0-impl-2.1",
+
+    // Only vendor and recovery variants are allowed, not core.
+    vendor: true,
+    recovery_available: true,
+
+    defaults: ["android.hardware.health@2.1-impl-defaults"],
+
+    srcs: [
+        "impl.cpp",
+    ],
+
+    // No vintf_fragments because both -impl and -service should have been
+    // installed.
+}
+
+// Default binderized service of the health@2.1 HAL.
+// This binderized implementation dlopen()s the passthrough implementation,
+// so there is no need to implement your own.
+cc_binary {
+    name: "android.hardware.health@2.1-service",
+    vendor: true,
+    defaults: ["android.hardware.health@2.1-impl-defaults"],
+    init_rc: ["android.hardware.health@2.1-service.rc"],
+
+    srcs: [
+        "service.cpp",
+    ],
+
+    vintf_fragments: [
+        "android.hardware.health@2.1.xml"
+    ],
+
+    overrides: [
+        "healthd",
+    ],
+}
diff --git a/health/2.1/default/android.hardware.health@2.1-service.rc b/health/2.1/default/android.hardware.health@2.1-service.rc
new file mode 100644
index 0000000..917f1c2
--- /dev/null
+++ b/health/2.1/default/android.hardware.health@2.1-service.rc
@@ -0,0 +1,6 @@
+service health-hal-2-1 /vendor/bin/hw/android.hardware.health@2.1-service
+    class hal
+    user system
+    group system
+    capabilities WAKE_ALARM
+    file /dev/kmsg w
diff --git a/health/2.1/default/android.hardware.health@2.1.xml b/health/2.1/default/android.hardware.health@2.1.xml
new file mode 100644
index 0000000..34fdca6
--- /dev/null
+++ b/health/2.1/default/android.hardware.health@2.1.xml
@@ -0,0 +1,7 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.health</name>
+        <transport>hwbinder</transport>
+        <fqname>@2.1::IHealth/default</fqname>
+    </hal>
+</manifest>
diff --git a/health/2.1/default/impl.cpp b/health/2.1/default/impl.cpp
new file mode 100644
index 0000000..7389a21
--- /dev/null
+++ b/health/2.1/default/impl.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <memory>
+#include <string_view>
+
+#include <health/utils.h>
+#include <health2impl/Health.h>
+
+using ::android::sp;
+using ::android::hardware::health::InitHealthdConfig;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hardware::health::V2_1::implementation::Health;
+
+using namespace std::literals;
+
+// Passthrough implementation of the health service. Use default configuration.
+// It does not invoke callbacks unless update() is called explicitly. No
+// background thread is spawned to handle callbacks.
+//
+// The passthrough implementation is only allowed in recovery mode, charger, and
+// opened by the hwbinder service.
+// If Android is booted normally, the hwbinder service is used instead.
+//
+// This implementation only implements the "default" instance. It rejects
+// other instance names.
+// Note that the Android framework only reads values from the "default"
+// health HAL 2.1 instance.
+extern "C" IHealth* HIDL_FETCH_IHealth(const char* instance) {
+    if (instance != "default"sv) {
+        return nullptr;
+    }
+    auto config = std::make_unique<healthd_config>();
+    InitHealthdConfig(config.get());
+
+    // This implementation uses default config. If you want to customize it
+    // (e.g. with healthd_board_init), do it here.
+
+    return new Health(std::move(config));
+}
diff --git a/health/2.1/default/service.cpp b/health/2.1/default/service.cpp
new file mode 100644
index 0000000..f8334c5
--- /dev/null
+++ b/health/2.1/default/service.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 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 "android.hardware.health@2.1-service"
+
+#include <android-base/logging.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <health2impl/BinderHealth.h>
+
+using ::android::sp;
+using ::android::hardware::health::V2_1::IHealth;
+using ::android::hardware::health::V2_1::implementation::BinderHealth;
+using IHealth_2_0 = ::android::hardware::health::V2_0::IHealth;
+
+static constexpr const char* gInstanceName = "default";
+
+int main(int /* argc */, char* /* argv */[]) {
+    sp<IHealth> passthrough =
+            IHealth::castFrom(IHealth_2_0::getService(gInstanceName, true /* getStub */));
+    CHECK(passthrough != nullptr)
+            << "Cannot find passthrough implementation of health 2.1 HAL for instance "
+            << gInstanceName;
+    sp<BinderHealth> binder = new BinderHealth(gInstanceName, passthrough);
+    return binder->StartLoop();
+}
diff --git a/health/utils/libhealth2impl/Android.bp b/health/utils/libhealth2impl/Android.bp
new file mode 100644
index 0000000..14374a2
--- /dev/null
+++ b/health/utils/libhealth2impl/Android.bp
@@ -0,0 +1,51 @@
+// Copyright (C) 2019 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.
+
+// A helper library for health@2.x HAL implementation.
+// HAL implementations can link to this library and extend the Health class.
+cc_library_static {
+    name: "libhealth2impl",
+    vendor_available: true,
+    recovery_available: true,
+    srcs: [
+        "BinderHealth.cpp",
+        "HalHealthLoop.cpp",
+        "Health.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libcutils",
+        "libhidlbase",
+        "liblog",
+        "libutils",
+        "android.hardware.health@2.1",
+        "android.hardware.health@2.0",
+    ],
+    static_libs: [
+        "libbatterymonitor",
+        "libhealthloop",
+        "android.hardware.health@1.0-convert",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    export_static_lib_headers: [
+        "libbatterymonitor",
+        "libhealthloop",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/health/utils/libhealth2impl/BinderHealth.cpp b/health/utils/libhealth2impl/BinderHealth.cpp
new file mode 100644
index 0000000..625d0e0
--- /dev/null
+++ b/health/utils/libhealth2impl/BinderHealth.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <health2impl/BinderHealth.h>
+
+#include <android-base/logging.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/Health.h>
+
+using android::hardware::handleTransportPoll;
+using android::hardware::IPCThreadState;
+using android::hardware::setupTransportPolling;
+
+using android::hardware::health::V2_0::Result;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+bool IsDeadObjectLogged(const Return<void>& ret) {
+    if (ret.isOk()) return false;
+    if (ret.isDeadObject()) return true;
+    LOG(ERROR) << "Cannot call healthInfoChanged* on callback: " << ret.description();
+    return false;
+}
+
+BinderHealth::BinderHealth(const std::string& name, const sp<IHealth>& impl)
+    : HalHealthLoop(name, impl) {
+    CHECK_NE(this, impl.get());
+    CHECK(!impl->isRemote());
+}
+
+//
+// Methods that handle callbacks.
+//
+
+Return<Result> BinderHealth::registerCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
+    if (callback == nullptr) {
+        return Result::SUCCESS;
+    }
+
+    Callback* wrapped = nullptr;
+    {
+        std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+        wrapped = callbacks_.emplace_back(Wrap(callback)).get();
+        // unlock
+    }
+
+    auto linkRet = callback->linkToDeath(this, 0u /* cookie */);
+    if (!linkRet.withDefault(false)) {
+        LOG(WARNING) << __func__ << "Cannot link to death: "
+                     << (linkRet.isOk() ? "linkToDeath returns false" : linkRet.description());
+        // ignore the error
+    }
+
+    getHealthInfo_2_1([&](auto res, const auto& health_info) {
+        if (res != Result::SUCCESS) {
+            LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
+            return;
+        }
+        auto ret = wrapped->Notify(health_info);
+        if (IsDeadObjectLogged(ret)) {
+            // Remove callback reference.
+            std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+            auto it = std::find_if(callbacks_.begin(), callbacks_.end(),
+                                   [wrapped](const auto& cb) { return cb.get() == wrapped; });
+            if (it != callbacks_.end()) {
+                callbacks_.erase(it);
+            }
+            // unlock
+        }
+    });
+
+    return Result::SUCCESS;
+}
+
+bool BinderHealth::unregisterCallbackInternal(const sp<IBase>& callback) {
+    if (callback == nullptr) {
+        return false;
+    }
+
+    bool removed = false;
+    std::lock_guard<decltype(callbacks_lock_)> lock(callbacks_lock_);
+    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+        if (interfacesEqual((*it)->Get(), callback)) {
+            it = callbacks_.erase(it);
+            removed = true;
+        } else {
+            ++it;
+        }
+    }
+    (void)callback->unlinkToDeath(this).isOk();  // ignore errors
+    return removed;
+}
+
+Return<Result> BinderHealth::update() {
+    Result result = service()->update();
+    if (result != Result::SUCCESS) return result;
+    getHealthInfo_2_1([&](auto res, const auto& health_info) {
+        if (res != Result::SUCCESS) {
+            result = res;
+            return;
+        }
+        OnHealthInfoChanged(health_info);
+    });
+    return result;
+}
+
+Return<Result> BinderHealth::unregisterCallback(const sp<V2_0::IHealthInfoCallback>& callback) {
+    return unregisterCallbackInternal(callback) ? Result::SUCCESS : Result::NOT_FOUND;
+}
+
+void BinderHealth::OnHealthInfoChanged(const HealthInfo& health_info) {
+    // Notify all callbacks
+    std::unique_lock<decltype(callbacks_lock_)> lock(callbacks_lock_);
+    for (auto it = callbacks_.begin(); it != callbacks_.end();) {
+        auto ret = (*it)->Notify(health_info);
+        if (IsDeadObjectLogged(ret)) {
+            it = callbacks_.erase(it);
+        } else {
+            ++it;
+        }
+    }
+    lock.unlock();
+
+    // adjusts uevent / wakealarm periods
+    HalHealthLoop::OnHealthInfoChanged(health_info);
+}
+
+void BinderHealth::serviceDied(uint64_t /* cookie */, const wp<IBase>& who) {
+    (void)unregisterCallbackInternal(who.promote());
+}
+
+void BinderHealth::BinderEvent(uint32_t /*epevents*/) {
+    if (binder_fd_ >= 0) {
+        handleTransportPoll(binder_fd_);
+    }
+}
+
+void BinderHealth::Init(struct healthd_config* config) {
+    // Set up epoll and get uevent / wake alarm periods
+    HalHealthLoop::Init(config);
+
+    LOG(INFO) << instance_name() << " instance initializing with healthd_config...";
+
+    binder_fd_ = setupTransportPolling();
+
+    if (binder_fd_ >= 0) {
+        auto binder_event = [](auto* health_loop, uint32_t epevents) {
+            static_cast<BinderHealth*>(health_loop)->BinderEvent(epevents);
+        };
+        if (RegisterEvent(binder_fd_, binder_event, EVENT_NO_WAKEUP_FD) != 0) {
+            PLOG(ERROR) << instance_name() << " instance: Register for binder events failed";
+        }
+    }
+
+    CHECK_EQ(registerAsService(instance_name()), android::OK)
+            << instance_name() << ": Failed to register HAL";
+
+    LOG(INFO) << instance_name() << ": Hal init done";
+}
+
+int BinderHealth::PrepareToWait(void) {
+    IPCThreadState::self()->flushCommands();
+    return HalHealthLoop::PrepareToWait();
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/HalHealthLoop.cpp b/health/utils/libhealth2impl/HalHealthLoop.cpp
new file mode 100644
index 0000000..3901a76
--- /dev/null
+++ b/health/utils/libhealth2impl/HalHealthLoop.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <health2impl/HalHealthLoop.h>
+
+#include <android-base/logging.h>
+#include <hal_conversion.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Health.h>
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::handleTransportPoll;
+using android::hardware::IPCThreadState;
+using android::hardware::setupTransportPolling;
+
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthConfig;
+using android::hardware::health::V2_0::Result;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+void HalHealthLoop::Init(struct healthd_config* config) {
+    // Retrieve healthd_config from the HAL.
+    service_->getHealthConfig([config](auto res, const auto& health_config) {
+        CHECK(res == Result::SUCCESS);
+
+        convertFromHealthConfig(health_config.battery, config);
+        config->boot_min_cap = health_config.bootMinCap;
+
+        // Leave screen_on empty because it is handled in GetScreenOn below.
+
+        // Leave ignorePowerSupplyNames empty because it isn't
+        // used by clients of health HAL.
+    });
+}
+
+void HalHealthLoop::Heartbeat(void) {
+    // noop
+}
+
+void HalHealthLoop::ScheduleBatteryUpdate() {
+    // ignore errors. impl may not be able to handle any callbacks, so
+    // update() may return errors.
+    Result res = service_->update();
+    if (res != Result::SUCCESS) {
+        LOG(WARNING) << "update() on the health HAL implementation failed with " << toString(res);
+    }
+
+    service_->getHealthInfo_2_1([this](auto res, const auto& health_info) {
+        CHECK(res == Result::SUCCESS)
+                << "getHealthInfo_2_1() on the health HAL implementation failed with "
+                << toString(res);
+        this->OnHealthInfoChanged(health_info);
+    });
+}
+
+int HalHealthLoop::PrepareToWait() {
+    return -1;
+}
+
+void HalHealthLoop::OnHealthInfoChanged(const HealthInfo& health_info) {
+    set_charger_online(health_info);
+    AdjustWakealarmPeriods(charger_online());
+}
+
+void HalHealthLoop::set_charger_online(const HealthInfo& health_info) {
+    const auto& props = health_info.legacy.legacy;
+    charger_online_ =
+            props.chargerAcOnline || props.chargerUsbOnline || props.chargerWirelessOnline;
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/Health.cpp b/health/utils/libhealth2impl/Health.cpp
new file mode 100644
index 0000000..f4684ae
--- /dev/null
+++ b/health/utils/libhealth2impl/Health.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <health2impl/Health.h>
+
+#include <functional>
+#include <string_view>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android/hardware/health/1.0/types.h>
+#include <android/hardware/health/2.0/IHealthInfoCallback.h>
+#include <android/hardware/health/2.0/types.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+#include <hal_conversion.h>
+#include <healthd/healthd.h>
+#include <hidl/HidlTransportSupport.h>
+#include <hwbinder/IPCThreadState.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/HalHealthLoop.h>
+
+using android::hardware::health::V1_0::BatteryStatus;
+using android::hardware::health::V1_0::toString;
+using android::hardware::health::V1_0::hal_conversion::convertFromHealthInfo;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthConfig;
+using android::hardware::health::V1_0::hal_conversion::convertToHealthInfo;
+using android::hardware::health::V2_0::Result;
+using android::hardware::health::V2_1::IHealth;
+
+using ScreenOn = decltype(healthd_config::screen_on);
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+/*
+// If you need to call healthd_board_init, construct the Health instance with
+// the healthd_config after calling healthd_board_init:
+struct healthd_config* init_config(struct healthd_config* config) {
+    healthd_board_init(config);
+    return config;
+}
+class MyHealth : public Health {
+    MyHealth(struct healthd_config* config) :
+        Health(init_config(config)) {}
+};
+*/
+
+Health::Health(std::unique_ptr<healthd_config>&& config) : healthd_config_(std::move(config)) {
+    battery_monitor_.init(healthd_config_.get());
+}
+
+//
+// Callbacks are not supported by the passthrough implementation.
+//
+
+Return<Result> Health::registerCallback(const sp<V2_0::IHealthInfoCallback>&) {
+    return Result::NOT_SUPPORTED;
+}
+
+Return<Result> Health::unregisterCallback(const sp<V2_0::IHealthInfoCallback>&) {
+    return Result::NOT_SUPPORTED;
+}
+
+Return<Result> Health::update() {
+    Result result = Result::UNKNOWN;
+    getHealthInfo_2_1([&](auto res, const auto& /* health_info */) {
+        result = res;
+        if (res != Result::SUCCESS) {
+            LOG(ERROR) << "Cannot call getHealthInfo_2_1: " << toString(res);
+            return;
+        }
+
+        battery_monitor_.logValues();
+    });
+    return result;
+}
+
+//
+// Getters.
+//
+
+template <typename T>
+static Return<void> GetProperty(BatteryMonitor* monitor, int id, T defaultValue,
+                                const std::function<void(Result, T)>& callback) {
+    struct BatteryProperty prop;
+    T ret = defaultValue;
+    Result result = Result::SUCCESS;
+    status_t err = monitor->getProperty(static_cast<int>(id), &prop);
+    if (err != OK) {
+        LOG(DEBUG) << "getProperty(" << id << ")"
+                   << " fails: (" << err << ") " << strerror(-err);
+    } else {
+        ret = static_cast<T>(prop.valueInt64);
+    }
+    switch (err) {
+        case OK:
+            result = Result::SUCCESS;
+            break;
+        case NAME_NOT_FOUND:
+            result = Result::NOT_SUPPORTED;
+            break;
+        default:
+            result = Result::UNKNOWN;
+            break;
+    }
+    callback(result, static_cast<T>(ret));
+    return Void();
+}
+
+Return<void> Health::getChargeCounter(getChargeCounter_cb _hidl_cb) {
+    return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CHARGE_COUNTER, 0, _hidl_cb);
+}
+
+Return<void> Health::getCurrentNow(getCurrentNow_cb _hidl_cb) {
+    return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CURRENT_NOW, 0, _hidl_cb);
+}
+
+Return<void> Health::getCurrentAverage(getCurrentAverage_cb _hidl_cb) {
+    return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CURRENT_AVG, 0, _hidl_cb);
+}
+
+Return<void> Health::getCapacity(getCapacity_cb _hidl_cb) {
+    return GetProperty<int32_t>(&battery_monitor_, BATTERY_PROP_CAPACITY, 0, _hidl_cb);
+}
+
+Return<void> Health::getEnergyCounter(getEnergyCounter_cb _hidl_cb) {
+    return GetProperty<int64_t>(&battery_monitor_, BATTERY_PROP_ENERGY_COUNTER, 0, _hidl_cb);
+}
+
+Return<void> Health::getChargeStatus(getChargeStatus_cb _hidl_cb) {
+    return GetProperty(&battery_monitor_, BATTERY_PROP_BATTERY_STATUS, BatteryStatus::UNKNOWN,
+                       _hidl_cb);
+}
+
+Return<void> Health::getStorageInfo(getStorageInfo_cb _hidl_cb) {
+    // This implementation does not support StorageInfo. An implementation may extend this
+    // class and override this function to support storage info.
+    _hidl_cb(Result::NOT_SUPPORTED, {});
+    return Void();
+}
+
+Return<void> Health::getDiskStats(getDiskStats_cb _hidl_cb) {
+    // This implementation does not support DiskStats. An implementation may extend this
+    // class and override this function to support disk stats.
+    _hidl_cb(Result::NOT_SUPPORTED, {});
+    return Void();
+}
+
+template <typename T, typename Method>
+static inline void GetHealthInfoField(Health* service, Method func, T* out) {
+    *out = T{};
+    std::invoke(func, service, [out](Result result, const T& value) {
+        if (result == Result::SUCCESS) *out = value;
+    });
+}
+
+Return<void> Health::getHealthInfo(getHealthInfo_cb _hidl_cb) {
+    return getHealthInfo_2_1(
+            [&](auto res, const auto& health_info) { _hidl_cb(res, health_info.legacy); });
+}
+
+Return<void> Health::getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) {
+    battery_monitor_.updateValues();
+
+    HealthInfo health_info = battery_monitor_.getHealthInfo_2_1();
+
+    // Fill in storage infos; these aren't retrieved by BatteryMonitor.
+    GetHealthInfoField(this, &Health::getStorageInfo, &health_info.legacy.storageInfos);
+    GetHealthInfoField(this, &Health::getDiskStats, &health_info.legacy.diskStats);
+
+    // A subclass may want to update health info struct before returning it.
+    UpdateHealthInfo(&health_info);
+
+    _hidl_cb(Result::SUCCESS, health_info);
+    return Void();
+}
+
+Return<void> Health::debug(const hidl_handle& handle, const hidl_vec<hidl_string>&) {
+    if (handle == nullptr || handle->numFds == 0) {
+        return Void();
+    }
+
+    int fd = handle->data[0];
+    battery_monitor_.dumpState(fd);
+    getHealthInfo_2_1([fd](auto res, const auto& info) {
+        android::base::WriteStringToFd("\ngetHealthInfo -> ", fd);
+        if (res == Result::SUCCESS) {
+            android::base::WriteStringToFd(toString(info), fd);
+        } else {
+            android::base::WriteStringToFd(toString(res), fd);
+        }
+        android::base::WriteStringToFd("\n", fd);
+    });
+
+    fsync(fd);
+    return Void();
+}
+
+Return<void> Health::getHealthConfig(getHealthConfig_cb _hidl_cb) {
+    HealthConfig config = {};
+    convertToHealthConfig(healthd_config_.get(), config.battery);
+    config.bootMinCap = static_cast<int32_t>(healthd_config_->boot_min_cap);
+
+    _hidl_cb(Result::SUCCESS, config);
+    return Void();
+}
+
+Return<void> Health::shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) {
+    if (!healthd_config_->screen_on) {
+        _hidl_cb(Result::NOT_SUPPORTED, true);
+        return Void();
+    }
+
+    Result returned_result = Result::UNKNOWN;
+    bool screen_on = true;
+    getHealthInfo_2_1([&](auto res, const auto& health_info) {
+        returned_result = res;
+        if (returned_result != Result::SUCCESS) return;
+
+        struct BatteryProperties props = {};
+        V1_0::hal_conversion::convertFromHealthInfo(health_info.legacy.legacy, &props);
+        screen_on = healthd_config_->screen_on(&props);
+    });
+    _hidl_cb(returned_result, screen_on);
+    return Void();
+}
+
+//
+// Subclass helpers / overrides
+//
+
+void Health::UpdateHealthInfo(HealthInfo* /* health_info */) {
+    /*
+        // Sample code for a subclass to implement this:
+        // If you need to modify values (e.g. batteryChargeTimeToFullNowSeconds), do it here.
+        health_info->batteryChargeTimeToFullNowSeconds = calculate_charge_time_seconds();
+
+        // If you need to call healthd_board_battery_update:
+        struct BatteryProperties props;
+        convertFromHealthInfo(health_info.legacy.legacy, &props);
+        healthd_board_battery_update(&props);
+        convertToHealthInfo(&props, health_info.legacy.legacy);
+    */
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/BinderHealth.h b/health/utils/libhealth2impl/include/health2impl/BinderHealth.h
new file mode 100644
index 0000000..1da5bd1
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/BinderHealth.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <healthd/healthd.h>
+
+#include <health2impl/Callback.h>
+#include <health2impl/HalHealthLoop.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// binderized health HAL implementation.
+class BinderHealth : public HalHealthLoop, public IHealth, public hidl_death_recipient {
+  public:
+    // |impl| should be the passthrough implementation.
+    BinderHealth(const std::string& name, const sp<IHealth>& impl);
+
+    // Methods from ::android::hardware::health::V2_0::IHealth follow.
+    Return<::android::hardware::health::V2_0::Result> registerCallback(
+            const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+    Return<::android::hardware::health::V2_0::Result> unregisterCallback(
+            const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+    Return<::android::hardware::health::V2_0::Result> update() override;
+    Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override {
+        return service()->getChargeCounter(_hidl_cb);
+    }
+    Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override {
+        return service()->getCurrentNow(_hidl_cb);
+    }
+    Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override {
+        return service()->getCurrentAverage(_hidl_cb);
+    }
+    Return<void> getCapacity(getCapacity_cb _hidl_cb) override {
+        return service()->getCapacity(_hidl_cb);
+    }
+    Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override {
+        return service()->getEnergyCounter(_hidl_cb);
+    }
+    Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override {
+        return service()->getChargeStatus(_hidl_cb);
+    }
+    Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override {
+        return service()->getStorageInfo(_hidl_cb);
+    }
+    Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override {
+        return service()->getDiskStats(_hidl_cb);
+    }
+    Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override {
+        return service()->getHealthInfo(_hidl_cb);
+    }
+
+    // Methods from ::android::hardware::health::V2_1::IHealth follow.
+    Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override {
+        return service()->getHealthConfig(_hidl_cb);
+    }
+    Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override {
+        return service()->getHealthInfo_2_1(_hidl_cb);
+    }
+    Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override {
+        return service()->shouldKeepScreenOn(_hidl_cb);
+    }
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override {
+        return service()->debug(fd, args);
+    }
+
+    // hidl_death_recipient implementation.
+    void serviceDied(uint64_t cookie, const wp<IBase>& who) override;
+
+    // Called by BinderHealthCallback.
+    void OnHealthInfoChanged(const HealthInfo& health_info) override;
+
+  protected:
+    void Init(struct healthd_config* config) override;
+    int PrepareToWait() override;
+    // A subclass may override this if it wants to handle binder events differently.
+    virtual void BinderEvent(uint32_t epevents);
+
+  private:
+    bool unregisterCallbackInternal(const sp<IBase>& callback);
+    int binder_fd_ = -1;
+    std::mutex callbacks_lock_;
+    std::vector<std::unique_ptr<Callback>> callbacks_;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/Callback.h b/health/utils/libhealth2impl/include/health2impl/Callback.h
new file mode 100644
index 0000000..a30480b
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/Callback.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#pragma once
+
+#include <android/hardware/health/2.1/IHealth.h>
+#include <android/hardware/health/2.1/IHealthInfoCallback.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hidl::base::V1_0::IBase;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// Wraps an IHealthInfoCallback.
+class Callback {
+  public:
+    virtual ~Callback() {}
+    virtual Return<void> Notify(const HealthInfo&) = 0;
+    virtual sp<IBase> Get() = 0;
+};
+
+class Callback_2_0 : public Callback {
+  public:
+    Callback_2_0(const sp<V2_0::IHealthInfoCallback>& callback) : callback_(callback) {}
+    Return<void> Notify(const HealthInfo& info) override {
+        return callback_->healthInfoChanged(info.legacy);
+    }
+    sp<IBase> Get() override { return callback_; }
+
+  private:
+    sp<V2_0::IHealthInfoCallback> callback_;
+};
+
+class Callback_2_1 : public Callback {
+  public:
+    Callback_2_1(const sp<IHealthInfoCallback>& callback) : callback_(callback) {}
+    Return<void> Notify(const HealthInfo& info) override {
+        return callback_->healthInfoChanged_2_1(info);
+    }
+    sp<IBase> Get() override { return callback_; }
+
+  private:
+    sp<IHealthInfoCallback> callback_;
+};
+
+inline std::unique_ptr<Callback> Wrap(const sp<V2_0::IHealthInfoCallback>& callback_2_0) {
+    auto callback_2_1 = IHealthInfoCallback::castFrom(callback_2_0).withDefault(nullptr);
+    if (callback_2_1) return std::make_unique<Callback_2_1>(callback_2_1);
+    return std::make_unique<Callback_2_0>(callback_2_0);
+}
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h b/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
new file mode 100644
index 0000000..d9b5580
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/HalHealthLoop.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include <android/hardware/health/2.1/IHealth.h>
+#include <health/HealthLoop.h>
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+// An implementation of HealthLoop for using a given health HAL. This is useful
+// for services that opens the passthrough implementation and starts the HealthLoop
+// to periodically poll data from the implementation.
+class HalHealthLoop : public HealthLoop {
+  public:
+    HalHealthLoop(const std::string& name, const sp<IHealth>& service)
+        : instance_name_(name), service_(service) {}
+
+  protected:
+    virtual void Init(struct healthd_config* config) override;
+    virtual void Heartbeat() override;
+    virtual int PrepareToWait() override;
+    virtual void ScheduleBatteryUpdate() override;
+
+    // HealthLoop periodically calls ScheduleBatteryUpdate, which calls
+    // OnHealthInfoChanged callback. A client can override this function to
+    // broadcast the health_info to interested listeners. By default, this
+    // adjust uevents / wakealarm periods.
+    virtual void OnHealthInfoChanged(const HealthInfo& health_info);
+
+    const std::string& instance_name() const { return instance_name_; }
+    const sp<IHealth>& service() const { return service_; }
+    bool charger_online() const { return charger_online_; }
+
+    // Helpers for subclasses to implement OnHealthInfoChanged.
+    void set_charger_online(const HealthInfo& health_info);
+
+  private:
+    const std::string& instance_name_;
+    sp<IHealth> service_;
+    bool charger_online_ = false;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/health/utils/libhealth2impl/include/health2impl/Health.h b/health/utils/libhealth2impl/include/health2impl/Health.h
new file mode 100644
index 0000000..853b0cd
--- /dev/null
+++ b/health/utils/libhealth2impl/include/health2impl/Health.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#pragma once
+
+#include <memory>
+#include <mutex>
+#include <vector>
+
+#include <android-base/unique_fd.h>
+#include <android/hardware/health/2.1/IHealth.h>
+#include <healthd/BatteryMonitor.h>
+#include <hidl/Status.h>
+
+#include <health2impl/Callback.h>
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hidl::base::V1_0::IBase;
+
+namespace android {
+namespace hardware {
+namespace health {
+namespace V2_1 {
+namespace implementation {
+
+class Health : public IHealth {
+  public:
+    Health(std::unique_ptr<healthd_config>&& config);
+
+    // Methods from ::android::hardware::health::V2_0::IHealth follow.
+    Return<::android::hardware::health::V2_0::Result> registerCallback(
+            const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+    Return<::android::hardware::health::V2_0::Result> unregisterCallback(
+            const sp<::android::hardware::health::V2_0::IHealthInfoCallback>& callback) override;
+    Return<::android::hardware::health::V2_0::Result> update() override;
+    Return<void> getChargeCounter(getChargeCounter_cb _hidl_cb) override;
+    Return<void> getCurrentNow(getCurrentNow_cb _hidl_cb) override;
+    Return<void> getCurrentAverage(getCurrentAverage_cb _hidl_cb) override;
+    Return<void> getCapacity(getCapacity_cb _hidl_cb) override;
+    Return<void> getEnergyCounter(getEnergyCounter_cb _hidl_cb) override;
+    Return<void> getChargeStatus(getChargeStatus_cb _hidl_cb) override;
+    Return<void> getStorageInfo(getStorageInfo_cb _hidl_cb) override;
+    Return<void> getDiskStats(getDiskStats_cb _hidl_cb) override;
+    Return<void> getHealthInfo(getHealthInfo_cb _hidl_cb) override;
+
+    // Methods from ::android::hardware::health::V2_1::IHealth follow.
+    Return<void> getHealthConfig(getHealthConfig_cb _hidl_cb) override;
+    Return<void> getHealthInfo_2_1(getHealthInfo_2_1_cb _hidl_cb) override;
+    Return<void> shouldKeepScreenOn(shouldKeepScreenOn_cb _hidl_cb) override;
+
+    // Methods from ::android::hidl::base::V1_0::IBase follow.
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+  protected:
+    // A subclass can override this to modify any health info object before
+    // returning to clients. This is similar to healthd_board_battery_update().
+    // By default, it does nothing.
+    virtual void UpdateHealthInfo(HealthInfo* health_info);
+
+  private:
+    bool unregisterCallbackInternal(const sp<IBase>& callback);
+
+    BatteryMonitor battery_monitor_;
+    std::unique_ptr<healthd_config> healthd_config_;
+
+    std::mutex callbacks_lock_;
+    std::vector<std::unique_ptr<Callback>> callbacks_;
+};
+
+}  // namespace implementation
+}  // namespace V2_1
+}  // namespace health
+}  // namespace hardware
+}  // namespace android
diff --git a/ir/1.0/vts/functional/Android.bp b/ir/1.0/vts/functional/Android.bp
index f5c9d61..f9edebd 100644
--- a/ir/1.0/vts/functional/Android.bp
+++ b/ir/1.0/vts/functional/Android.bp
@@ -21,5 +21,5 @@
     static_libs: [
         "android.hardware.ir@1.0",
     ],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp b/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
index 5fd2dd4..a5dbdcc 100644
--- a/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
+++ b/ir/1.0/vts/functional/VtsHalIrV1_0TargetTest.cpp
@@ -21,8 +21,9 @@
 #include <android/hardware/ir/1.0/IConsumerIr.h>
 #include <android/hardware/ir/1.0/types.h>
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <algorithm>
 
 using ::android::hardware::ir::V1_0::IConsumerIr;
@@ -31,26 +32,10 @@
 using ::android::hardware::Return;
 using ::android::sp;
 
-// Test environment for Ir
-class ConsumerIrHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static ConsumerIrHidlEnvironment* Instance() {
-    static ConsumerIrHidlEnvironment* instance = new ConsumerIrHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IConsumerIr>(); }
- private:
-  ConsumerIrHidlEnvironment() {}
-};
-
-// The main test class for IR HIDL HAL.
-class ConsumerIrHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class ConsumerIrHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   virtual void SetUp() override {
-    ir = ::testing::VtsHalHidlTargetTestBase::getService<IConsumerIr>(
-      ConsumerIrHidlEnvironment::Instance()->getServiceName<IConsumerIr>());
+    ir = IConsumerIr::getService(GetParam());
     ASSERT_NE(ir, nullptr);
   }
 
@@ -60,7 +45,7 @@
 };
 
 // Test transmit() for the min and max frequency of every available range
-TEST_F(ConsumerIrHidlTest, TransmitTest) {
+TEST_P(ConsumerIrHidlTest, TransmitTest) {
   bool success;
   hidl_vec<ConsumerIrFreqRange> ranges;
   auto cb = [&](bool s, hidl_vec<ConsumerIrFreqRange> v) {
@@ -84,7 +69,7 @@
 }
 
 // Test transmit() when called with invalid frequencies
-TEST_F(ConsumerIrHidlTest, BadFreqTest) {
+TEST_P(ConsumerIrHidlTest, BadFreqTest) {
   uint32_t len = 16;
   hidl_vec<int32_t> vec;
   vec.resize(len);
@@ -92,11 +77,7 @@
   EXPECT_FALSE(ir->transmit(-1, vec));
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(ConsumerIrHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  ConsumerIrHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  LOG(INFO) << "Test result = " << status;
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, ConsumerIrHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IConsumerIr::descriptor)),
+        android::hardware::PrintInstanceNameToString);
diff --git a/neuralnetworks/1.2/types.t b/neuralnetworks/1.2/types.t
index cab330d..d197f6b 100644
--- a/neuralnetworks/1.2/types.t
+++ b/neuralnetworks/1.2/types.t
@@ -41,27 +41,7 @@
 
 enum OperandType : @1.0::OperandType {
 %insert Operand_1.2
-
-    /*
-     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
-     * alternative to OEM operation and data types.
-     *
-     * OEM specific scalar value.
-     * OEM                 = 10000,
-     */
-    /*
-     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
-     * alternative to OEM operation and data types.
-     *
-     * A tensor of OEM specific values.
-     * TENSOR_OEM_BYTE     = 10001,
-     */
-    /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF
-     * OperandTypeRange::FUNDAMENTAL_MAX.
-     */
-    /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF
-     * OperandTypeRange::OEM_MAX.
-     */
+%insert OEMDeprecationAndOperandTypeRangeMaxComment
 };
 
 /**
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index 2beec98..aacb385 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -33,6 +33,7 @@
 
 #include <gtest/gtest.h>
 #include <algorithm>
+#include <chrono>
 #include <iostream>
 #include <numeric>
 
@@ -190,7 +191,8 @@
 }
 static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
         const sp<IPreparedModel>& preparedModel) {
-    return android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
+    return android::nn::ExecutionBurstController::create(preparedModel,
+                                                         std::chrono::microseconds{0});
 }
 enum class Executor { ASYNC, SYNC, BURST };
 
@@ -254,8 +256,10 @@
             }
 
             // execute burst
-            std::tie(executionStatus, outputShapes, timing) =
+            int n;
+            std::tie(n, outputShapes, timing, std::ignore) =
                     controller->compute(request, measure, keys);
+            executionStatus = nn::convertResultCodeToErrorStatus(n);
 
             break;
         }
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
index 1d4493d..416744f 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -26,6 +26,7 @@
 #include "Utils.h"
 
 #include <android-base/logging.h>
+#include <chrono>
 #include <cstring>
 
 namespace android::hardware::neuralnetworks::V1_2::vts::functional {
@@ -64,9 +65,9 @@
 
     // create FMQ objects
     auto [fmqRequestChannel, fmqRequestDescriptor] =
-            RequestChannelSender::create(kExecutionBurstChannelLength, /*blocking=*/true);
+            RequestChannelSender::create(kExecutionBurstChannelLength);
     auto [fmqResultChannel, fmqResultDescriptor] =
-            ResultChannelReceiver::create(resultChannelLength, /*blocking=*/true);
+            ResultChannelReceiver::create(resultChannelLength, std::chrono::microseconds{0});
     ASSERT_NE(nullptr, fmqRequestChannel.get());
     ASSERT_NE(nullptr, fmqResultChannel.get());
     ASSERT_NE(nullptr, fmqRequestDescriptor);
@@ -293,8 +294,10 @@
     }
 
     // collect serialized result by running regular burst
-    const auto [statusRegular, outputShapesRegular, timingRegular] =
+    const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
             controllerRegular->compute(request, MeasureTiming::NO, keys);
+    const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular);
+    EXPECT_FALSE(fallbackRegular);
 
     // skip test if regular burst output isn't useful for testing a failure
     // caused by having too small of a length for the result FMQ
@@ -307,11 +310,13 @@
 
     // by this point, execution should fail because the result channel isn't
     // large enough to return the serialized result
-    const auto [statusSmall, outputShapesSmall, timingSmall] =
+    const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
             controllerSmall->compute(request, MeasureTiming::NO, keys);
+    const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall);
     EXPECT_NE(ErrorStatus::NONE, statusSmall);
     EXPECT_EQ(0u, outputShapesSmall.size());
     EXPECT_TRUE(badTiming(timingSmall));
+    EXPECT_FALSE(fallbackSmall);
 }
 
 static bool isSanitized(const FmqResultDatum& datum) {
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index f25ee62..2d83b81 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
+#include <chrono>
 #include "1.0/Utils.h"
 #include "1.2/Callbacks.h"
 #include "ExecutionBurstController.h"
@@ -94,7 +95,8 @@
 
         // create burst
         std::shared_ptr<::android::nn::ExecutionBurstController> burst =
-                android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
+                android::nn::ExecutionBurstController::create(preparedModel,
+                                                              std::chrono::microseconds{0});
         ASSERT_NE(nullptr, burst.get());
 
         // create memory keys
@@ -104,13 +106,12 @@
         }
 
         // execute and verify
-        ErrorStatus error;
-        std::vector<OutputShape> outputShapes;
-        Timing timing;
-        std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys);
-        EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+        const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys);
+        const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
+        EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
         EXPECT_EQ(outputShapes.size(), 0);
         EXPECT_TRUE(badTiming(timing));
+        EXPECT_FALSE(fallback);
 
         // additional burst testing
         if (request.pools.size() > 0) {
diff --git a/neuralnetworks/1.3/types.hal b/neuralnetworks/1.3/types.hal
index db5dd51..86ab287 100644
--- a/neuralnetworks/1.3/types.hal
+++ b/neuralnetworks/1.3/types.hal
@@ -25,13 +25,6 @@
 
 import android.hidl.safe_union@1.0::Monostate;
 
-/**
- * NOTE: Since NNAPI 1.2, OEM operation and data type are deprecated. Extensions
- * are the preferred alternative.
- *
- * NOTE: Adding a new fundamental type requires updating the value of
- * OperandTypeRange::FUNDAMENTAL_MAX.
- */
 enum OperandType : @1.2::OperandType {
     /**
      * A tensor of 8 bit signed integers that represent real numbers.
@@ -43,10 +36,29 @@
      *
      * The formula is:
      * real_value = (integer_value - zeroPoint) * scale.
-     *
-     * Available since API level 30.
      */
     TENSOR_QUANT8_ASYMM_SIGNED = 14,
+
+    /*
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
+     *
+     * OEM specific scalar value.
+     * OEM                 = 10000,
+     */
+    /*
+     * DEPRECATED. Since HAL version 1.2, extensions are the preferred
+     * alternative to OEM operation and data types.
+     *
+     * A tensor of OEM specific values.
+     * TENSOR_OEM_BYTE     = 10001,
+     */
+    /* ADDING A NEW FUNDAMENTAL TYPE REQUIRES UPDATING THE VALUE OF
+     * OperandTypeRange::FUNDAMENTAL_MAX.
+     */
+    /* ADDING A NEW OEM TYPE REQUIRES UPDATING THE VALUE OF
+     * OperandTypeRange::OEM_MAX.
+     */
 };
 
 /**
diff --git a/neuralnetworks/1.3/types.t b/neuralnetworks/1.3/types.t
new file mode 100644
index 0000000..d41cfd2
--- /dev/null
+++ b/neuralnetworks/1.3/types.t
@@ -0,0 +1,344 @@
+%% template file for generating types.hal.
+%% see frameworks/ml/nn/tools/api/README.md.
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.neuralnetworks@1.3;
+
+import @1.0::DataLocation;
+import @1.0::OperandLifeTime;
+import @1.0::PerformanceInfo;
+import @1.2::OperandType;
+import @1.2::OperationType;
+import @1.2::SymmPerChannelQuantParams;
+
+import android.hidl.safe_union@1.0::Monostate;
+
+enum OperandType : @1.2::OperandType {
+%insert Operand_1.3
+%insert OEMDeprecationAndOperandTypeRangeMaxComment
+};
+
+/**
+ * The range of operand values in the OperandType enum.
+ */
+enum OperandTypeRange : uint32_t {
+    BASE_MIN        = 0,
+    FUNDAMENTAL_MIN = 0,
+%insert Operand_1.3_MAX
+    OEM_MIN         = 10000,
+    OEM_MAX         = 10001,
+    BASE_MAX        = 0xFFFF,
+};
+
+
+/**
+ * The capabilities of a driver.
+ *
+ * Performance of an operation comes from the type of its first operand.
+ * This represents performance for non extension operand types.
+ */
+struct Capabilities {
+    /**
+     * Driver performance when operating on float32 data but performing
+     * calculations with range and/or precision as low as that of the IEEE
+     * 754 16-bit floating-point format.
+     */
+    PerformanceInfo relaxedFloat32toFloat16PerformanceScalar;
+    PerformanceInfo relaxedFloat32toFloat16PerformanceTensor;
+
+    /**
+     * Driver performance when operating on a particular data type.
+     * In the case of float32 data, this is used when the calculations
+     * are not relaxed.
+     */
+    struct OperandPerformance {
+        OperandType type;
+        PerformanceInfo info;
+    };
+
+    /**
+     * Performance by operand type. Must be sorted by OperandType.
+     * If a particular OperandType is not present in operandPerformance,
+     * its performance is treated as
+     * { .execTime = FLT_MAX, .powerUsage = FLT_MAX }.
+     */
+    vec<OperandPerformance> operandPerformance;
+};
+
+/**
+ * Describes one operand of the model's graph.
+ */
+struct Operand {
+    /**
+     * The data type.
+     *
+     * Besides the values listed in {@link OperandType}, any value above
+     * {@link OperandTypeRange::BASE_MAX} is possible and should be interpreted
+     * as an extension type according to {@link Model::extensionNameToPrefix}.
+     */
+    OperandType type;
+
+    /**
+     * Dimensions of the operand.
+     *
+     * For a scalar operand, dimensions.size() must be 0.
+     *
+     * A tensor operand with all dimensions specified has "fully
+     * specified" dimensions. Whenever possible (i.e., whenever the
+     * dimensions are known at model construction time), a tensor
+     * operand should have (but is not required to have) fully
+     * specified dimensions, in order to enable the best possible
+     * performance.
+     *
+     * If a tensor operand's dimensions are not fully specified, the
+     * dimensions of the operand are deduced from the operand
+     * dimensions and values of the operation for which that operand
+     * is an output.
+     *
+     * In the following situations, a tensor operand's dimensions must
+     * be fully specified:
+     *
+     *     . The operand has lifetime CONSTANT_COPY or
+     *       CONSTANT_REFERENCE.
+     *
+     *     . The operand has lifetime MODEL_INPUT. Fully
+     *       specified dimensions must either be present in the
+     *       Operand or they must be provided in the corresponding
+     *       RequestArgument.
+     *       EXCEPTION: If the input is optional and omitted
+     *       (by setting the hasNoValue field of the corresponding
+     *       RequestArgument to true) then it need not have fully
+     *       specified dimensions.
+     *
+     * A tensor operand with some number of unspecified dimensions is
+     * represented by setting each unspecified dimension to 0.
+     *
+     * A tensor operand with unspecified rank is represented by providing
+     * an empty dimensions vector.
+     */
+    vec<uint32_t> dimensions;
+
+    /**
+     * The number of times this operand appears as an operation input.
+     *
+     * (For example, if this operand appears once in one operation's
+     * input list, and three times in another operation's input list,
+     * then numberOfConsumers = 4.)
+     */
+    uint32_t numberOfConsumers;
+
+    /**
+     * Quantized scale of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or
+     * TENSOR_INT32.
+     */
+    float scale;
+
+    /**
+     * Quantized zero-point offset of the operand.
+     *
+     * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM.
+     */
+    int32_t zeroPoint;
+
+    /**
+     * How the operand is used.
+     */
+    OperandLifeTime lifetime;
+
+    /**
+     * Where to find the data for this operand.
+     * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or
+     * NO_VALUE:
+     * - All the fields must be 0.
+     * If the lifetime is CONSTANT_COPY:
+     * - location.poolIndex is 0.
+     * - location.offset is the offset in bytes into Model.operandValues.
+     * - location.length is set.
+     * If the lifetime is CONSTANT_REFERENCE:
+     * - location.poolIndex is set.
+     * - location.offset is the offset in bytes into the specified pool.
+     * - location.length is set.
+     */
+    DataLocation location;
+
+    /**
+     * Additional parameters specific to a particular operand type.
+     */
+    safe_union ExtraParams {
+       /**
+        * No additional parameters.
+        */
+       Monostate none;
+
+       /**
+        * Symmetric per-channel quantization parameters.
+        *
+        * Only applicable to operands of type TENSOR_QUANT8_SYMM_PER_CHANNEL.
+        */
+       SymmPerChannelQuantParams channelQuant;
+
+       /**
+        * Extension operand parameters.
+        *
+        * The framework treats this as an opaque data blob.
+        * The format is up to individual extensions.
+        */
+       vec<uint8_t> extension;
+    } extraParams;
+};
+
+/**
+ * Describes one operation of the model's graph.
+ */
+struct Operation {
+    /**
+     * The operation type.
+     */
+    OperationType type;
+
+    /**
+     * Describes the table that contains the indexes of the inputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> inputs;
+
+    /**
+     * Describes the table that contains the indexes of the outputs of the
+     * operation. The offset is the index in the operandIndexes table.
+     */
+    vec<uint32_t> outputs;
+};
+
+/**
+ * A Neural Network Model.
+ *
+ * This includes not only the execution graph, but also constant data such as
+ * weights or scalars added at construction time. The only information that
+ * may not be known is the shape of the input tensors.
+ */
+struct Model {
+    /**
+     * All operands included in the model.
+     */
+    vec<Operand> operands;
+
+    /**
+     * All operations included in the model.
+     *
+     * The operations are sorted into execution order. Every operand
+     * with lifetime MODEL_OUTPUT or TEMPORARY_VARIABLE must be
+     * written before it is read.
+     */
+    vec<Operation> operations;
+
+    /**
+     * Input indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> inputIndexes;
+
+    /**
+     * Output indexes of the model. There must be at least one.
+     *
+     * Each value corresponds to the index of the operand in "operands".
+     */
+    vec<uint32_t> outputIndexes;
+
+    /**
+     * A byte buffer containing operand data that were copied into the model.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_COPY.
+     */
+    vec<uint8_t> operandValues;
+
+    /**
+     * A collection of shared memory pools containing operand values.
+     *
+     * An operand's value must be located here if and only if Operand::lifetime
+     * equals OperandLifeTime::CONSTANT_REFERENCE.
+     */
+    vec<memory> pools;
+
+    /**
+     * 'true' indicates TENSOR_FLOAT32 may be calculated with range and/or
+     * precision as low as that of the IEEE 754 16-bit floating-point format.
+     * 'false' indicates TENSOR_FLOAT32 must be calculated using at least the
+     * range and precision of the IEEE 754 32-bit floating-point format.
+     */
+    bool relaxComputationFloat32toFloat16;
+
+    /**
+     * The mapping between extension names and prefixes of operand and
+     * operation type values.
+     *
+     * An operand or operation whose numeric type value is above
+     * {@link OperandTypeRange::BASE_MAX} or
+     * {@link OperationTypeRange::BASE_MAX} respectively should be interpreted
+     * as an extension operand. The low
+     * {@link Model::ExtensionTypeEncoding::LOW_BITS_TYPE} bits of the value
+     * correspond to the type ID within the extension and the high
+     * {@link Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX} bits encode
+     * the "prefix", which maps uniquely to the extension name.
+     *
+     * For example, if a model contains an operation whose value is
+     * 0xAAAABBBB and extensionNameToPrefix contains an entry with
+     * prefix=0xAAAA and name="vendor.test.test_extension", then
+     * the operation should be interpreted as the operation 0xBBBB
+     * of the extension named vendor.test.test_extension.
+     *
+     * This is a one-to-one correspondence. That is, there must be at most one
+     * prefix corresponding to each extension name and at most one extension
+     * name corresponding to each prefix.
+     */
+    vec<ExtensionNameAndPrefix> extensionNameToPrefix;
+
+    /**
+     * A correspondence between an extension name and a prefix of operand and
+     * operation type values.
+     */
+    struct ExtensionNameAndPrefix {
+        /**
+         * The extension name.
+         *
+         * See {@link Extension::name} for the format specification.
+         */
+        string name;
+
+        /**
+         * The unique extension identifier within the model.
+         *
+         * See {@link Model::extensionNameToPrefix}.
+         */
+        uint16_t prefix;
+    };
+
+    /**
+     * Numeric values of extension operand and operation types have the
+     * following structure:
+     * - 16 high bits represent the "prefix", which corresponds uniquely to the
+     *   extension name.
+     * - 16 low bits represent the type ID within the extension.
+     */
+    enum ExtensionTypeEncoding : uint8_t {
+        HIGH_BITS_PREFIX = 16,
+        LOW_BITS_TYPE = 16,
+    };
+};
diff --git a/neuralnetworks/1.3/vts/functional/Android.bp b/neuralnetworks/1.3/vts/functional/Android.bp
index 90ce852..0f2720e 100644
--- a/neuralnetworks/1.3/vts/functional/Android.bp
+++ b/neuralnetworks/1.3/vts/functional/Android.bp
@@ -15,7 +15,7 @@
 //
 
 cc_test {
-    name: "VtsHalNeuralNetworksV1_3TargetTest",
+    name: "VtsHalNeuralnetworksV1_3TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "BasicTests.cpp",
diff --git a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
index 16a7d70..8a7ed24 100644
--- a/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.3/vts/functional/GeneratedTestHarness.cpp
@@ -36,6 +36,7 @@
 
 #include <gtest/gtest.h>
 #include <algorithm>
+#include <chrono>
 #include <iostream>
 #include <numeric>
 
@@ -200,7 +201,8 @@
 }
 static std::shared_ptr<::android::nn::ExecutionBurstController> CreateBurst(
         const sp<IPreparedModel>& preparedModel) {
-    return android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
+    return android::nn::ExecutionBurstController::create(preparedModel,
+                                                         std::chrono::microseconds{0});
 }
 enum class Executor { ASYNC, SYNC, BURST };
 
@@ -264,8 +266,10 @@
             }
 
             // execute burst
-            std::tie(executionStatus, outputShapes, timing) =
+            int n;
+            std::tie(n, outputShapes, timing, std::ignore) =
                     controller->compute(request, measure, keys);
+            executionStatus = nn::convertResultCodeToErrorStatus(n);
 
             break;
         }
diff --git a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
index 95f9f42..2c97294 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateBurst.cpp
@@ -26,6 +26,7 @@
 #include "Utils.h"
 
 #include <android-base/logging.h>
+#include <chrono>
 #include <cstring>
 
 namespace android::hardware::neuralnetworks::V1_3::vts::functional {
@@ -71,9 +72,9 @@
 
     // create FMQ objects
     auto [fmqRequestChannel, fmqRequestDescriptor] =
-            RequestChannelSender::create(kExecutionBurstChannelLength, /*blocking=*/true);
+            RequestChannelSender::create(kExecutionBurstChannelLength);
     auto [fmqResultChannel, fmqResultDescriptor] =
-            ResultChannelReceiver::create(resultChannelLength, /*blocking=*/true);
+            ResultChannelReceiver::create(resultChannelLength, std::chrono::microseconds{0});
     ASSERT_NE(nullptr, fmqRequestChannel.get());
     ASSERT_NE(nullptr, fmqResultChannel.get());
     ASSERT_NE(nullptr, fmqRequestDescriptor);
@@ -300,8 +301,10 @@
     }
 
     // collect serialized result by running regular burst
-    const auto [statusRegular, outputShapesRegular, timingRegular] =
+    const auto [nRegular, outputShapesRegular, timingRegular, fallbackRegular] =
             controllerRegular->compute(request, MeasureTiming::NO, keys);
+    const ErrorStatus statusRegular = nn::convertResultCodeToErrorStatus(nRegular);
+    EXPECT_FALSE(fallbackRegular);
 
     // skip test if regular burst output isn't useful for testing a failure
     // caused by having too small of a length for the result FMQ
@@ -314,11 +317,13 @@
 
     // by this point, execution should fail because the result channel isn't
     // large enough to return the serialized result
-    const auto [statusSmall, outputShapesSmall, timingSmall] =
+    const auto [nSmall, outputShapesSmall, timingSmall, fallbackSmall] =
             controllerSmall->compute(request, MeasureTiming::NO, keys);
+    const ErrorStatus statusSmall = nn::convertResultCodeToErrorStatus(nSmall);
     EXPECT_NE(ErrorStatus::NONE, statusSmall);
     EXPECT_EQ(0u, outputShapesSmall.size());
     EXPECT_TRUE(badTiming(timingSmall));
+    EXPECT_FALSE(fallbackSmall);
 }
 
 static bool isSanitized(const FmqResultDatum& datum) {
diff --git a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
index 6122123..c00512c 100644
--- a/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.3/vts/functional/ValidateRequest.cpp
@@ -16,6 +16,7 @@
 
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
+#include <chrono>
 #include "1.0/Utils.h"
 #include "1.2/Callbacks.h"
 #include "ExecutionBurstController.h"
@@ -98,7 +99,8 @@
 
         // create burst
         std::shared_ptr<::android::nn::ExecutionBurstController> burst =
-                android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
+                android::nn::ExecutionBurstController::create(preparedModel,
+                                                              std::chrono::microseconds{0});
         ASSERT_NE(nullptr, burst.get());
 
         // create memory keys
@@ -108,13 +110,12 @@
         }
 
         // execute and verify
-        ErrorStatus error;
-        std::vector<OutputShape> outputShapes;
-        Timing timing;
-        std::tie(error, outputShapes, timing) = burst->compute(request, measure, keys);
-        EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, error);
+        const auto [n, outputShapes, timing, fallback] = burst->compute(request, measure, keys);
+        const ErrorStatus status = nn::convertResultCodeToErrorStatus(n);
+        EXPECT_EQ(ErrorStatus::INVALID_ARGUMENT, status);
         EXPECT_EQ(outputShapes.size(), 0);
         EXPECT_TRUE(badTiming(timing));
+        EXPECT_FALSE(fallback);
 
         // additional burst testing
         if (request.pools.size() > 0) {
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index 421922a..0cefffa 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -4,10 +4,10 @@
       "name": "VtsHalNeuralnetworksV1_0TargetTest",
       "options": [
         {
-          // Just use sample-all driver for presubmit tests for faster results.
-          // The other sample drivers (fast-float, quant, etc.) are subsets of
-          // sample-all.
-          "native-test-flag": "--gtest_filter=*sample_all*"
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
         }
       ]
     },
@@ -15,10 +15,10 @@
       "name": "VtsHalNeuralnetworksV1_1TargetTest",
       "options": [
         {
-          // Just use sample-all driver for presubmit tests for faster results.
-          // The other sample drivers (fast-float, quant, etc.) are subsets of
-          // sample-all.
-          "native-test-flag": "--gtest_filter=*sample_all*"
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
         }
       ]
     },
@@ -26,10 +26,21 @@
       "name": "VtsHalNeuralnetworksV1_2TargetTest",
       "options": [
         {
-          // Just use sample-all driver for presubmit tests for faster results.
-          // The other sample drivers (fast-float, quant, etc.) are subsets of
-          // sample-all.
-          "native-test-flag": "--gtest_filter=*sample_all*"
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
+        }
+      ]
+    },
+    {
+      "name": "VtsHalNeuralnetworksV1_3TargetTest",
+      "options": [
+        {
+          // Do not use any sample driver except sample-all in order to reduce
+          // testing time. The other sample drivers (fast-float, quant, etc.)
+          // are subsets of sample-all.
+          "include-filter": "-*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*"
         }
       ]
     }
diff --git a/radio/1.5/Android.bp b/radio/1.5/Android.bp
new file mode 100644
index 0000000..06a2a6e
--- /dev/null
+++ b/radio/1.5/Android.bp
@@ -0,0 +1,25 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+    name: "android.hardware.radio@1.5",
+    root: "android.hardware",
+    vndk: {
+        enabled: true,
+    },
+    srcs: [
+        "types.hal",
+        "IRadio.hal",
+        "IRadioIndication.hal",
+        "IRadioResponse.hal",
+    ],
+    interfaces: [
+        "android.hardware.radio@1.0",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.4",
+        "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
+    ],
+    gen_java: true,
+}
diff --git a/radio/1.5/IRadio.hal b/radio/1.5/IRadio.hal
new file mode 100644
index 0000000..de20dd0
--- /dev/null
+++ b/radio/1.5/IRadio.hal
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.radio@1.5;
+
+import @1.4::IRadio;
+
+/**
+ * This interface is used by telephony and telecom to talk to cellular radio.
+ * All the functions have minimum one parameter:
+ * serial: which corresponds to serial no. of request. Serial numbers must only be memorized for the
+ * duration of a method call. If clients provide colliding serials (including passing the same
+ * serial to different methods), multiple responses (one for each method call) must still be served.
+ * setResponseFunctions must work with @1.5::IRadioResponse and @1.5::IRadioIndication.
+ */
+interface IRadio extends @1.4::IRadio {
+};
diff --git a/radio/1.5/IRadioIndication.hal b/radio/1.5/IRadioIndication.hal
new file mode 100644
index 0000000..d488404
--- /dev/null
+++ b/radio/1.5/IRadioIndication.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.radio@1.5;
+
+import @1.0::RadioIndicationType;
+import @1.4::IRadioIndication;
+
+/**
+ * Interface declaring unsolicited radio indications.
+ */
+interface IRadioIndication extends @1.4::IRadioIndication {
+};
diff --git a/radio/1.5/IRadioResponse.hal b/radio/1.5/IRadioResponse.hal
new file mode 100644
index 0000000..d4c4f76
--- /dev/null
+++ b/radio/1.5/IRadioResponse.hal
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.radio@1.5;
+
+import @1.0::RadioResponseInfo;
+import @1.4::IRadioResponse;
+
+/**
+ * Interface declaring response functions to solicited radio requests.
+ */
+interface IRadioResponse extends @1.4::IRadioResponse {
+};
diff --git a/radio/1.5/types.hal b/radio/1.5/types.hal
new file mode 100644
index 0000000..a639a8d
--- /dev/null
+++ b/radio/1.5/types.hal
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.radio@1.5;
diff --git a/radio/1.5/vts/OWNERS b/radio/1.5/vts/OWNERS
new file mode 100644
index 0000000..3629a6c
--- /dev/null
+++ b/radio/1.5/vts/OWNERS
@@ -0,0 +1,10 @@
+# Telephony team
+refuhoo@google.com
+amitmahajan@google.com
+jackyu@google.com
+fionaxu@google.com
+# more to add
+
+# VTS team
+yuexima@google.com
+dshi@google.com
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/Android.bp b/radio/1.5/vts/functional/Android.bp
new file mode 100644
index 0000000..85c4f99
--- /dev/null
+++ b/radio/1.5/vts/functional/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2019 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.
+//
+
+cc_test {
+    name: "VtsHalRadioV1_5TargetTest",
+    defaults: ["VtsHalTargetTestDefaults"],
+    srcs: [
+        "radio_hidl_hal_api.cpp",
+        "radio_hidl_hal_test.cpp",
+        "radio_response.cpp",
+        "radio_indication.cpp",
+        "VtsHalRadioV1_5TargetTest.cpp",
+    ],
+    static_libs: [
+        "RadioVtsTestUtilBase",
+        "android.hardware.radio@1.5",
+        "android.hardware.radio@1.4",
+        "android.hardware.radio@1.3",
+        "android.hardware.radio@1.2",
+        "android.hardware.radio@1.1",
+        "android.hardware.radio@1.0",
+        "android.hardware.radio.config@1.0",
+        "android.hardware.radio.config@1.1",
+    ],
+    header_libs: ["radio.util.header@1.0"],
+    test_suites: ["general-tests"]
+}
diff --git a/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
new file mode 100644
index 0000000..b72febd
--- /dev/null
+++ b/radio/1.5/vts/functional/VtsHalRadioV1_5TargetTest.cpp
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+int main(int argc, char** argv) {
+    ::testing::AddGlobalTestEnvironment(RadioHidlEnvironment::Instance());
+    ::testing::InitGoogleTest(&argc, argv);
+    RadioHidlEnvironment::Instance()->init(&argc, argv);
+    int status = RUN_ALL_TESTS();
+    LOG(INFO) << "Test result = " << status;
+    return status;
+}
\ No newline at end of file
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
new file mode 100644
index 0000000..b86fa5f
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+#define ASSERT_OK(ret) ASSERT_TRUE(ret.isOk())
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_test.cpp b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
new file mode 100644
index 0000000..a5d236d
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_test.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+void RadioHidlTest_v1_5::SetUp() {
+    radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
+            ::android::hardware::radio::V1_5::IRadio>(
+            RadioHidlEnvironment::Instance()
+                    ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
+                            hidl_string(RADIO_SERVICE_NAME)));
+    if (radio_v1_5 == NULL) {
+        sleep(60);
+        radio_v1_5 = ::testing::VtsHalHidlTargetTestBase::getService<
+                ::android::hardware::radio::V1_5::IRadio>(
+                RadioHidlEnvironment::Instance()
+                        ->getServiceName<::android::hardware::radio::V1_5::IRadio>(
+                                hidl_string(RADIO_SERVICE_NAME)));
+    }
+    ASSERT_NE(nullptr, radio_v1_5.get());
+
+    radioRsp_v1_5 = new (std::nothrow) RadioResponse_v1_5(*this);
+    ASSERT_NE(nullptr, radioRsp_v1_5.get());
+
+    count_ = 0;
+
+    radioInd_v1_5 = new (std::nothrow) RadioIndication_v1_5(*this);
+    ASSERT_NE(nullptr, radioInd_v1_5.get());
+
+    radio_v1_5->setResponseFunctions(radioRsp_v1_5, radioInd_v1_5);
+
+    updateSimCardStatus();
+    EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);
+    EXPECT_EQ(serial, radioRsp_v1_5->rspInfo.serial);
+    EXPECT_EQ(RadioError::NONE, radioRsp_v1_5->rspInfo.error);
+
+    sp<::android::hardware::radio::config::V1_1::IRadioConfig> radioConfig =
+            ::testing::VtsHalHidlTargetTestBase::getService<
+                    ::android::hardware::radio::config::V1_1::IRadioConfig>();
+
+    /* Enforce Vts tesing with RadioConfig is existed. */
+    ASSERT_NE(nullptr, radioConfig.get());
+
+    /* Enforce Vts Testing with Sim Status Present only. */
+    EXPECT_EQ(CardState::PRESENT, cardStatus.base.base.cardState);
+}
+
+/*
+ * Notify that the response message is received.
+ */
+void RadioHidlTest_v1_5::notify(int receivedSerial) {
+    std::unique_lock<std::mutex> lock(mtx_);
+    if (serial == receivedSerial) {
+        count_++;
+        cv_.notify_one();
+    }
+}
+
+/*
+ * Wait till the response message is notified or till TIMEOUT_PERIOD.
+ */
+std::cv_status RadioHidlTest_v1_5::wait() {
+    std::unique_lock<std::mutex> lock(mtx_);
+
+    std::cv_status status = std::cv_status::no_timeout;
+    auto now = std::chrono::system_clock::now();
+    while (count_ == 0) {
+        status = cv_.wait_until(lock, now + std::chrono::seconds(TIMEOUT_PERIOD));
+        if (status == std::cv_status::timeout) {
+            return status;
+        }
+    }
+    count_--;
+    return status;
+}
+
+void RadioHidlTest_v1_5::updateSimCardStatus() {
+    serial = GetRandomSerialNumber();
+    radio_v1_5->getIccCardStatus(serial);
+    EXPECT_EQ(std::cv_status::no_timeout, wait());
+}
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
new file mode 100644
index 0000000..799702b
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -0,0 +1,760 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <android-base/logging.h>
+
+#include <VtsHalHidlTargetTestBase.h>
+#include <VtsHalHidlTargetTestEnvBase.h>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+
+#include <android/hardware/radio/config/1.1/IRadioConfig.h>
+
+#include <android/hardware/radio/1.5/IRadio.h>
+#include <android/hardware/radio/1.5/IRadioIndication.h>
+#include <android/hardware/radio/1.5/IRadioResponse.h>
+#include <android/hardware/radio/1.5/types.h>
+
+#include "vts_test_util.h"
+
+using namespace ::android::hardware::radio::V1_5;
+using namespace ::android::hardware::radio::V1_4;
+using namespace ::android::hardware::radio::V1_3;
+using namespace ::android::hardware::radio::V1_2;
+using namespace ::android::hardware::radio::V1_1;
+using namespace ::android::hardware::radio::V1_0;
+
+using ::android::sp;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+#define TIMEOUT_PERIOD 75
+#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
+#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
+
+#define RADIO_SERVICE_NAME "slot1"
+
+class RadioHidlTest_v1_5;
+extern ::android::hardware::radio::V1_4::CardStatus cardStatus;
+
+/* Callback class for radio respons v1_5 */
+class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioResponse {
+  protected:
+    RadioHidlTest_v1_5& parent_v1_5;
+
+  public:
+    hidl_vec<RadioBandMode> radioBandModes;
+
+    RadioResponseInfo rspInfo;
+
+    // Call
+    hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls;
+
+    // Modem
+    bool isModemEnabled;
+    bool enableModemResponseToggle;
+
+    ::android::hardware::hidl_bitfield<::android::hardware::radio::V1_4::RadioAccessFamily>
+            networkTypeBitmapResponse;
+
+    // Data
+    ::android::hardware::radio::V1_4::DataRegStateResult dataRegResp;
+
+    // SimLock status
+    ::android::hardware::radio::V1_4::CarrierRestrictionsWithPriority carrierRestrictionsResp;
+    ::android::hardware::radio::V1_4::SimLockMultiSimPolicy multiSimPolicyResp;
+
+    RadioResponse_v1_5(RadioHidlTest_v1_5& parent_v1_5);
+    virtual ~RadioResponse_v1_5() = default;
+
+    Return<void> getIccCardStatusResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::CardStatus& cardStatus);
+
+    Return<void> supplyIccPinForAppResponse(const RadioResponseInfo& info,
+                                            int32_t remainingRetries);
+
+    Return<void> supplyIccPukForAppResponse(const RadioResponseInfo& info,
+                                            int32_t remainingRetries);
+
+    Return<void> supplyIccPin2ForAppResponse(const RadioResponseInfo& info,
+                                             int32_t remainingRetries);
+
+    Return<void> supplyIccPuk2ForAppResponse(const RadioResponseInfo& info,
+                                             int32_t remainingRetries);
+
+    Return<void> changeIccPinForAppResponse(const RadioResponseInfo& info,
+                                            int32_t remainingRetries);
+
+    Return<void> changeIccPin2ForAppResponse(const RadioResponseInfo& info,
+                                             int32_t remainingRetries);
+
+    Return<void> supplyNetworkDepersonalizationResponse(const RadioResponseInfo& info,
+                                                        int32_t remainingRetries);
+
+    Return<void> getCurrentCallsResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& calls);
+
+    Return<void> dialResponse(const RadioResponseInfo& info);
+
+    Return<void> getIMSIForAppResponse(const RadioResponseInfo& info,
+                                       const ::android::hardware::hidl_string& imsi);
+
+    Return<void> hangupConnectionResponse(const RadioResponseInfo& info);
+
+    Return<void> hangupWaitingOrBackgroundResponse(const RadioResponseInfo& info);
+
+    Return<void> hangupForegroundResumeBackgroundResponse(const RadioResponseInfo& info);
+
+    Return<void> switchWaitingOrHoldingAndActiveResponse(const RadioResponseInfo& info);
+
+    Return<void> conferenceResponse(const RadioResponseInfo& info);
+
+    Return<void> rejectCallResponse(const RadioResponseInfo& info);
+
+    Return<void> getLastCallFailCauseResponse(const RadioResponseInfo& info,
+                                              const LastCallFailCauseInfo& failCauseInfo);
+
+    Return<void> getSignalStrengthResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::SignalStrength& sigStrength);
+
+    Return<void> getVoiceRegistrationStateResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::VoiceRegStateResult& voiceRegResponse);
+
+    Return<void> getDataRegistrationStateResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_0::DataRegStateResult& dataRegResponse);
+
+    Return<void> getOperatorResponse(const RadioResponseInfo& info,
+                                     const ::android::hardware::hidl_string& longName,
+                                     const ::android::hardware::hidl_string& shortName,
+                                     const ::android::hardware::hidl_string& numeric);
+
+    Return<void> setRadioPowerResponse(const RadioResponseInfo& info);
+
+    Return<void> sendDtmfResponse(const RadioResponseInfo& info);
+
+    Return<void> sendSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+    Return<void> sendSMSExpectMoreResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+    Return<void> setupDataCallResponse(
+            const RadioResponseInfo& info,
+            const android::hardware::radio::V1_0::SetupDataCallResult& dcResponse);
+
+    Return<void> iccIOForAppResponse(const RadioResponseInfo& info, const IccIoResult& iccIo);
+
+    Return<void> sendUssdResponse(const RadioResponseInfo& info);
+
+    Return<void> cancelPendingUssdResponse(const RadioResponseInfo& info);
+
+    Return<void> getClirResponse(const RadioResponseInfo& info, int32_t n, int32_t m);
+
+    Return<void> setClirResponse(const RadioResponseInfo& info);
+
+    Return<void> getCallForwardStatusResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<CallForwardInfo>& call_forwardInfos);
+
+    Return<void> setCallForwardResponse(const RadioResponseInfo& info);
+
+    Return<void> getCallWaitingResponse(const RadioResponseInfo& info, bool enable,
+                                        int32_t serviceClass);
+
+    Return<void> setCallWaitingResponse(const RadioResponseInfo& info);
+
+    Return<void> acknowledgeLastIncomingGsmSmsResponse(const RadioResponseInfo& info);
+
+    Return<void> acceptCallResponse(const RadioResponseInfo& info);
+
+    Return<void> deactivateDataCallResponse(const RadioResponseInfo& info);
+
+    Return<void> getFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t response);
+
+    Return<void> setFacilityLockForAppResponse(const RadioResponseInfo& info, int32_t retry);
+
+    Return<void> setBarringPasswordResponse(const RadioResponseInfo& info);
+
+    Return<void> getNetworkSelectionModeResponse(const RadioResponseInfo& info, bool manual);
+
+    Return<void> setNetworkSelectionModeAutomaticResponse(const RadioResponseInfo& info);
+
+    Return<void> setNetworkSelectionModeManualResponse(const RadioResponseInfo& info);
+
+    Return<void> getAvailableNetworksResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<OperatorInfo>& networkInfos);
+
+    Return<void> startDtmfResponse(const RadioResponseInfo& info);
+
+    Return<void> stopDtmfResponse(const RadioResponseInfo& info);
+
+    Return<void> getBasebandVersionResponse(const RadioResponseInfo& info,
+                                            const ::android::hardware::hidl_string& version);
+
+    Return<void> separateConnectionResponse(const RadioResponseInfo& info);
+
+    Return<void> setMuteResponse(const RadioResponseInfo& info);
+
+    Return<void> getMuteResponse(const RadioResponseInfo& info, bool enable);
+
+    Return<void> getClipResponse(const RadioResponseInfo& info, ClipStatus status);
+
+    Return<void> getDataCallListResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<
+                    android::hardware::radio::V1_0::SetupDataCallResult>& dcResponse);
+
+    Return<void> sendOemRilRequestRawResponse(const RadioResponseInfo& info,
+                                              const ::android::hardware::hidl_vec<uint8_t>& data);
+
+    Return<void> sendOemRilRequestStringsResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& data);
+
+    Return<void> setSuppServiceNotificationsResponse(const RadioResponseInfo& info);
+
+    Return<void> writeSmsToSimResponse(const RadioResponseInfo& info, int32_t index);
+
+    Return<void> deleteSmsOnSimResponse(const RadioResponseInfo& info);
+
+    Return<void> setBandModeResponse(const RadioResponseInfo& info);
+
+    Return<void> getAvailableBandModesResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<RadioBandMode>& bandModes);
+
+    Return<void> sendEnvelopeResponse(const RadioResponseInfo& info,
+                                      const ::android::hardware::hidl_string& commandResponse);
+
+    Return<void> sendTerminalResponseToSimResponse(const RadioResponseInfo& info);
+
+    Return<void> handleStkCallSetupRequestFromSimResponse(const RadioResponseInfo& info);
+
+    Return<void> explicitCallTransferResponse(const RadioResponseInfo& info);
+
+    Return<void> setPreferredNetworkTypeResponse(const RadioResponseInfo& info);
+
+    Return<void> getPreferredNetworkTypeResponse(const RadioResponseInfo& info,
+                                                 PreferredNetworkType nwType);
+
+    Return<void> getNeighboringCidsResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<NeighboringCell>& cells);
+
+    Return<void> setLocationUpdatesResponse(const RadioResponseInfo& info);
+
+    Return<void> setCdmaSubscriptionSourceResponse(const RadioResponseInfo& info);
+
+    Return<void> setCdmaRoamingPreferenceResponse(const RadioResponseInfo& info);
+
+    Return<void> getCdmaRoamingPreferenceResponse(const RadioResponseInfo& info,
+                                                  CdmaRoamingType type);
+
+    Return<void> setTTYModeResponse(const RadioResponseInfo& info);
+
+    Return<void> getTTYModeResponse(const RadioResponseInfo& info, TtyMode mode);
+
+    Return<void> setPreferredVoicePrivacyResponse(const RadioResponseInfo& info);
+
+    Return<void> getPreferredVoicePrivacyResponse(const RadioResponseInfo& info, bool enable);
+
+    Return<void> sendCDMAFeatureCodeResponse(const RadioResponseInfo& info);
+
+    Return<void> sendBurstDtmfResponse(const RadioResponseInfo& info);
+
+    Return<void> sendCdmaSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+    Return<void> acknowledgeLastIncomingCdmaSmsResponse(const RadioResponseInfo& info);
+
+    Return<void> getGsmBroadcastConfigResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& configs);
+
+    Return<void> setGsmBroadcastConfigResponse(const RadioResponseInfo& info);
+
+    Return<void> setGsmBroadcastActivationResponse(const RadioResponseInfo& info);
+
+    Return<void> getCdmaBroadcastConfigResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& configs);
+
+    Return<void> setCdmaBroadcastConfigResponse(const RadioResponseInfo& info);
+
+    Return<void> setCdmaBroadcastActivationResponse(const RadioResponseInfo& info);
+
+    Return<void> getCDMASubscriptionResponse(const RadioResponseInfo& info,
+                                             const ::android::hardware::hidl_string& mdn,
+                                             const ::android::hardware::hidl_string& hSid,
+                                             const ::android::hardware::hidl_string& hNid,
+                                             const ::android::hardware::hidl_string& min,
+                                             const ::android::hardware::hidl_string& prl);
+
+    Return<void> writeSmsToRuimResponse(const RadioResponseInfo& info, uint32_t index);
+
+    Return<void> deleteSmsOnRuimResponse(const RadioResponseInfo& info);
+
+    Return<void> getDeviceIdentityResponse(const RadioResponseInfo& info,
+                                           const ::android::hardware::hidl_string& imei,
+                                           const ::android::hardware::hidl_string& imeisv,
+                                           const ::android::hardware::hidl_string& esn,
+                                           const ::android::hardware::hidl_string& meid);
+
+    Return<void> exitEmergencyCallbackModeResponse(const RadioResponseInfo& info);
+
+    Return<void> getSmscAddressResponse(const RadioResponseInfo& info,
+                                        const ::android::hardware::hidl_string& smsc);
+
+    Return<void> setSmscAddressResponse(const RadioResponseInfo& info);
+
+    Return<void> reportSmsMemoryStatusResponse(const RadioResponseInfo& info);
+
+    Return<void> reportStkServiceIsRunningResponse(const RadioResponseInfo& info);
+
+    Return<void> getCdmaSubscriptionSourceResponse(const RadioResponseInfo& info,
+                                                   CdmaSubscriptionSource source);
+
+    Return<void> requestIsimAuthenticationResponse(
+            const RadioResponseInfo& info, const ::android::hardware::hidl_string& response);
+
+    Return<void> acknowledgeIncomingGsmSmsWithPduResponse(const RadioResponseInfo& info);
+
+    Return<void> sendEnvelopeWithStatusResponse(const RadioResponseInfo& info,
+                                                const IccIoResult& iccIo);
+
+    Return<void> getVoiceRadioTechnologyResponse(
+            const RadioResponseInfo& info, ::android::hardware::radio::V1_0::RadioTechnology rat);
+
+    Return<void> getCellInfoListResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
+                    cellInfo);
+
+    Return<void> setCellInfoListRateResponse(const RadioResponseInfo& info);
+
+    Return<void> setInitialAttachApnResponse(const RadioResponseInfo& info);
+
+    Return<void> getImsRegistrationStateResponse(const RadioResponseInfo& info, bool isRegistered,
+                                                 RadioTechnologyFamily ratFamily);
+
+    Return<void> sendImsSmsResponse(const RadioResponseInfo& info, const SendSmsResult& sms);
+
+    Return<void> iccTransmitApduBasicChannelResponse(const RadioResponseInfo& info,
+                                                     const IccIoResult& result);
+
+    Return<void> iccOpenLogicalChannelResponse(
+            const RadioResponseInfo& info, int32_t channelId,
+            const ::android::hardware::hidl_vec<int8_t>& selectResponse);
+
+    Return<void> iccCloseLogicalChannelResponse(const RadioResponseInfo& info);
+
+    Return<void> iccTransmitApduLogicalChannelResponse(const RadioResponseInfo& info,
+                                                       const IccIoResult& result);
+
+    Return<void> nvReadItemResponse(const RadioResponseInfo& info,
+                                    const ::android::hardware::hidl_string& result);
+
+    Return<void> nvWriteItemResponse(const RadioResponseInfo& info);
+
+    Return<void> nvWriteCdmaPrlResponse(const RadioResponseInfo& info);
+
+    Return<void> nvResetConfigResponse(const RadioResponseInfo& info);
+
+    Return<void> setUiccSubscriptionResponse(const RadioResponseInfo& info);
+
+    Return<void> setDataAllowedResponse(const RadioResponseInfo& info);
+
+    Return<void> getHardwareConfigResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<HardwareConfig>& config);
+
+    Return<void> requestIccSimAuthenticationResponse(const RadioResponseInfo& info,
+                                                     const IccIoResult& result);
+
+    Return<void> setDataProfileResponse(const RadioResponseInfo& info);
+
+    Return<void> requestShutdownResponse(const RadioResponseInfo& info);
+
+    Return<void> getRadioCapabilityResponse(
+            const RadioResponseInfo& info,
+            const android::hardware::radio::V1_0::RadioCapability& rc);
+
+    Return<void> setRadioCapabilityResponse(
+            const RadioResponseInfo& info,
+            const android::hardware::radio::V1_0::RadioCapability& rc);
+
+    Return<void> startLceServiceResponse(const RadioResponseInfo& info,
+                                         const LceStatusInfo& statusInfo);
+
+    Return<void> stopLceServiceResponse(const RadioResponseInfo& info,
+                                        const LceStatusInfo& statusInfo);
+
+    Return<void> pullLceDataResponse(const RadioResponseInfo& info, const LceDataInfo& lceInfo);
+
+    Return<void> getModemActivityInfoResponse(const RadioResponseInfo& info,
+                                              const ActivityStatsInfo& activityInfo);
+
+    Return<void> setAllowedCarriersResponse(const RadioResponseInfo& info, int32_t numAllowed);
+
+    Return<void> getAllowedCarriersResponse(const RadioResponseInfo& info, bool allAllowed,
+                                            const CarrierRestrictions& carriers);
+
+    Return<void> sendDeviceStateResponse(const RadioResponseInfo& info);
+
+    Return<void> setIndicationFilterResponse(const RadioResponseInfo& info);
+
+    Return<void> setSimCardPowerResponse(const RadioResponseInfo& info);
+
+    Return<void> acknowledgeRequest(int32_t serial);
+
+    /* 1.1 Api */
+    Return<void> setCarrierInfoForImsiEncryptionResponse(const RadioResponseInfo& info);
+
+    Return<void> setSimCardPowerResponse_1_1(const RadioResponseInfo& info);
+
+    Return<void> startNetworkScanResponse(const RadioResponseInfo& info);
+
+    Return<void> stopNetworkScanResponse(const RadioResponseInfo& info);
+
+    Return<void> startKeepaliveResponse(const RadioResponseInfo& info,
+                                        const KeepaliveStatus& status);
+
+    Return<void> stopKeepaliveResponse(const RadioResponseInfo& info);
+
+    /* 1.2 Api */
+    Return<void> setSignalStrengthReportingCriteriaResponse(const RadioResponseInfo& info);
+
+    Return<void> setLinkCapacityReportingCriteriaResponse(const RadioResponseInfo& info);
+
+    Return<void> getIccCardStatusResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_2::CardStatus& card_status);
+
+    Return<void> getCurrentCallsResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls);
+
+    Return<void> getSignalStrengthResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_2::SignalStrength& sig_strength);
+
+    Return<void> getSignalStrengthResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_4::SignalStrength& sig_strength);
+
+    Return<void> getCellInfoListResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
+                    cellInfo);
+
+    Return<void> getVoiceRegistrationStateResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_2::VoiceRegStateResult& voiceRegResponse);
+
+    Return<void> getDataRegistrationStateResponse_1_2(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_2::DataRegStateResult& dataRegResponse);
+
+    /* 1.3 Api */
+    Return<void> setSystemSelectionChannelsResponse(const RadioResponseInfo& info);
+
+    Return<void> enableModemResponse(const RadioResponseInfo& info);
+
+    Return<void> getModemStackStatusResponse(const RadioResponseInfo& info, const bool enabled);
+
+    /* 1.4 Api */
+    Return<void> emergencyDialResponse(const RadioResponseInfo& info);
+
+    Return<void> startNetworkScanResponse_1_4(const RadioResponseInfo& info);
+
+    Return<void> getCellInfoListResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
+                    cellInfo);
+
+    Return<void> getDataRegistrationStateResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse);
+
+    Return<void> getIccCardStatusResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::radio::V1_4::CardStatus& card_status);
+
+    Return<void> getPreferredNetworkTypeBitmapResponse(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_bitfield<
+                    ::android::hardware::radio::V1_4::RadioAccessFamily>
+                    networkTypeBitmap);
+
+    Return<void> setPreferredNetworkTypeBitmapResponse(const RadioResponseInfo& info);
+
+    Return<void> getDataCallListResponse_1_4(
+            const RadioResponseInfo& info,
+            const ::android::hardware::hidl_vec<
+                    ::android::hardware::radio::V1_4::SetupDataCallResult>& dcResponse);
+
+    Return<void> setupDataCallResponse_1_4(
+            const RadioResponseInfo& info,
+            const android::hardware::radio::V1_4::SetupDataCallResult& dcResponse);
+
+    Return<void> setAllowedCarriersResponse_1_4(const RadioResponseInfo& info);
+
+    Return<void> getAllowedCarriersResponse_1_4(const RadioResponseInfo& info,
+                                                const CarrierRestrictionsWithPriority& carriers,
+                                                SimLockMultiSimPolicy multiSimPolicy);
+};
+
+/* Callback class for radio indication */
+class RadioIndication_v1_5 : public ::android::hardware::radio::V1_5::IRadioIndication {
+  protected:
+    RadioHidlTest_v1_5& parent_v1_5;
+
+  public:
+    RadioIndication_v1_5(RadioHidlTest_v1_5& parent_v1_5);
+    virtual ~RadioIndication_v1_5() = default;
+
+    /* 1.4 Api */
+    Return<void> currentEmergencyNumberList(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<EmergencyNumber>& emergencyNumberList);
+
+    Return<void> cellInfoList_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::CellInfo>&
+                    records);
+
+    Return<void> networkScanResult_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_4::NetworkScanResult& result);
+
+    Return<void> currentPhysicalChannelConfigs_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<
+                    ::android::hardware::radio::V1_4::PhysicalChannelConfig>& configs);
+
+    Return<void> dataCallListChanged_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<
+                    android::hardware::radio::V1_4::SetupDataCallResult>& dcList);
+
+    /* 1.2 Api */
+    Return<void> networkScanResult_1_2(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_2::NetworkScanResult& result);
+
+    Return<void> cellInfoList_1_2(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::CellInfo>&
+                    records);
+
+    Return<void> currentLinkCapacityEstimate(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_2::LinkCapacityEstimate& lce);
+
+    Return<void> currentPhysicalChannelConfigs(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<
+                    ::android::hardware::radio::V1_2::PhysicalChannelConfig>& configs);
+
+    Return<void> currentSignalStrength_1_2(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_2::SignalStrength& signalStrength);
+
+    Return<void> currentSignalStrength_1_4(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_4::SignalStrength& signalStrength);
+
+    /* 1.1 Api */
+    Return<void> carrierInfoForImsiEncryption(RadioIndicationType info);
+
+    Return<void> networkScanResult(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_1::NetworkScanResult& result);
+
+    Return<void> keepaliveStatus(RadioIndicationType type, const KeepaliveStatus& status);
+
+    /* 1.0 Api */
+    Return<void> radioStateChanged(RadioIndicationType type, RadioState radioState);
+
+    Return<void> callStateChanged(RadioIndicationType type);
+
+    Return<void> networkStateChanged(RadioIndicationType type);
+
+    Return<void> newSms(RadioIndicationType type,
+                        const ::android::hardware::hidl_vec<uint8_t>& pdu);
+
+    Return<void> newSmsStatusReport(RadioIndicationType type,
+                                    const ::android::hardware::hidl_vec<uint8_t>& pdu);
+
+    Return<void> newSmsOnSim(RadioIndicationType type, int32_t recordNumber);
+
+    Return<void> onUssd(RadioIndicationType type, UssdModeType modeType,
+                        const ::android::hardware::hidl_string& msg);
+
+    Return<void> nitzTimeReceived(RadioIndicationType type,
+                                  const ::android::hardware::hidl_string& nitzTime,
+                                  uint64_t receivedTime);
+
+    Return<void> currentSignalStrength(
+            RadioIndicationType type,
+            const ::android::hardware::radio::V1_0::SignalStrength& signalStrength);
+
+    Return<void> dataCallListChanged(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<
+                    android::hardware::radio::V1_0::SetupDataCallResult>& dcList);
+
+    Return<void> suppSvcNotify(RadioIndicationType type, const SuppSvcNotification& suppSvc);
+
+    Return<void> stkSessionEnd(RadioIndicationType type);
+
+    Return<void> stkProactiveCommand(RadioIndicationType type,
+                                     const ::android::hardware::hidl_string& cmd);
+
+    Return<void> stkEventNotify(RadioIndicationType type,
+                                const ::android::hardware::hidl_string& cmd);
+
+    Return<void> stkCallSetup(RadioIndicationType type, int64_t timeout);
+
+    Return<void> simSmsStorageFull(RadioIndicationType type);
+
+    Return<void> simRefresh(RadioIndicationType type, const SimRefreshResult& refreshResult);
+
+    Return<void> callRing(RadioIndicationType type, bool isGsm, const CdmaSignalInfoRecord& record);
+
+    Return<void> simStatusChanged(RadioIndicationType type);
+
+    Return<void> cdmaNewSms(RadioIndicationType type, const CdmaSmsMessage& msg);
+
+    Return<void> newBroadcastSms(RadioIndicationType type,
+                                 const ::android::hardware::hidl_vec<uint8_t>& data);
+
+    Return<void> cdmaRuimSmsStorageFull(RadioIndicationType type);
+
+    Return<void> restrictedStateChanged(RadioIndicationType type, PhoneRestrictedState state);
+
+    Return<void> enterEmergencyCallbackMode(RadioIndicationType type);
+
+    Return<void> cdmaCallWaiting(RadioIndicationType type,
+                                 const CdmaCallWaiting& callWaitingRecord);
+
+    Return<void> cdmaOtaProvisionStatus(RadioIndicationType type, CdmaOtaProvisionStatus status);
+
+    Return<void> cdmaInfoRec(RadioIndicationType type, const CdmaInformationRecords& records);
+
+    Return<void> indicateRingbackTone(RadioIndicationType type, bool start);
+
+    Return<void> resendIncallMute(RadioIndicationType type);
+
+    Return<void> cdmaSubscriptionSourceChanged(RadioIndicationType type,
+                                               CdmaSubscriptionSource cdmaSource);
+
+    Return<void> cdmaPrlChanged(RadioIndicationType type, int32_t version);
+
+    Return<void> exitEmergencyCallbackMode(RadioIndicationType type);
+
+    Return<void> rilConnected(RadioIndicationType type);
+
+    Return<void> voiceRadioTechChanged(RadioIndicationType type,
+                                       ::android::hardware::radio::V1_0::RadioTechnology rat);
+
+    Return<void> cellInfoList(
+            RadioIndicationType type,
+            const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::CellInfo>&
+                    records);
+
+    Return<void> imsNetworkStateChanged(RadioIndicationType type);
+
+    Return<void> subscriptionStatusChanged(RadioIndicationType type, bool activate);
+
+    Return<void> srvccStateNotify(RadioIndicationType type, SrvccState state);
+
+    Return<void> hardwareConfigChanged(
+            RadioIndicationType type, const ::android::hardware::hidl_vec<HardwareConfig>& configs);
+
+    Return<void> radioCapabilityIndication(
+            RadioIndicationType type, const android::hardware::radio::V1_0::RadioCapability& rc);
+
+    Return<void> onSupplementaryServiceIndication(RadioIndicationType type,
+                                                  const StkCcUnsolSsResult& ss);
+
+    Return<void> stkCallControlAlphaNotify(RadioIndicationType type,
+                                           const ::android::hardware::hidl_string& alpha);
+
+    Return<void> lceData(RadioIndicationType type, const LceDataInfo& lce);
+
+    Return<void> pcoData(RadioIndicationType type, const PcoDataInfo& pco);
+
+    Return<void> modemReset(RadioIndicationType type,
+                            const ::android::hardware::hidl_string& reason);
+};
+
+// Test environment for Radio HIDL HAL.
+class RadioHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
+  public:
+    // get the test environment singleton
+    static RadioHidlEnvironment* Instance() {
+        static RadioHidlEnvironment* instance = new RadioHidlEnvironment;
+        return instance;
+    }
+    virtual void registerTestServices() override {
+        registerTestService<::android::hardware::radio::V1_5::IRadio>();
+    }
+
+  private:
+    RadioHidlEnvironment() {}
+};
+
+// The main test class for Radio HIDL.
+class RadioHidlTest_v1_5 : public ::testing::VtsHalHidlTargetTestBase {
+  protected:
+    std::mutex mtx_;
+    std::condition_variable cv_;
+    int count_;
+
+    /* Serial number for radio request */
+    int serial;
+
+    /* Clear Potential Established Calls */
+    void clearPotentialEstablishedCalls();
+
+    /* Update Sim Card Status */
+    void updateSimCardStatus();
+
+  public:
+    virtual void SetUp() override;
+
+    /* Used as a mechanism to inform the test about data/event callback */
+    void notify(int receivedSerial);
+
+    /* Test code calls this function to wait for response */
+    std::cv_status wait();
+
+    /* radio service handle */
+    sp<::android::hardware::radio::V1_5::IRadio> radio_v1_5;
+
+    /* radio response handle */
+    sp<RadioResponse_v1_5> radioRsp_v1_5;
+
+    /* radio indication handle */
+    sp<RadioIndication_v1_5> radioInd_v1_5;
+};
diff --git a/radio/1.5/vts/functional/radio_indication.cpp b/radio/1.5/vts/functional/radio_indication.cpp
new file mode 100644
index 0000000..b63b745
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_indication.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+RadioIndication_v1_5::RadioIndication_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+
+/* 1.4 Apis */
+Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_4::PhysicalChannelConfig>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_4::NetworkScanResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_4::CellInfo>& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentEmergencyNumberList(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<EmergencyNumber>& /*emergencyNumberList*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<android::hardware::radio::V1_4::SetupDataCallResult>&
+        /*dcList*/) {
+    return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioIndication_v1_5::networkScanResult_1_2(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_2::NetworkScanResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList_1_2(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_2::CellInfo>& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentLinkCapacityEstimate(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_2::LinkCapacityEstimate& /*lce*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentPhysicalChannelConfigs(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_2::PhysicalChannelConfig>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength_1_2(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_2::SignalStrength& /*signalStrength*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength_1_4(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_4::SignalStrength& /*signalStrength*/) {
+    return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioIndication_v1_5::carrierInfoForImsiEncryption(RadioIndicationType /*info*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkScanResult(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_1::NetworkScanResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::keepaliveStatus(RadioIndicationType /*type*/,
+                                                   const KeepaliveStatus& /*status*/) {
+    return Void();
+}
+
+/* 1.0 Apis */
+Return<void> RadioIndication_v1_5::radioStateChanged(RadioIndicationType /*type*/,
+                                                     RadioState /*radioState*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::callStateChanged(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::networkStateChanged(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSms(RadioIndicationType /*type*/,
+                                          const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSmsStatusReport(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*pdu*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::newSmsOnSim(RadioIndicationType /*type*/,
+                                               int32_t /*recordNumber*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::onUssd(RadioIndicationType /*type*/, UssdModeType /*modeType*/,
+                                          const ::android::hardware::hidl_string& /*msg*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::nitzTimeReceived(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*nitzTime*/,
+        uint64_t /*receivedTime*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::currentSignalStrength(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::radio::V1_0::SignalStrength& /*signalStrength*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::dataCallListChanged(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
+        /*dcList*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::suppSvcNotify(RadioIndicationType /*type*/,
+                                                 const SuppSvcNotification& /*suppSvc*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkSessionEnd(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkProactiveCommand(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*cmd*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkEventNotify(RadioIndicationType /*type*/,
+                                                  const ::android::hardware::hidl_string& /*cmd*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkCallSetup(RadioIndicationType /*type*/, int64_t /*timeout*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::simSmsStorageFull(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::simRefresh(RadioIndicationType /*type*/,
+                                              const SimRefreshResult& /*refreshResult*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::callRing(RadioIndicationType /*type*/, bool /*isGsm*/,
+                                            const CdmaSignalInfoRecord& /*record*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::simStatusChanged(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaNewSms(RadioIndicationType /*type*/,
+                                              const CdmaSmsMessage& /*msg*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::newBroadcastSms(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaRuimSmsStorageFull(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::restrictedStateChanged(RadioIndicationType /*type*/,
+                                                          PhoneRestrictedState /*state*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::enterEmergencyCallbackMode(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaCallWaiting(RadioIndicationType /*type*/,
+                                                   const CdmaCallWaiting& /*callWaitingRecord*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaOtaProvisionStatus(RadioIndicationType /*type*/,
+                                                          CdmaOtaProvisionStatus /*status*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaInfoRec(RadioIndicationType /*type*/,
+                                               const CdmaInformationRecords& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::indicateRingbackTone(RadioIndicationType /*type*/,
+                                                        bool /*start*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::resendIncallMute(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaSubscriptionSourceChanged(
+        RadioIndicationType /*type*/, CdmaSubscriptionSource /*cdmaSource*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cdmaPrlChanged(RadioIndicationType /*type*/,
+                                                  int32_t /*version*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::exitEmergencyCallbackMode(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::rilConnected(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::voiceRadioTechChanged(
+        RadioIndicationType /*type*/, ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::cellInfoList(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_0::CellInfo>& /*records*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::imsNetworkStateChanged(RadioIndicationType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::subscriptionStatusChanged(RadioIndicationType /*type*/,
+                                                             bool /*activate*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::srvccStateNotify(RadioIndicationType /*type*/,
+                                                    SrvccState /*state*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::hardwareConfigChanged(
+        RadioIndicationType /*type*/,
+        const ::android::hardware::hidl_vec<HardwareConfig>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::radioCapabilityIndication(
+        RadioIndicationType /*type*/,
+        const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::onSupplementaryServiceIndication(
+        RadioIndicationType /*type*/, const StkCcUnsolSsResult& /*ss*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::stkCallControlAlphaNotify(
+        RadioIndicationType /*type*/, const ::android::hardware::hidl_string& /*alpha*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::lceData(RadioIndicationType /*type*/,
+                                           const LceDataInfo& /*lce*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::pcoData(RadioIndicationType /*type*/,
+                                           const PcoDataInfo& /*pco*/) {
+    return Void();
+}
+
+Return<void> RadioIndication_v1_5::modemReset(RadioIndicationType /*type*/,
+                                              const ::android::hardware::hidl_string& /*reason*/) {
+    return Void();
+}
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
new file mode 100644
index 0000000..1e5cc47
--- /dev/null
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -0,0 +1,887 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <radio_hidl_hal_utils_v1_5.h>
+
+::android::hardware::radio::V1_4::CardStatus cardStatus;
+
+RadioResponse_v1_5::RadioResponse_v1_5(RadioHidlTest_v1_5& parent) : parent_v1_5(parent) {}
+
+/* 1.0 Apis */
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::CardStatus& /*card_status*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+                                                            int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPukForAppResponse(const RadioResponseInfo& /*info*/,
+                                                            int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                             int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyIccPuk2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                             int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::changeIccPinForAppResponse(const RadioResponseInfo& /*info*/,
+                                                            int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::changeIccPin2ForAppResponse(const RadioResponseInfo& /*info*/,
+                                                             int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::supplyNetworkDepersonalizationResponse(
+        const RadioResponseInfo& /*info*/, int32_t /*remainingRetries*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCurrentCallsResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_0::Call>& /*calls*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::dialResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIMSIForAppResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imsi*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupConnectionResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupWaitingOrBackgroundResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::hangupForegroundResumeBackgroundResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::switchWaitingOrHoldingAndActiveResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::conferenceResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::rejectCallResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getLastCallFailCauseResponse(
+        const RadioResponseInfo& /*info*/, const LastCallFailCauseInfo& /*failCauseInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::SignalStrength& /*sig_strength*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::VoiceRegStateResult& /*voiceRegResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_0::DataRegStateResult& /*dataRegResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getOperatorResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*longName*/,
+        const ::android::hardware::hidl_string& /*shortName*/,
+        const ::android::hardware::hidl_string& /*numeric*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioPowerResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendSmsResponse(const RadioResponseInfo& /*info*/,
+                                                 const SendSmsResult& /*sms*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendSMSExpectMoreResponse(const RadioResponseInfo& /*info*/,
+                                                           const SendSmsResult& /*sms*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse(
+        const RadioResponseInfo& /*info*/,
+        const android::hardware::radio::V1_0::SetupDataCallResult& /*dcResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccIOForAppResponse(const RadioResponseInfo& /*info*/,
+                                                     const IccIoResult& /*iccIo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendUssdResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::cancelPendingUssdResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getClirResponse(const RadioResponseInfo& /*info*/, int32_t /*n*/,
+                                                 int32_t /*m*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setClirResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCallForwardStatusResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<CallForwardInfo>&
+        /*callForwardInfos*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCallForwardResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCallWaitingResponse(const RadioResponseInfo& /*info*/,
+                                                        bool /*enable*/, int32_t /*serviceClass*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCallWaitingResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeLastIncomingGsmSmsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acceptCallResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::deactivateDataCallResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
+                                                               int32_t /*response*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setFacilityLockForAppResponse(const RadioResponseInfo& /*info*/,
+                                                               int32_t /*retry*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setBarringPasswordResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getNetworkSelectionModeResponse(const RadioResponseInfo& /*info*/,
+                                                                 bool /*manual*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeAutomaticResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setNetworkSelectionModeManualResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAvailableNetworksResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<OperatorInfo>& /*networkInfos*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getBasebandVersionResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*version*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::separateConnectionResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setMuteResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getMuteResponse(const RadioResponseInfo& /*info*/,
+                                                 bool /*enable*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getClipResponse(const RadioResponseInfo& /*info*/,
+                                                 ClipStatus /*status*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataCallListResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<android::hardware::radio::V1_0::SetupDataCallResult>&
+        /*dcResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendOemRilRequestRawResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_vec<uint8_t>& /*data*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendOemRilRequestStringsResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<::android::hardware::hidl_string>& /*data*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSuppServiceNotificationsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::writeSmsToSimResponse(const RadioResponseInfo& /*info*/,
+                                                       int32_t /*index*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::deleteSmsOnSimResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setBandModeResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAvailableBandModesResponse(
+        const RadioResponseInfo& info,
+        const ::android::hardware::hidl_vec<RadioBandMode>& bandModes) {
+    rspInfo = info;
+    radioBandModes = bandModes;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendEnvelopeResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_string& /*commandResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendTerminalResponseToSimResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::handleStkCallSetupRequestFromSimResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::explicitCallTransferResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredNetworkTypeResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredNetworkTypeResponse(const RadioResponseInfo& /*info*/,
+                                                                 PreferredNetworkType /*nw_type*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getNeighboringCidsResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<NeighboringCell>& /*cells*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setLocationUpdatesResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaSubscriptionSourceResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaRoamingPreferenceResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaRoamingPreferenceResponse(const RadioResponseInfo& /*info*/,
+                                                                  CdmaRoamingType /*type*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setTTYModeResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getTTYModeResponse(const RadioResponseInfo& /*info*/,
+                                                    TtyMode /*mode*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredVoicePrivacyResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredVoicePrivacyResponse(const RadioResponseInfo& /*info*/,
+                                                                  bool /*enable*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCDMAFeatureCodeResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendBurstDtmfResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendCdmaSmsResponse(const RadioResponseInfo& /*info*/,
+                                                     const SendSmsResult& /*sms*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeLastIncomingCdmaSmsResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getGsmBroadcastConfigResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<GsmBroadcastSmsConfigInfo>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setGsmBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setGsmBroadcastActivationResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaBroadcastConfigResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<CdmaBroadcastSmsConfigInfo>& /*configs*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaBroadcastConfigResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCdmaBroadcastActivationResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCDMASubscriptionResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*mdn*/,
+        const ::android::hardware::hidl_string& /*hSid*/,
+        const ::android::hardware::hidl_string& /*hNid*/,
+        const ::android::hardware::hidl_string& /*min*/,
+        const ::android::hardware::hidl_string& /*prl*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::writeSmsToRuimResponse(const RadioResponseInfo& /*info*/,
+                                                        uint32_t /*index*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::deleteSmsOnRuimResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDeviceIdentityResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*imei*/,
+        const ::android::hardware::hidl_string& /*imeisv*/,
+        const ::android::hardware::hidl_string& /*esn*/,
+        const ::android::hardware::hidl_string& /*meid*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::exitEmergencyCallbackModeResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSmscAddressResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*smsc*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSmscAddressResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::reportSmsMemoryStatusResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::reportStkServiceIsRunningResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCdmaSubscriptionSourceResponse(
+        const RadioResponseInfo& /*info*/, CdmaSubscriptionSource /*source*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestIsimAuthenticationResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*response*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeIncomingGsmSmsWithPduResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendEnvelopeWithStatusResponse(const RadioResponseInfo& /*info*/,
+                                                                const IccIoResult& /*iccIo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRadioTechnologyResponse(
+        const RadioResponseInfo& /*info*/,
+        ::android::hardware::radio::V1_0::RadioTechnology /*rat*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_0::CellInfo>& /*cellInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setCellInfoListRateResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setInitialAttachApnResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getImsRegistrationStateResponse(
+        const RadioResponseInfo& /*info*/, bool /*isRegistered*/,
+        RadioTechnologyFamily /*ratFamily*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendImsSmsResponse(const RadioResponseInfo& /*info*/,
+                                                    const SendSmsResult& /*sms*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccTransmitApduBasicChannelResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccOpenLogicalChannelResponse(
+        const RadioResponseInfo& /*info*/, int32_t /*channelId*/,
+        const ::android::hardware::hidl_vec<int8_t>& /*selectResponse*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccCloseLogicalChannelResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::iccTransmitApduLogicalChannelResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvReadItemResponse(
+        const RadioResponseInfo& /*info*/, const ::android::hardware::hidl_string& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvWriteItemResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvWriteCdmaPrlResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::nvResetConfigResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setUiccSubscriptionResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataAllowedResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getHardwareConfigResponse(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<HardwareConfig>& /*config*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestIccSimAuthenticationResponse(
+        const RadioResponseInfo& /*info*/, const IccIoResult& /*result*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setDataProfileResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::requestShutdownResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getRadioCapabilityResponse(
+        const RadioResponseInfo& /*info*/,
+        const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setRadioCapabilityResponse(
+        const RadioResponseInfo& /*info*/,
+        const android::hardware::radio::V1_0::RadioCapability& /*rc*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startLceServiceResponse(const RadioResponseInfo& /*info*/,
+                                                         const LceStatusInfo& /*statusInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopLceServiceResponse(const RadioResponseInfo& /*info*/,
+                                                        const LceStatusInfo& /*statusInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::pullLceDataResponse(const RadioResponseInfo& /*info*/,
+                                                     const LceDataInfo& /*lceInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getModemActivityInfoResponse(
+        const RadioResponseInfo& /*info*/, const ActivityStatsInfo& /*activityInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setAllowedCarriersResponse(const RadioResponseInfo& /*info*/,
+                                                            int32_t /*numAllowed*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAllowedCarriersResponse(
+        const RadioResponseInfo& /*info*/, bool /*allAllowed*/,
+        const CarrierRestrictions& /*carriers*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::sendDeviceStateResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setIndicationFilterResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSimCardPowerResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::acknowledgeRequest(int32_t /*serial*/) {
+    return Void();
+}
+
+/* 1.1 Apis */
+Return<void> RadioResponse_v1_5::setCarrierInfoForImsiEncryptionResponse(
+        const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setSimCardPowerResponse_1_1(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopNetworkScanResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startKeepaliveResponse(const RadioResponseInfo& /*info*/,
+                                                        const KeepaliveStatus& /*status*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::stopKeepaliveResponse(const RadioResponseInfo& /*info*/) {
+    return Void();
+}
+
+/* 1.2 Apis */
+Return<void> RadioResponse_v1_5::setSignalStrengthReportingCriteriaResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setLinkCapacityReportingCriteriaResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_2(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_2::CardStatus& /*card_status*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCurrentCallsResponse_1_2(
+        const RadioResponseInfo& info,
+        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_2::Call>& calls) {
+    rspInfo = info;
+    currentCalls = calls;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse_1_2(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_2::SignalStrength& /*sig_strength*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getSignalStrengthResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_4::SignalStrength& /*sig_strength*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_2(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_2::CellInfo>& /*cellInfo*/) {
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_2(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_2(
+        const RadioResponseInfo& /*info*/,
+        const ::android::hardware::radio::V1_2::DataRegStateResult& /*dataRegResponse*/) {
+    return Void();
+}
+
+/* 1.3 Apis */
+Return<void> RadioResponse_v1_5::setSystemSelectionChannelsResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::enableModemResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getModemStackStatusResponse(const RadioResponseInfo& info,
+                                                             const bool enabled) {
+    rspInfo = info;
+    isModemEnabled = enabled;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+/* 1.4 Apis */
+Return<void> RadioResponse_v1_5::emergencyDialResponse(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::startNetworkScanResponse_1_4(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataRegistrationStateResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_4::DataRegStateResult& dataRegResponse) {
+    rspInfo = info;
+    dataRegResp = dataRegResponse;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::hidl_vec<
+                ::android::hardware::radio::V1_4::CellInfo>& /*cellInfo*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getIccCardStatusResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::radio::V1_4::CardStatus& card_status) {
+    rspInfo = info;
+    cardStatus = card_status;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getPreferredNetworkTypeBitmapResponse(
+        const RadioResponseInfo& info, const ::android::hardware::hidl_bitfield<
+                                               ::android::hardware::radio::V1_4::RadioAccessFamily>
+                                               networkTypeBitmap) {
+    rspInfo = info;
+    networkTypeBitmapResponse = networkTypeBitmap;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setPreferredNetworkTypeBitmapResponse(
+        const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getDataCallListResponse_1_4(
+        const RadioResponseInfo& info,
+        const ::android::hardware::hidl_vec<::android::hardware::radio::V1_4::SetupDataCallResult>&
+        /*dcResponse*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setupDataCallResponse_1_4(
+        const RadioResponseInfo& info,
+        const android::hardware::radio::V1_4::SetupDataCallResult& /*dcResponse*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::setAllowedCarriersResponse_1_4(const RadioResponseInfo& info) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
+
+Return<void> RadioResponse_v1_5::getAllowedCarriersResponse_1_4(
+        const RadioResponseInfo& info, const CarrierRestrictionsWithPriority& carriers,
+        SimLockMultiSimPolicy multiSimPolicy) {
+    rspInfo = info;
+    carrierRestrictionsResp = carriers;
+    multiSimPolicyResp = multiSimPolicy;
+    parent_v1_5.notify(info.serial);
+    return Void();
+}
diff --git a/sensors/2.0/multihal/Android.bp b/sensors/2.0/multihal/Android.bp
new file mode 100644
index 0000000..c13eaf2
--- /dev/null
+++ b/sensors/2.0/multihal/Android.bp
@@ -0,0 +1,73 @@
+//
+// Copyright (C) 2019 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.
+
+cc_defaults {
+    name: "android.hardware.sensors@2.0-multihal-defaults",
+    header_libs: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    cflags: ["-DLOG_TAG=\"SensorsMultiHal\""],
+}
+
+cc_binary {
+    name: "android.hardware.sensors@2.0-service.multihal",
+    defaults: [
+        "hidl_defaults",
+        "android.hardware.sensors@2.0-multihal-defaults",
+    ],
+    vendor: true,
+    relative_install_path: "hw",
+    srcs: [
+        "service.cpp",
+        "HalProxy.cpp",
+        "ScopedWakelock.cpp",
+    ],
+    init_rc: ["android.hardware.sensors@2.0-service-multihal.rc"],
+    vintf_fragments: ["android.hardware.sensors@2.0-multihal.xml"],
+}
+
+cc_library_headers {
+    name: "android.hardware.sensors@2.0-multihal.header",
+    vendor_available: true,
+    export_include_dirs: ["include"],
+}
+
+// The below targets should only be used for testing.
+cc_test_library {
+    name: "android.hardware.sensors@2.0-HalProxy",
+    defaults: ["android.hardware.sensors@2.0-multihal-defaults"],
+    vendor_available: true,
+    srcs: [
+        "HalProxy.cpp",
+        "ScopedWakelock.cpp",
+    ],
+    export_header_lib_headers: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    shared_libs: [
+        "libutils",
+    ],
+}
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
new file mode 100644
index 0000000..49c5a0d
--- /dev/null
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -0,0 +1,686 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "HalProxy.h"
+
+#include "SubHal.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+
+#include <android-base/file.h>
+#include "hardware_legacy/power.h"
+
+#include <dlfcn.h>
+
+#include <cinttypes>
+#include <cmath>
+#include <fstream>
+#include <functional>
+#include <thread>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::getTimeNow;
+using ::android::hardware::sensors::V2_0::implementation::kWakelockTimeoutNs;
+
+typedef ISensorsSubHal*(SensorsHalGetSubHalFunc)(uint32_t*);
+
+static constexpr int32_t kBitsAfterSubHalIndex = 24;
+
+/**
+ * Set the subhal index as first byte of sensor handle and return this modified version.
+ *
+ * @param sensorHandle The sensor handle to modify.
+ * @param subHalIndex The index in the hal proxy of the sub hal this sensor belongs to.
+ *
+ * @return The modified sensor handle.
+ */
+int32_t setSubHalIndex(int32_t sensorHandle, size_t subHalIndex) {
+    return sensorHandle | (static_cast<int32_t>(subHalIndex) << kBitsAfterSubHalIndex);
+}
+
+/**
+ * Extract the subHalIndex from sensorHandle.
+ *
+ * @param sensorHandle The sensorHandle to extract from.
+ *
+ * @return The subhal index.
+ */
+size_t extractSubHalIndex(int32_t sensorHandle) {
+    return static_cast<size_t>(sensorHandle >> kBitsAfterSubHalIndex);
+}
+
+/**
+ * Convert nanoseconds to milliseconds.
+ *
+ * @param nanos The nanoseconds input.
+ *
+ * @return The milliseconds count.
+ */
+int64_t msFromNs(int64_t nanos) {
+    constexpr int64_t nanosecondsInAMillsecond = 1000000;
+    return nanos / nanosecondsInAMillsecond;
+}
+
+HalProxy::HalProxy() {
+    const char* kMultiHalConfigFile = "/vendor/etc/sensors/hals.conf";
+    initializeSubHalListFromConfigFile(kMultiHalConfigFile);
+    init();
+}
+
+HalProxy::HalProxy(std::vector<ISensorsSubHal*>& subHalList) : mSubHalList(subHalList) {
+    init();
+}
+
+HalProxy::~HalProxy() {
+    stopThreads();
+}
+
+Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& iter : mSensors) {
+        sensors.push_back(iter.second);
+    }
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<Result> HalProxy::setOperationMode(OperationMode mode) {
+    Result result = Result::OK;
+    size_t subHalIndex;
+    for (subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+        result = subHal->setOperationMode(mode);
+        if (result != Result::OK) {
+            ALOGE("setOperationMode failed for SubHal: %s", subHal->getName().c_str());
+            break;
+        }
+    }
+    if (result != Result::OK) {
+        // Reset the subhal operation modes that have been flipped
+        for (size_t i = 0; i < subHalIndex; i++) {
+            ISensorsSubHal* subHal = mSubHalList[i];
+            subHal->setOperationMode(mCurrentOperationMode);
+        }
+    } else {
+        mCurrentOperationMode = mode;
+    }
+    return result;
+}
+
+Return<Result> HalProxy::activate(int32_t sensorHandle, bool enabled) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)
+            ->activate(clearSubHalIndex(sensorHandle), enabled);
+}
+
+Return<Result> HalProxy::initialize(
+        const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+        const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+        const sp<ISensorsCallback>& sensorsCallback) {
+    Result result = Result::OK;
+
+    stopThreads();
+    resetSharedWakelock();
+
+    // So that the pending write events queue can be cleared safely and when we start threads
+    // again we do not get new events until after initialize resets the subhals.
+    disableAllSensors();
+
+    // Clears the queue if any events were pending write before.
+    mPendingWriteEventsQueue = std::queue<std::pair<std::vector<Event>, size_t>>();
+
+    // Clears previously connected dynamic sensors
+    mDynamicSensors.clear();
+
+    mDynamicSensorsCallback = sensorsCallback;
+
+    // Create the Event FMQ from the eventQueueDescriptor. Reset the read/write positions.
+    mEventQueue =
+            std::make_unique<EventMessageQueue>(eventQueueDescriptor, true /* resetPointers */);
+
+    // Create the Wake Lock FMQ that is used by the framework to communicate whenever WAKE_UP
+    // events have been successfully read and handled by the framework.
+    mWakeLockQueue =
+            std::make_unique<WakeLockMessageQueue>(wakeLockDescriptor, true /* resetPointers */);
+
+    if (mEventQueueFlag != nullptr) {
+        EventFlag::deleteEventFlag(&mEventQueueFlag);
+    }
+    if (mWakelockQueueFlag != nullptr) {
+        EventFlag::deleteEventFlag(&mWakelockQueueFlag);
+    }
+    if (EventFlag::createEventFlag(mEventQueue->getEventFlagWord(), &mEventQueueFlag) != OK) {
+        result = Result::BAD_VALUE;
+    }
+    if (EventFlag::createEventFlag(mWakeLockQueue->getEventFlagWord(), &mWakelockQueueFlag) != OK) {
+        result = Result::BAD_VALUE;
+    }
+    if (!mDynamicSensorsCallback || !mEventQueue || !mWakeLockQueue || mEventQueueFlag == nullptr) {
+        result = Result::BAD_VALUE;
+    }
+
+    mThreadsRun.store(true);
+
+    mPendingWritesThread = std::thread(startPendingWritesThread, this);
+    mWakelockThread = std::thread(startWakelockThread, this);
+
+    for (size_t i = 0; i < mSubHalList.size(); i++) {
+        auto subHal = mSubHalList[i];
+        const auto& subHalCallback = mSubHalCallbacks[i];
+        Result currRes = subHal->initialize(subHalCallback);
+        if (currRes != Result::OK) {
+            result = currRes;
+            ALOGE("Subhal '%s' failed to initialize.", subHal->getName().c_str());
+            break;
+        }
+    }
+
+    mCurrentOperationMode = OperationMode::NORMAL;
+
+    return result;
+}
+
+Return<Result> HalProxy::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                               int64_t maxReportLatencyNs) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)
+            ->batch(clearSubHalIndex(sensorHandle), samplingPeriodNs, maxReportLatencyNs);
+}
+
+Return<Result> HalProxy::flush(int32_t sensorHandle) {
+    if (!isSubHalIndexValid(sensorHandle)) {
+        return Result::BAD_VALUE;
+    }
+    return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
+}
+
+Return<Result> HalProxy::injectSensorData(const Event& event) {
+    Result result = Result::OK;
+    if (mCurrentOperationMode == OperationMode::NORMAL &&
+        event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) {
+        ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation"
+              " mode was NORMAL.");
+        result = Result::BAD_VALUE;
+    }
+    if (result == Result::OK) {
+        Event subHalEvent = event;
+        if (!isSubHalIndexValid(event.sensorHandle)) {
+            return Result::BAD_VALUE;
+        }
+        subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
+        result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent);
+    }
+    return result;
+}
+
+Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& mem,
+                                             registerDirectChannel_cb _hidl_cb) {
+    if (mDirectChannelSubHal == nullptr) {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+    } else {
+        mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb);
+    }
+    return Return<void>();
+}
+
+Return<Result> HalProxy::unregisterDirectChannel(int32_t channelHandle) {
+    Result result;
+    if (mDirectChannelSubHal == nullptr) {
+        result = Result::INVALID_OPERATION;
+    } else {
+        result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle);
+    }
+    return result;
+}
+
+Return<void> HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+                                          RateLevel rate, configDirectReport_cb _hidl_cb) {
+    if (mDirectChannelSubHal == nullptr) {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */);
+    } else {
+        mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle,
+                                                 rate, _hidl_cb);
+    }
+    return Return<void>();
+}
+
+Return<void> HalProxy::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& /*args*/) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    android::base::borrowed_fd writeFd = dup(fd->data[0]);
+
+    std::ostringstream stream;
+    stream << "===HalProxy===" << std::endl;
+    stream << "Internal values:" << std::endl;
+    stream << "  Threads are running: " << (mThreadsRun.load() ? "true" : "false") << std::endl;
+    int64_t now = getTimeNow();
+    stream << "  Wakelock timeout start time: " << msFromNs(now - mWakelockTimeoutStartTime)
+           << " ms ago" << std::endl;
+    stream << "  Wakelock timeout reset time: " << msFromNs(now - mWakelockTimeoutResetTime)
+           << " ms ago" << std::endl;
+    // TODO(b/142969448): Add logging for history of wakelock acquisition per subhal.
+    stream << "  Wakelock ref count: " << mWakelockRefCount << std::endl;
+    stream << "  Size of pending write events queue: " << mPendingWriteEventsQueue.size()
+           << std::endl;
+    if (!mPendingWriteEventsQueue.empty()) {
+        stream << "  Size of events list on front of pending writes queue: "
+               << mPendingWriteEventsQueue.front().first.size() << std::endl;
+    }
+    stream << "  # of non-dynamic sensors across all subhals: " << mSensors.size() << std::endl;
+    stream << "  # of dynamic sensors across all subhals: " << mDynamicSensors.size() << std::endl;
+    stream << "SubHals (" << mSubHalList.size() << "):" << std::endl;
+    for (ISensorsSubHal* subHal : mSubHalList) {
+        stream << "  Name: " << subHal->getName() << std::endl;
+        stream << "  Debug dump: " << std::endl;
+        android::base::WriteStringToFd(stream.str(), writeFd);
+        subHal->debug(fd, {});
+        stream.str("");
+        stream << std::endl;
+    }
+    android::base::WriteStringToFd(stream.str(), writeFd);
+    return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                                 int32_t subHalIndex) {
+    std::vector<SensorInfo> sensors;
+    {
+        std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+        for (SensorInfo sensor : dynamicSensorsAdded) {
+            if (!subHalIndexIsClear(sensor.sensorHandle)) {
+                ALOGE("Dynamic sensor added %s had sensorHandle with first byte not 0.",
+                      sensor.name.c_str());
+            } else {
+                sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+                mDynamicSensors[sensor.sensorHandle] = sensor;
+                sensors.push_back(sensor);
+            }
+        }
+    }
+    mDynamicSensorsCallback->onDynamicSensorsConnected(sensors);
+    return Return<void>();
+}
+
+Return<void> HalProxy::onDynamicSensorsDisconnected(
+        const hidl_vec<int32_t>& dynamicSensorHandlesRemoved, int32_t subHalIndex) {
+    // TODO(b/143302327): Block this call until all pending events are flushed from queue
+    std::vector<int32_t> sensorHandles;
+    {
+        std::lock_guard<std::mutex> lock(mDynamicSensorsMutex);
+        for (int32_t sensorHandle : dynamicSensorHandlesRemoved) {
+            if (!subHalIndexIsClear(sensorHandle)) {
+                ALOGE("Dynamic sensorHandle removed had first byte not 0.");
+            } else {
+                sensorHandle = setSubHalIndex(sensorHandle, subHalIndex);
+                if (mDynamicSensors.find(sensorHandle) != mDynamicSensors.end()) {
+                    mDynamicSensors.erase(sensorHandle);
+                    sensorHandles.push_back(sensorHandle);
+                }
+            }
+        }
+    }
+    mDynamicSensorsCallback->onDynamicSensorsDisconnected(sensorHandles);
+    return Return<void>();
+}
+
+void HalProxy::initializeSubHalListFromConfigFile(const char* configFileName) {
+    std::ifstream subHalConfigStream(configFileName);
+    if (!subHalConfigStream) {
+        ALOGE("Failed to load subHal config file: %s", configFileName);
+    } else {
+        std::string subHalLibraryFile;
+        while (subHalConfigStream >> subHalLibraryFile) {
+            void* handle = dlopen(subHalLibraryFile.c_str(), RTLD_NOW);
+            if (handle == nullptr) {
+                ALOGE("dlopen failed for library: %s", subHalLibraryFile.c_str());
+            } else {
+                SensorsHalGetSubHalFunc* sensorsHalGetSubHalPtr =
+                        (SensorsHalGetSubHalFunc*)dlsym(handle, "sensorsHalGetSubHal");
+                if (sensorsHalGetSubHalPtr == nullptr) {
+                    ALOGE("Failed to locate sensorsHalGetSubHal function for library: %s",
+                          subHalLibraryFile.c_str());
+                } else {
+                    std::function<SensorsHalGetSubHalFunc> sensorsHalGetSubHal =
+                            *sensorsHalGetSubHalPtr;
+                    uint32_t version;
+                    ISensorsSubHal* subHal = sensorsHalGetSubHal(&version);
+                    if (version != SUB_HAL_2_0_VERSION) {
+                        ALOGE("SubHal version was not 2.0 for library: %s",
+                              subHalLibraryFile.c_str());
+                    } else {
+                        ALOGV("Loaded SubHal from library: %s", subHalLibraryFile.c_str());
+                        mSubHalList.push_back(subHal);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void HalProxy::initializeSubHalCallbacks() {
+    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        sp<IHalProxyCallback> callback = new HalProxyCallback(this, subHalIndex);
+        mSubHalCallbacks.push_back(callback);
+    }
+}
+
+void HalProxy::initializeSensorList() {
+    for (size_t subHalIndex = 0; subHalIndex < mSubHalList.size(); subHalIndex++) {
+        ISensorsSubHal* subHal = mSubHalList[subHalIndex];
+        auto result = subHal->getSensorsList([&](const auto& list) {
+            for (SensorInfo sensor : list) {
+                if (!subHalIndexIsClear(sensor.sensorHandle)) {
+                    ALOGE("SubHal sensorHandle's first byte was not 0");
+                } else {
+                    ALOGV("Loaded sensor: %s", sensor.name.c_str());
+                    sensor.sensorHandle = setSubHalIndex(sensor.sensorHandle, subHalIndex);
+                    setDirectChannelFlags(&sensor, subHal);
+                    mSensors[sensor.sensorHandle] = sensor;
+                }
+            }
+        });
+        if (!result.isOk()) {
+            ALOGE("getSensorsList call failed for SubHal: %s", subHal->getName().c_str());
+        }
+    }
+}
+
+void HalProxy::init() {
+    initializeSubHalCallbacks();
+    initializeSensorList();
+}
+
+void HalProxy::stopThreads() {
+    mThreadsRun.store(false);
+    if (mEventQueueFlag != nullptr && mEventQueue != nullptr) {
+        size_t numToRead = mEventQueue->availableToRead();
+        std::vector<Event> events(numToRead);
+        mEventQueue->read(events.data(), numToRead);
+        mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ));
+    }
+    if (mWakelockQueueFlag != nullptr && mWakeLockQueue != nullptr) {
+        uint32_t kZero = 0;
+        mWakeLockQueue->write(&kZero);
+        mWakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+    }
+    mWakelockCV.notify_one();
+    mEventQueueWriteCV.notify_one();
+    if (mPendingWritesThread.joinable()) {
+        mPendingWritesThread.join();
+    }
+    if (mWakelockThread.joinable()) {
+        mWakelockThread.join();
+    }
+}
+
+void HalProxy::disableAllSensors() {
+    for (const auto& sensorEntry : mSensors) {
+        int32_t sensorHandle = sensorEntry.first;
+        activate(sensorHandle, false /* enabled */);
+    }
+    std::lock_guard<std::mutex> dynamicSensorsLock(mDynamicSensorsMutex);
+    for (const auto& sensorEntry : mDynamicSensors) {
+        int32_t sensorHandle = sensorEntry.first;
+        activate(sensorHandle, false /* enabled */);
+    }
+}
+
+void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
+    halProxy->handlePendingWrites();
+}
+
+void HalProxy::handlePendingWrites() {
+    // TODO(b/143302327): Find a way to optimize locking strategy maybe using two mutexes instead of
+    // one.
+    std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
+    while (mThreadsRun.load()) {
+        mEventQueueWriteCV.wait(
+                lock, [&] { return !mPendingWriteEventsQueue.empty() || !mThreadsRun.load(); });
+        if (mThreadsRun.load()) {
+            std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front().first;
+            size_t numWakeupEvents = mPendingWriteEventsQueue.front().second;
+            size_t eventQueueSize = mEventQueue->getQuantumCount();
+            size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
+            lock.unlock();
+            if (!mEventQueue->writeBlocking(
+                        pendingWriteEvents.data(), numToWrite,
+                        static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+                        static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+                        kPendingWriteTimeoutNs, mEventQueueFlag)) {
+                ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
+                if (numWakeupEvents > 0) {
+                    if (pendingWriteEvents.size() > eventQueueSize) {
+                        decrementRefCountAndMaybeReleaseWakelock(
+                                countNumWakeupEvents(pendingWriteEvents, eventQueueSize));
+                    } else {
+                        decrementRefCountAndMaybeReleaseWakelock(numWakeupEvents);
+                    }
+                }
+            }
+            lock.lock();
+            if (pendingWriteEvents.size() > eventQueueSize) {
+                // TODO(b/143302327): Check if this erase operation is too inefficient. It will copy
+                // all the events ahead of it down to fill gap off array at front after the erase.
+                pendingWriteEvents.erase(pendingWriteEvents.begin(),
+                                         pendingWriteEvents.begin() + eventQueueSize);
+            } else {
+                mPendingWriteEventsQueue.pop();
+            }
+        }
+    }
+}
+
+void HalProxy::startWakelockThread(HalProxy* halProxy) {
+    halProxy->handleWakelocks();
+}
+
+void HalProxy::handleWakelocks() {
+    std::unique_lock<std::recursive_mutex> lock(mWakelockMutex);
+    while (mThreadsRun.load()) {
+        mWakelockCV.wait(lock, [&] { return mWakelockRefCount > 0 || !mThreadsRun.load(); });
+        if (mThreadsRun.load()) {
+            int64_t timeLeft;
+            if (sharedWakelockDidTimeout(&timeLeft)) {
+                resetSharedWakelock();
+            } else {
+                uint32_t numWakeLocksProcessed;
+                lock.unlock();
+                bool success = mWakeLockQueue->readBlocking(
+                        &numWakeLocksProcessed, 1, 0,
+                        static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN), timeLeft);
+                lock.lock();
+                if (success) {
+                    decrementRefCountAndMaybeReleaseWakelock(
+                            static_cast<size_t>(numWakeLocksProcessed));
+                }
+            }
+        }
+    }
+    resetSharedWakelock();
+}
+
+bool HalProxy::sharedWakelockDidTimeout(int64_t* timeLeft) {
+    bool didTimeout;
+    int64_t duration = getTimeNow() - mWakelockTimeoutStartTime;
+    if (duration > kWakelockTimeoutNs) {
+        didTimeout = true;
+    } else {
+        didTimeout = false;
+        *timeLeft = kWakelockTimeoutNs - duration;
+    }
+    return didTimeout;
+}
+
+void HalProxy::resetSharedWakelock() {
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    decrementRefCountAndMaybeReleaseWakelock(mWakelockRefCount);
+    mWakelockTimeoutResetTime = getTimeNow();
+}
+
+void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+                                        ScopedWakelock wakelock) {
+    size_t numToWrite = 0;
+    std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
+    if (wakelock.isLocked()) {
+        incrementRefCountAndMaybeAcquireWakelock(numWakeupEvents);
+    }
+    if (mPendingWriteEventsQueue.empty()) {
+        numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
+        if (numToWrite > 0) {
+            if (mEventQueue->write(events.data(), numToWrite)) {
+                // TODO(b/143302327): While loop if mEventQueue->avaiableToWrite > 0 to possibly fit
+                // in more writes immediately
+                mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+            } else {
+                numToWrite = 0;
+            }
+        }
+    }
+    if (numToWrite < events.size()) {
+        // TODO(b/143302327): Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if
+        // framework stalls
+        std::vector<Event> eventsLeft(events.begin() + numToWrite, events.end());
+        mPendingWriteEventsQueue.push({eventsLeft, numWakeupEvents});
+        mEventQueueWriteCV.notify_one();
+    }
+}
+
+bool HalProxy::incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                        int64_t* timeoutStart /* = nullptr */) {
+    if (!mThreadsRun.load()) return false;
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    if (mWakelockRefCount == 0) {
+        acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakelockName);
+        mWakelockCV.notify_one();
+    }
+    mWakelockTimeoutStartTime = getTimeNow();
+    mWakelockRefCount += delta;
+    if (timeoutStart != nullptr) {
+        *timeoutStart = mWakelockTimeoutStartTime;
+    }
+    return true;
+}
+
+void HalProxy::decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+                                                        int64_t timeoutStart /* = -1 */) {
+    if (!mThreadsRun.load()) return;
+    std::lock_guard<std::recursive_mutex> lockGuard(mWakelockMutex);
+    if (timeoutStart == -1) timeoutStart = mWakelockTimeoutResetTime;
+    if (mWakelockRefCount == 0 || timeoutStart < mWakelockTimeoutResetTime) return;
+    mWakelockRefCount -= std::min(mWakelockRefCount, delta);
+    if (mWakelockRefCount == 0) {
+        release_wake_lock(kWakelockName);
+    }
+}
+
+void HalProxy::setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal) {
+    bool sensorSupportsDirectChannel =
+            (sensorInfo->flags & (V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+                                  V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL)) != 0;
+    if (mDirectChannelSubHal == nullptr && sensorSupportsDirectChannel) {
+        mDirectChannelSubHal = subHal;
+    } else if (mDirectChannelSubHal != nullptr && subHal != mDirectChannelSubHal) {
+        // disable direct channel capability for sensors in subHals that are not
+        // the only one we will enable
+        sensorInfo->flags &= ~(V1_0::SensorFlagBits::MASK_DIRECT_REPORT |
+                               V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+    }
+}
+
+ISensorsSubHal* HalProxy::getSubHalForSensorHandle(int32_t sensorHandle) {
+    return mSubHalList[extractSubHalIndex(sensorHandle)];
+}
+
+bool HalProxy::isSubHalIndexValid(int32_t sensorHandle) {
+    return extractSubHalIndex(sensorHandle) < mSubHalList.size();
+}
+
+size_t HalProxy::countNumWakeupEvents(const std::vector<Event>& events, size_t n) {
+    size_t numWakeupEvents = 0;
+    for (size_t i = 0; i < n; i++) {
+        int32_t sensorHandle = events[i].sensorHandle;
+        if (mSensors[sensorHandle].flags & static_cast<uint32_t>(V1_0::SensorFlagBits::WAKE_UP)) {
+            numWakeupEvents++;
+        }
+    }
+    return numWakeupEvents;
+}
+
+int32_t HalProxy::clearSubHalIndex(int32_t sensorHandle) {
+    return sensorHandle & (~kSensorHandleSubHalIndexMask);
+}
+
+bool HalProxy::subHalIndexIsClear(int32_t sensorHandle) {
+    return (sensorHandle & kSensorHandleSubHalIndexMask) == 0;
+}
+
+void HalProxyCallback::postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) {
+    if (events.empty() || !mHalProxy->areThreadsRunning()) return;
+    size_t numWakeupEvents;
+    std::vector<Event> processedEvents = processEvents(events, &numWakeupEvents);
+    if (numWakeupEvents > 0) {
+        ALOG_ASSERT(wakelock.isLocked(),
+                    "Wakeup events posted while wakelock unlocked for subhal"
+                    " w/ index %zu.",
+                    mSubHalIndex);
+    } else {
+        ALOG_ASSERT(!wakelock.isLocked(),
+                    "No Wakeup events posted but wakelock locked for subhal"
+                    " w/ index %zu.",
+                    mSubHalIndex);
+    }
+    mHalProxy->postEventsToMessageQueue(processedEvents, numWakeupEvents, std::move(wakelock));
+}
+
+ScopedWakelock HalProxyCallback::createScopedWakelock(bool lock) {
+    ScopedWakelock wakelock(mHalProxy, lock);
+    return wakelock;
+}
+
+std::vector<Event> HalProxyCallback::processEvents(const std::vector<Event>& events,
+                                                   size_t* numWakeupEvents) const {
+    *numWakeupEvents = 0;
+    std::vector<Event> eventsOut;
+    for (Event event : events) {
+        event.sensorHandle = setSubHalIndex(event.sensorHandle, mSubHalIndex);
+        eventsOut.push_back(event);
+        const SensorInfo& sensor = mHalProxy->getSensorInfo(event.sensorHandle);
+        if ((sensor.flags & V1_0::SensorFlagBits::WAKE_UP) != 0) {
+            (*numWakeupEvents)++;
+        }
+    }
+    return eventsOut;
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/OWNERS b/sensors/2.0/multihal/OWNERS
new file mode 100644
index 0000000..e955670
--- /dev/null
+++ b/sensors/2.0/multihal/OWNERS
@@ -0,0 +1,3 @@
+arthuri@google.com
+bduddie@google.com
+stange@google.com
\ No newline at end of file
diff --git a/sensors/2.0/multihal/ScopedWakelock.cpp b/sensors/2.0/multihal/ScopedWakelock.cpp
new file mode 100644
index 0000000..d85d4a7
--- /dev/null
+++ b/sensors/2.0/multihal/ScopedWakelock.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "ScopedWakelock.h"
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+int64_t getTimeNow() {
+    return std::chrono::duration_cast<std::chrono::nanoseconds>(
+                   std::chrono::system_clock::now().time_since_epoch())
+            .count();
+}
+
+ScopedWakelock::ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked)
+    : mRefCounter(refCounter), mLocked(locked) {
+    if (mLocked) {
+        mLocked = mRefCounter->incrementRefCountAndMaybeAcquireWakelock(1, &mCreatedAtTimeNs);
+    }
+}
+
+ScopedWakelock::~ScopedWakelock() {
+    if (mLocked) {
+        mRefCounter->decrementRefCountAndMaybeReleaseWakelock(1, mCreatedAtTimeNs);
+    }
+}
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
new file mode 100644
index 0000000..a771100
--- /dev/null
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-multihal.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+    <hal format="hidl">
+        <name>android.hardware.sensors</name>
+        <transport>hwbinder</transport>
+        <version>2.0</version>
+        <interface>
+            <name>ISensors</name>
+            <instance>multihal</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
new file mode 100644
index 0000000..a4da3b0
--- /dev/null
+++ b/sensors/2.0/multihal/android.hardware.sensors@2.0-service-multihal.rc
@@ -0,0 +1,7 @@
+service vendor.sensors-hal-2-0-multihal /vendor/bin/hw/android.hardware.sensors@2.0-service.multihal
+    class hal
+    user system
+    group system wakelock
+    writepid /dev/cpuset/system-background/tasks
+    capabilities BLOCK_SUSPEND
+    rlimit rtprio 10 10
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
new file mode 100644
index 0000000..b1dd737
--- /dev/null
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include "ScopedWakelock.h"
+#include "SubHal.h"
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <android/hardware/sensors/2.0/types.h>
+#include <fmq/MessageQueue.h>
+#include <hardware_legacy/power.h>
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <map>
+#include <mutex>
+#include <queue>
+#include <thread>
+#include <utility>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptor;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+class HalProxy : public ISensors, public IScopedWakelockRefCounter {
+  public:
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    using OperationMode = ::android::hardware::sensors::V1_0::OperationMode;
+    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+    using Result = ::android::hardware::sensors::V1_0::Result;
+    using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+    using ISensorsSubHal = ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
+
+    explicit HalProxy();
+    // Test only constructor.
+    explicit HalProxy(std::vector<ISensorsSubHal*>& subHalList);
+    ~HalProxy();
+
+    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+    Return<Result> setOperationMode(OperationMode mode) override;
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+    Return<Result> initialize(
+            const ::android::hardware::MQDescriptorSync<Event>& eventQueueDescriptor,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& wakeLockDescriptor,
+            const sp<ISensorsCallback>& sensorsCallback) override;
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override;
+
+    Return<Result> flush(int32_t sensorHandle) override;
+
+    Return<Result> injectSensorData(const Event& event) override;
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       registerDirectChannel_cb _hidl_cb) override;
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    configDirectReport_cb _hidl_cb) override;
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+    // Below methods from ::android::hardware::sensors::V2_0::ISensorsCallback with a minor change
+    // to pass in the sub-HAL index. While the above methods are invoked from the sensors framework
+    // via the binder, these methods are invoked from a callback provided to sub-HALs inside the
+    // same process as the HalProxy, but potentially running on different threads.
+    Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& dynamicSensorsAdded,
+                                           int32_t subHalIndex);
+
+    Return<void> onDynamicSensorsDisconnected(const hidl_vec<int32_t>& dynamicSensorHandlesRemoved,
+                                              int32_t subHalIndex);
+
+    // Below methods are for HalProxyCallback
+
+    /**
+     * Post events to the event message queue if there is room to write them. Otherwise post the
+     * remaining events to a background thread for a blocking write with a kPendingWriteTimeoutNs
+     * timeout.
+     *
+     * @param events The list of events to post to the message queue.
+     * @param numWakeupEvents The number of wakeup events in events.
+     * @param wakelock The wakelock associated with this post of events.
+     */
+    void postEventsToMessageQueue(const std::vector<Event>& events, size_t numWakeupEvents,
+                                  ScopedWakelock wakelock);
+
+    /**
+     * Get the sensor info associated with that sensorHandle.
+     *
+     * @param sensorHandle The sensor handle.
+     *
+     * @return The sensor info object in the mapping.
+     */
+    const SensorInfo& getSensorInfo(int32_t sensorHandle) { return mSensors[sensorHandle]; }
+
+    bool areThreadsRunning() { return mThreadsRun.load(); }
+
+    // Below methods are from IScopedWakelockRefCounter interface
+    bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                  int64_t* timeoutStart = nullptr) override;
+
+    void decrementRefCountAndMaybeReleaseWakelock(size_t delta, int64_t timeoutStart = -1) override;
+
+  private:
+    using EventMessageQueue = MessageQueue<Event, kSynchronizedReadWrite>;
+    using WakeLockMessageQueue = MessageQueue<uint32_t, kSynchronizedReadWrite>;
+
+    /**
+     * The Event FMQ where sensor events are written
+     */
+    std::unique_ptr<EventMessageQueue> mEventQueue;
+
+    /**
+     * The Wake Lock FMQ that is read to determine when the framework has handled WAKE_UP events
+     */
+    std::unique_ptr<WakeLockMessageQueue> mWakeLockQueue;
+
+    /**
+     * Event Flag to signal to the framework when sensor events are available to be read and to
+     * interrupt event queue blocking write.
+     */
+    EventFlag* mEventQueueFlag = nullptr;
+
+    //! Event Flag to signal internally that the wakelock queue should stop its blocking read.
+    EventFlag* mWakelockQueueFlag = nullptr;
+
+    /**
+     * Callback to the sensors framework to inform it that new sensors have been added or removed.
+     */
+    sp<ISensorsCallback> mDynamicSensorsCallback;
+
+    /**
+     * SubHal object pointers that have been saved from vendor dynamic libraries.
+     */
+    std::vector<ISensorsSubHal*> mSubHalList;
+
+    //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList
+    std::vector<const sp<IHalProxyCallback>> mSubHalCallbacks;
+
+    /**
+     * Map of sensor handles to SensorInfo objects that contains the sensor info from subhals as
+     * well as the modified sensor handle for the framework.
+     *
+     * The subhal index is encoded in the first byte of the sensor handle and the remaining
+     * bytes are generated by the subhal to identify the sensor.
+     */
+    std::map<int32_t, SensorInfo> mSensors;
+
+    //! Map of the dynamic sensors that have been added to halproxy.
+    std::map<int32_t, SensorInfo> mDynamicSensors;
+
+    //! The current operation mode for all subhals.
+    OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+    //! The single subHal that supports directChannel reporting.
+    ISensorsSubHal* mDirectChannelSubHal = nullptr;
+
+    //! The timeout for each pending write on background thread for events.
+    static const int64_t kPendingWriteTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
+
+    //! The bit mask used to get the subhal index from a sensor handle.
+    static constexpr int32_t kSensorHandleSubHalIndexMask = 0xFF000000;
+
+    /**
+     * A FIFO queue of pairs of vector of events and the number of wakeup events in that vector
+     * which are waiting to be written to the events fmq in the background thread.
+     */
+    std::queue<std::pair<std::vector<Event>, size_t>> mPendingWriteEventsQueue;
+
+    //! The mutex protecting writing to the fmq and the pending events queue
+    std::mutex mEventQueueWriteMutex;
+
+    //! The condition variable waiting on pending write events to stack up
+    std::condition_variable mEventQueueWriteCV;
+
+    //! The thread object ptr that handles pending writes
+    std::thread mPendingWritesThread;
+
+    //! The thread object that handles wakelocks
+    std::thread mWakelockThread;
+
+    //! The bool indicating whether to end the threads started in initialize
+    std::atomic_bool mThreadsRun = true;
+
+    //! The mutex protecting access to the dynamic sensors added and removed methods.
+    std::mutex mDynamicSensorsMutex;
+
+    // WakelockRefCount membar vars below
+
+    //! The mutex protecting the wakelock refcount and subsequent wakelock releases and
+    //! acquisitions
+    std::recursive_mutex mWakelockMutex;
+
+    std::condition_variable_any mWakelockCV;
+
+    //! The refcount of how many ScopedWakelocks and pending wakeup events are active
+    size_t mWakelockRefCount = 0;
+
+    int64_t mWakelockTimeoutStartTime = getTimeNow();
+
+    int64_t mWakelockTimeoutResetTime = getTimeNow();
+
+    const char* kWakelockName = "SensorsHAL_WAKEUP";
+
+    /**
+     * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
+     * listed in a config file.
+     */
+    void initializeSubHalListFromConfigFile(const char* configFileName);
+
+    /**
+     * Initialize the HalProxyCallback vector using the list of subhals.
+     */
+    void initializeSubHalCallbacks();
+
+    /**
+     * Initialize the list of SensorInfo objects in mSensorList by getting sensors from each
+     * subhal.
+     */
+    void initializeSensorList();
+
+    /**
+     * Calls the helper methods that all ctors use.
+     */
+    void init();
+
+    /**
+     * Stops all threads by setting the threads running flag to false and joining to them.
+     */
+    void stopThreads();
+
+    /**
+     * Disable all the sensors observed by the HalProxy.
+     */
+    void disableAllSensors();
+
+    /**
+     * Starts the thread that handles pending writes to event fmq.
+     *
+     * @param halProxy The HalProxy object pointer.
+     */
+    static void startPendingWritesThread(HalProxy* halProxy);
+
+    //! Handles the pending writes on events to eventqueue.
+    void handlePendingWrites();
+
+    /**
+     * Starts the thread that handles decrementing the ref count on wakeup events processed by the
+     * framework and timing out wakelocks.
+     *
+     * @param halProxy The HalProxy object pointer.
+     */
+    static void startWakelockThread(HalProxy* halProxy);
+
+    //! Handles the wakelocks.
+    void handleWakelocks();
+
+    /**
+     * @param timeLeft The variable that should be set to the timeleft before timeout will occur or
+     * unmodified if timeout occurred.
+     *
+     * @return true if the shared wakelock has been held passed the timeout and should be released
+     */
+    bool sharedWakelockDidTimeout(int64_t* timeLeft);
+
+    /**
+     * Reset all the member variables associated with the wakelock ref count and maybe release
+     * the shared wakelock.
+     */
+    void resetSharedWakelock();
+
+    /**
+     * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
+     * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
+     * direct channel enabled sensor seen.
+     *
+     * @param sensorInfo The SensorInfo object that may be altered to have direct channel support
+     *    disabled.
+     * @param subHal The subhal pointer that the current sensorInfo object came from.
+     */
+    void setDirectChannelFlags(SensorInfo* sensorInfo, ISensorsSubHal* subHal);
+
+    /*
+     * Get the subhal pointer which can be found by indexing into the mSubHalList vector
+     * using the index from the first byte of sensorHandle.
+     *
+     * @param sensorHandle The handle used to identify a sensor in one of the subhals.
+     */
+    ISensorsSubHal* getSubHalForSensorHandle(int32_t sensorHandle);
+
+    /**
+     * Checks that sensorHandle's subhal index byte is within bounds of mSubHalList.
+     *
+     * @param sensorHandle The sensor handle to check.
+     *
+     * @return true if sensorHandles's subhal index byte is valid.
+     */
+    bool isSubHalIndexValid(int32_t sensorHandle);
+
+    /**
+     * Count the number of wakeup events in the first n events of the vector.
+     *
+     * @param events The vector of Event objects.
+     * @param n The end index not inclusive of events to consider.
+     *
+     * @return The number of wakeup events of the considered events.
+     */
+    size_t countNumWakeupEvents(const std::vector<Event>& events, size_t n);
+
+    /*
+     * Clear out the subhal index bytes from a sensorHandle.
+     *
+     * @param sensorHandle The sensor handle to modify.
+     *
+     * @return The modified version of the sensor handle.
+     */
+    static int32_t clearSubHalIndex(int32_t sensorHandle);
+
+    /**
+     * @param sensorHandle The sensor handle to modify.
+     *
+     * @return true if subHalIndex byte of sensorHandle is zeroed.
+     */
+    static bool subHalIndexIsClear(int32_t sensorHandle);
+};
+
+/**
+ * Callback class used to provide the HalProxy with the index of which subHal is invoking
+ */
+class HalProxyCallback : public IHalProxyCallback {
+    using SensorInfo = ::android::hardware::sensors::V1_0::SensorInfo;
+
+  public:
+    HalProxyCallback(HalProxy* halProxy, int32_t subHalIndex)
+        : mHalProxy(halProxy), mSubHalIndex(subHalIndex) {}
+
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+        return mHalProxy->onDynamicSensorsConnected(dynamicSensorsAdded, mSubHalIndex);
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        return mHalProxy->onDynamicSensorsDisconnected(dynamicSensorHandlesRemoved, mSubHalIndex);
+    }
+
+    void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock);
+
+    ScopedWakelock createScopedWakelock(bool lock);
+
+  private:
+    HalProxy* mHalProxy;
+    int32_t mSubHalIndex;
+
+    std::vector<Event> processEvents(const std::vector<Event>& events,
+                                     size_t* numWakeupEvents) const;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/include/ScopedWakelock.h b/sensors/2.0/multihal/include/ScopedWakelock.h
new file mode 100644
index 0000000..aa6d9db
--- /dev/null
+++ b/sensors/2.0/multihal/include/ScopedWakelock.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/2.0/types.h>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+
+const int64_t kWakelockTimeoutNs =
+        static_cast<int64_t>(SensorTimeout::WAKE_LOCK_SECONDS) * INT64_C(1000000000);
+
+int64_t getTimeNow();
+
+class IScopedWakelockRefCounter : public RefBase {
+  public:
+    /**
+     * Increment the wakelock ref count and maybe acquire the shared wakelock if incrementing
+     * from 0 then return the time of incrementing back to caller.
+     *
+     * @param delta The amount to change ref count by.
+     * @param timeoutStart The ptr to the timestamp in ns that the increment occurred which will be
+     *        set in the function or nullptr if not specified.
+     *
+     * @return true if successfully incremented the wakelock ref count.
+     */
+    virtual bool incrementRefCountAndMaybeAcquireWakelock(size_t delta,
+                                                          int64_t* timeoutStart = nullptr) = 0;
+    /**
+     * Decrement the wakelock ref count and maybe release wakelock if ref count ends up 0.
+     *
+     * @param delta The amount to change ref count by.
+     * @param timeoutStart The timestamp in ns that the calling context kept track of when
+     *        incrementing the ref count or -1 by default
+     */
+    virtual void decrementRefCountAndMaybeReleaseWakelock(size_t delta,
+                                                          int64_t timeoutStart = -1) = 0;
+    // Virtual dtor needed for compilation success
+    virtual ~IScopedWakelockRefCounter(){};
+};
+
+/**
+ * Wrapper around wake lock acquisition functions (acquire/release_wake_lock) that provides a
+ * RAII-style mechanism for keeping a wake lock held for the duration of a scoped block.
+ * When a ScopedWakelock is created, it increments the reference count stored in the HalProxy
+ * for the sub-HALs specific wake lock, acquiring the wake lock if necessary. When the object goes
+ * out of scope, the ref count is decremented, potentially releasing the wake lock if no other
+ * references to the wake lock exist.
+ *
+ * This class is allocated through the createScopedWakelock callback inside the IHalProxyCallback
+ * provided to sub-HALs during initialization and should be used for all wake lock acquisition
+ * inside of the sub-HAL to ensure wake locks are not held indefinitely.
+ *
+ * The most prevalent use case for this class will be for posting events to the framework through
+ * the postEvents HalProxy callback. The expectation is that sub-HALs will create this
+ * ScopedWakelock through the createScopedWakelock upon receiving a sensor events. The lock boolean
+ * provided to createScopedWakelock will be set the according to whether the sensor events are
+ * from wakeup sensors. Then, the sub-HAL will perform any processing necessary before invoking the
+ * postEvents callback passing in the previously created ScopedWakelock. At this point, ownership
+ * of the object will be passed to the HalProxy that will then be responsible for ensuring any
+ * wake locks continue to be held, if necessary.
+ */
+class ScopedWakelock {
+  public:
+    ScopedWakelock(ScopedWakelock&&) = default;
+    ScopedWakelock& operator=(ScopedWakelock&&) = default;
+    virtual ~ScopedWakelock();
+
+    bool isLocked() const { return mLocked; }
+
+  private:
+    friend class HalProxyCallback;
+    IScopedWakelockRefCounter* mRefCounter;
+    int64_t mCreatedAtTimeNs;
+    bool mLocked;
+    ScopedWakelock(IScopedWakelockRefCounter* refCounter, bool locked);
+    ScopedWakelock(const ScopedWakelock&) = delete;
+    ScopedWakelock& operator=(const ScopedWakelock&) = delete;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/sensors/2.0/multihal/include/SubHal.h b/sensors/2.0/multihal/include/SubHal.h
new file mode 100644
index 0000000..92ae3a6
--- /dev/null
+++ b/sensors/2.0/multihal/include/SubHal.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include "ScopedWakelock.h"
+
+#include <android/hardware/sensors/1.0/types.h>
+#include <android/hardware/sensors/2.0/ISensors.h>
+
+#include <vector>
+
+// Indicates the current version of the multiHAL interface formatted as (HAL major version) << 24 |
+// (HAL minor version) << 16 | (multiHAL version)
+#define SUB_HAL_2_0_VERSION 0x02000000
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+
+/**
+ * Interface that contains several callbacks into the HalProxy class to communicate dynamic sensor
+ * changes and sensor events to the framework and acquire wake locks. The HalProxy will ensure
+ * callbacks occurring at the same time from multiple sub-HALs are synchronized in a safe, efficient
+ * manner.
+ */
+class IHalProxyCallback : public ISensorsCallback {
+  public:
+    /**
+     * Thread-safe callback used to post events to the HalProxy. Sub-HALs should invoke this
+     * whenever new sensor events need to be delivered to the sensors framework. Once invoked, the
+     * HalProxy will attempt to send events to the sensors framework using a blocking write with a
+     * 5 second timeout. This write may be done asynchronously if the queue used to communicate
+     * with the framework is full to avoid blocking sub-HALs for the length of the timeout. If the
+     * write fails, the events will be dropped and any wake locks held will be released.
+     *
+     * The provided ScopedWakelock must be locked if the events are from wakeup sensors. If it's
+     * not locked accordingly, the HalProxy will crash as this indicates the sub-HAL isn't compliant
+     * with the sensors HAL 2.0 specification. Additionally, since ScopedWakelock isn't copyable,
+     * the HalProxy will take ownership of the wake lock given when this method is invoked. Once the
+     * method returns, the HalProxy will handle holding the wake lock, if necessary, until the
+     * framework has successfully processed any wakeup events.
+     *
+     * No return type is used for this callback to avoid sub-HALs trying to resend events when
+     * writes fail. Writes should only fail when the framework is under inordinate stress which will
+     * likely result in a framework restart so retrying will likely only result in overloading the
+     * HalProxy. Sub-HALs should always assume that the write was a success and perform any
+     * necessary cleanup. Additionally, the HalProxy will ensure it logs any errors (through ADB and
+     * bug reports) it encounters during delivery to ensure it's obvious that a failure occurred.
+     *
+     * @param events the events that should be sent to the sensors framework
+     * @param wakelock ScopedWakelock that should be locked to send events from wake sensors and
+     *     unlocked otherwise.
+     */
+    virtual void postEvents(const std::vector<Event>& events, ScopedWakelock wakelock) = 0;
+
+    /**
+     * Initializes a ScopedWakelock on the stack that, when locked, will increment the reference
+     * count for the sub-HAL's wake lock managed inside the HalProxy. See the ScopedWakelock class
+     * definition for how it should be used.
+     *
+     * @param lock whether the ScopedWakelock should be locked before it's returned.
+     * @return the created ScopedWakelock
+     */
+    virtual ScopedWakelock createScopedWakelock(bool lock) = 0;
+};
+
+/**
+ * ISensorsSubHal is an interface that sub-HALs must implement in order to be compliant with
+ * multihal 2.0 and in order for the HalProxy to successfully load and communicate with the sub-HAL.
+ *
+ * Any vendor wishing to implement this interface and support multihal 2.0 will need to create a
+ * dynamic library that exposes sensorsHalGetSubHal (defined below). This library will be loaded by
+ * the HalProxy when the sensors HAL is initialized and then the HalProxy will retrieve the vendor's
+ * implementation of sensorsHalGetSubHal.
+ *
+ * With the exception of the initialize method, ISensorsSubHal will implement the ISensors.hal spec.
+ * Any sensor handles given to the HalProxy, either through getSensorsList() or the
+ * onDynamicSensors(Dis)Connected callbacks, will be translated to avoid clashing with other sub-HAL
+ * handles. To achieve this, the HalProxy will use the upper byte to store the sub-HAL index and
+ * sub-HALs can continue to use the lower 3 bytes of the handle.
+ */
+class ISensorsSubHal : public ISensors {
+  public:
+    // The ISensors version of initialize isn't used for multihal. Instead, sub-HALs must implement
+    // the version below to allow communciation logic to centralized in the HalProxy
+    Return<Result> initialize(
+            const ::android::hardware::MQDescriptorSync<Event>& /* eventQueueDescriptor */,
+            const ::android::hardware::MQDescriptorSync<uint32_t>& /* wakeLockDescriptor */,
+            const sp<ISensorsCallback>& /* sensorsCallback */) final {
+        return Result::INVALID_OPERATION;
+    }
+
+    /**
+     * Method defined in ::android::hidl::base::V1_0::IBase.
+     *
+     * This method should write debug information to hidl_handle that is useful for debugging
+     * issues. Suggestions include:
+     * - Sensor info including handle values and any other state available in the SensorInfo class
+     * - List of active sensors and their current sampling period and reporting latency
+     * - Information about pending flush requests
+     * - Current operating mode
+     * - Currently registered direct channel info
+     * - A history of any of the above
+     */
+    virtual Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) = 0;
+
+    /**
+     * @return A human-readable name for use in wake locks and logging.
+     */
+    virtual const std::string getName() = 0;
+
+    /**
+     * This is the first method invoked on the sub-HAL after it's allocated through
+     * sensorsHalGetSubHal() by the HalProxy. Sub-HALs should use this to initialize any state and
+     * retain the callback given in order to communicate with the HalProxy. Method will be called
+     * anytime the sensors framework restarts. Therefore, this method will be responsible for
+     * reseting the state of the subhal and cleaning up and reallocating any previously allocated
+     * data. Initialize should ensure that the subhal has reset its operation mode to NORMAL state
+     * as well.
+     *
+     * @param halProxyCallback callback used to inform the HalProxy when a dynamic sensor's state
+     *     changes, new sensor events should be sent to the framework, and when a new ScopedWakelock
+     *     should be created.
+     * @return result OK on success
+     */
+    virtual Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) = 0;
+};
+
+}  // namespace implementation
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
+
+using ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal;
+
+/**
+ * Function that must be exported so the HalProxy class can invoke it on the sub-HAL dynamic
+ * library. This function will only be invoked once at initialization time.
+ *
+ * NOTE: The supported sensors HAL version must match SUB_HAL_2_0_VERSION exactly or the HalProxy
+ * will fail to initialize.
+ *
+ * @param uint32_t when this function returns, this parameter must contain the HAL version that
+ *     this sub-HAL supports. To support this version of multi-HAL, this must be set to
+ *     SUB_HAL_2_0_VERSION.
+ * @return A statically allocated, valid ISensorsSubHal implementation.
+ */
+__attribute__((visibility("default"))) extern "C" ISensorsSubHal* sensorsHalGetSubHal(
+        uint32_t* version);
diff --git a/sensors/2.0/multihal/service.cpp b/sensors/2.0/multihal/service.cpp
new file mode 100644
index 0000000..ef77048
--- /dev/null
+++ b/sensors/2.0/multihal/service.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include <android/hardware/sensors/2.0/ISensors.h>
+#include <hidl/HidlTransportSupport.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+#include "HalProxy.h"
+
+using android::hardware::configureRpcThreadpool;
+using android::hardware::joinRpcThreadpool;
+using android::hardware::sensors::V2_0::ISensors;
+using android::hardware::sensors::V2_0::implementation::HalProxy;
+
+int main(int /* argc */, char** /* argv */) {
+    configureRpcThreadpool(1, true);
+
+    android::sp<ISensors> halProxy = new HalProxy();
+    if (halProxy->registerAsService() != ::android::OK) {
+        ALOGE("Failed to register Sensors HAL instance");
+        return -1;
+    }
+
+    joinRpcThreadpool();
+    return 1;  // joinRpcThreadpool shouldn't exit
+}
diff --git a/sensors/2.0/multihal/tests/Android.bp b/sensors/2.0/multihal/tests/Android.bp
new file mode 100644
index 0000000..e7f9499
--- /dev/null
+++ b/sensors/2.0/multihal/tests/Android.bp
@@ -0,0 +1,99 @@
+//
+// Copyright (C) 2019 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.
+
+cc_defaults {
+    name: "android.hardware.sensors@2.0-fakesubhal-defaults",
+    srcs: [
+        "fake_subhal/*.cpp",
+    ],
+    header_libs: [
+        "android.hardware.sensors@2.0-multihal.header",
+    ],
+    export_include_dirs: ["fake_subhal"],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    static_libs: [
+        "android.hardware.sensors@2.0-HalProxy",
+    ],
+    cflags: [
+        "-DLOG_TAG=\"FakeSubHal\""
+    ],
+}
+
+cc_library {
+    name: "android.hardware.sensors@2.0-fakesubhal-config1",
+    vendor: true,
+    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+    cflags: [
+        "-DSUPPORT_CONTINUOUS_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-Continuous\"",
+    ],
+}
+
+cc_library {
+    name: "android.hardware.sensors@2.0-fakesubhal-config2",
+    vendor: true,
+    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+    cflags: [
+        "-DSUPPORT_ON_CHANGE_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-OnChange\"",
+    ],
+}
+
+cc_test_library {
+    name: "android.hardware.sensors@2.0-fakesubhal-unittest",
+    vendor_available: true,
+    defaults: ["android.hardware.sensors@2.0-fakesubhal-defaults"],
+    cflags: [
+        "-DSUPPORT_ON_CHANGE_SENSORS",
+        "-DSUPPORT_CONTINUOUS_SENSORS",
+        "-DSUB_HAL_NAME=\"FakeSubHal-Test\"",
+    ],
+}
+
+cc_test {
+    name: "android.hardware.sensors@2.0-halproxy-unit-tests",
+    srcs: ["HalProxy_test.cpp"],
+    vendor: true,
+    static_libs: [
+        "android.hardware.sensors@2.0-HalProxy",
+        "android.hardware.sensors@2.0-fakesubhal-unittest",
+    ],
+    shared_libs: [
+        "android.hardware.sensors@1.0",
+        "android.hardware.sensors@2.0",
+        "libbase",
+        "libcutils",
+        "libfmq",
+        "libhardware",
+        "libhidlbase",
+        "liblog",
+        "libpower",
+        "libutils",
+    ],
+    test_suites: ["device-tests"],
+    cflags: [
+        "-DLOG_TAG=\"HalProxyUnitTests\"",
+    ],
+}
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
new file mode 100644
index 0000000..1fd35d1
--- /dev/null
+++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp
@@ -0,0 +1,833 @@
+//
+// Copyright (C) 2019 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.
+
+#include <gtest/gtest.h>
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <fmq/MessageQueue.h>
+
+#include "HalProxy.h"
+#include "ScopedWakelock.h"
+#include "SensorsSubHal.h"
+
+#include <chrono>
+#include <set>
+#include <thread>
+#include <vector>
+
+namespace {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::Return;
+using ::android::hardware::sensors::V1_0::EventPayload;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+using ::android::hardware::sensors::V2_0::EventQueueFlagBits;
+using ::android::hardware::sensors::V2_0::ISensorsCallback;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::HalProxy;
+using ::android::hardware::sensors::V2_0::implementation::HalProxyCallback;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AddAndRemoveDynamicSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+        AllSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+        DoesNotSupportDirectChannelSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal;
+using ::android::hardware::sensors::V2_0::subhal::implementation::
+        SetOperationModeFailingSensorsSubHal;
+
+using EventMessageQueue = MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite>;
+using WakeupMessageQueue = MessageQueue<uint32_t, ::android::hardware::kSynchronizedReadWrite>;
+
+// The barebones sensors callback class passed into halproxy initialize calls
+class SensorsCallback : public ISensorsCallback {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& /*dynamicSensorsAdded*/) override {
+        // Nothing yet
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& /*dynamicSensorHandlesRemoved*/) override {
+        // Nothing yet
+        return Return<void>();
+    }
+};
+
+// The sensors callback that expects a variable list of sensors to be added
+class TestSensorsCallback : public ISensorsCallback {
+  public:
+    Return<void> onDynamicSensorsConnected(
+            const hidl_vec<SensorInfo>& dynamicSensorsAdded) override {
+        mSensorsConnected.insert(mSensorsConnected.end(), dynamicSensorsAdded.begin(),
+                                 dynamicSensorsAdded.end());
+        return Return<void>();
+    }
+
+    Return<void> onDynamicSensorsDisconnected(
+            const hidl_vec<int32_t>& dynamicSensorHandlesRemoved) override {
+        mSensorHandlesDisconnected.insert(mSensorHandlesDisconnected.end(),
+                                          dynamicSensorHandlesRemoved.begin(),
+                                          dynamicSensorHandlesRemoved.end());
+        return Return<void>();
+    }
+
+    const std::vector<SensorInfo>& getSensorsConnected() const { return mSensorsConnected; }
+    const std::vector<int32_t>& getSensorHandlesDisconnected() const {
+        return mSensorHandlesDisconnected;
+    }
+
+  private:
+    std::vector<SensorInfo> mSensorsConnected;
+    std::vector<int32_t> mSensorHandlesDisconnected;
+};
+
+// Helper declarations follow
+
+/**
+ * Tests that for each SensorInfo object from a proxy getSensorsList call each corresponding
+ * object from a subhal getSensorsList call has the same type and its last 3 bytes are the
+ * same for sensorHandle field.
+ *
+ * @param proxySensorsList The list of SensorInfo objects from the proxy.getSensorsList callback.
+ * @param subHalSenosrsList The list of SensorInfo objects from the subHal.getSensorsList callback.
+ */
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+                                       const std::vector<SensorInfo>& subHalSensorsList);
+
+/**
+ * Tests that there is exactly one subhal that allows its sensors to have direct channel enabled.
+ * Therefore, all SensorInfo objects that are not from the enabled subhal should be disabled for
+ * direct channel.
+ *
+ * @param sensorsList The SensorInfo object list from proxy.getSensorsList call.
+ * @param enabledSubHalIndex The index of the subhal in the halproxy that is expected to be
+ *     enabled.
+ */
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+                                                     size_t enabledSubHalIndex);
+
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+                               EventFlag* wakelockQueueFlag);
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+                          EventFlag* eventQueueFlag);
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size);
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size);
+
+/**
+ * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
+ *    which is a wakeup type sensor.
+ *
+ * @return A proximity event.
+ */
+Event makeProximityEvent();
+
+/**
+ * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
+ *    which is a wakeup type sensor.
+ *
+ * @return A proximity event.
+ */
+Event makeAccelerometerEvent();
+
+/**
+ * Make a certain number of proximity type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<Event> makeMultipleProximityEvents(size_t numEvents);
+
+/**
+ * Make a certain number of accelerometer type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents);
+
+/**
+ * Given a SensorInfo vector and a sensor handles vector populate 'sensors' with SensorInfo
+ * objects that have the sensorHandle property set to int32_ts from start to start + size
+ * (exclusive) and push those sensorHandles also onto 'sensorHandles'.
+ *
+ * @param start The starting sensorHandle value.
+ * @param size The ending (not included) sensorHandle value.
+ * @param sensors The SensorInfo object vector reference to push_back to.
+ * @param sensorHandles The sensor handles int32_t vector reference to push_back to.
+ */
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+                                                  std::vector<SensorInfo>& sensors,
+                                                  std::vector<int32_t>& sensorHandles);
+
+// Tests follow
+TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& proxySensorsList) {
+        subHal.getSensorsList([&](const auto& subHalSensorsList) {
+            testSensorsListFromProxyAndSubHal(proxySensorsList, subHalSensorsList);
+        });
+    });
+}
+
+TEST(HalProxyTest, GetSensorsListTwoSubHalTest) {
+    ContinuousSensorsSubHal continuousSubHal;
+    OnChangeSensorsSubHal onChangeSubHal;
+    std::vector<ISensorsSubHal*> fakeSubHals;
+    fakeSubHals.push_back(&continuousSubHal);
+    fakeSubHals.push_back(&onChangeSubHal);
+    HalProxy proxy(fakeSubHals);
+
+    std::vector<SensorInfo> proxySensorsList, combinedSubHalSensorsList;
+
+    proxy.getSensorsList([&](const auto& list) { proxySensorsList = list; });
+    continuousSubHal.getSensorsList([&](const auto& list) {
+        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+    });
+    onChangeSubHal.getSensorsList([&](const auto& list) {
+        combinedSubHalSensorsList.insert(combinedSubHalSensorsList.end(), list.begin(), list.end());
+    });
+
+    testSensorsListFromProxyAndSubHal(proxySensorsList, combinedSubHalSensorsList);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalSuccessTest) {
+    ContinuousSensorsSubHal subHal1;
+    OnChangeSensorsSubHal subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    EXPECT_EQ(result, Result::OK);
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::DATA_INJECTION);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::DATA_INJECTION);
+}
+
+TEST(HalProxyTest, SetOperationModeTwoSubHalFailTest) {
+    AllSensorsSubHal subHal1;
+    SetOperationModeFailingSensorsSubHal subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+
+    Result result = proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    EXPECT_NE(result, Result::OK);
+    EXPECT_EQ(subHal1.getOperationMode(), OperationMode::NORMAL);
+    EXPECT_EQ(subHal2.getOperationMode(), OperationMode::NORMAL);
+}
+
+TEST(HalProxyTest, InitDirectChannelTwoSubHalsUnitTest) {
+    AllSupportDirectChannelSensorsSubHal subHal1;
+    AllSupportDirectChannelSensorsSubHal subHal2;
+
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& sensorsList) {
+        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 0);
+    });
+}
+
+TEST(HalProxyTest, InitDirectChannelThreeSubHalsUnitTest) {
+    DoesNotSupportDirectChannelSensorsSubHal subHal1;
+    AllSupportDirectChannelSensorsSubHal subHal2, subHal3;
+    std::vector<ISensorsSubHal*> fakeSubHals{&subHal1, &subHal2, &subHal3};
+    HalProxy proxy(fakeSubHals);
+
+    proxy.getSensorsList([&](const auto& sensorsList) {
+        testSensorsListForOneDirectChannelEnabledSubHal(sensorsList, 1);
+    });
+}
+
+TEST(HalProxyTest, PostSingleNonWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events{makeAccelerometerEvent()};
+    subHal.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), 1);
+}
+
+TEST(HalProxyTest, PostMultipleNonWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 3;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+}
+
+TEST(HalProxyTest, PostSingleWakeupEvent) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    EventFlag* wakelockQueueFlag;
+    EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
+    std::vector<Event> events{makeProximityEvent()};
+    subHal.postEvents(events, true /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), 1);
+
+    readEventsOutOfQueue(1, eventQueue, eventQueueFlag);
+    ackWakeupEventsToHalProxy(1, wakeLockQueue, wakelockQueueFlag);
+}
+
+TEST(HalProxyTest, PostMultipleWakeupEvents) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 3;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    EventFlag* wakelockQueueFlag;
+    EventFlag::createEventFlag(wakeLockQueue->getEventFlagWord(), &wakelockQueueFlag);
+
+    std::vector<Event> events = makeMultipleProximityEvents(kNumEvents);
+    subHal.postEvents(events, true /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+    readEventsOutOfQueue(kNumEvents, eventQueue, eventQueueFlag);
+    ackWakeupEventsToHalProxy(kNumEvents, wakeLockQueue, wakelockQueueFlag);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhals) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal1.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+    subHal2.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, PostEventsDelayedWrite) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 6;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    EventFlag* eventQueueFlag;
+    EventFlag::createEventFlag(eventQueue->getEventFlagWord(), &eventQueueFlag);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal1.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
+
+    // readblock a full queue size worth of events out of queue, timeout for half a second
+    EXPECT_TRUE(readEventsOutOfQueue(kQueueSize, eventQueue, eventQueueFlag));
+
+    // proxy background thread should have wrote remaining events when it saw space
+    EXPECT_TRUE(readEventsOutOfQueue(kNumEvents - kQueueSize, eventQueue, eventQueueFlag));
+
+    EXPECT_EQ(eventQueue->availableToRead(), 0);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+
+    std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false);
+    std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false);
+
+    t1.join();
+    t2.join();
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThread) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 6;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(events, false /* wakeup */);
+
+    // Destructing HalProxy object with events on the background thread
+}
+
+TEST(HalProxyTest, DestructingWithUnackedWakeupEventsPosted) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events{makeProximityEvent()};
+    subHal.postEvents(events, true /* wakeup */);
+
+    // Not sending any acks back through wakeLockQueue
+
+    // Destructing HalProxy object with unacked wakeup events posted
+}
+
+TEST(HalProxyTest, ReinitializeWithEventsPendingOnBackgroundThread) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 10;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(events, false /* wakeup */);
+
+    eventQueue = makeEventFMQ(kQueueSize);
+    wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+    Result secondInitResult =
+            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    EXPECT_EQ(secondInitResult, Result::OK);
+    // Small sleep so that pending writes thread has a change to hit writeBlocking call.
+    std::this_thread::sleep_for(std::chrono::milliseconds(5));
+    Event eventOut;
+    EXPECT_FALSE(eventQueue->read(&eventOut));
+}
+
+TEST(HalProxyTest, ReinitializingWithUnackedWakeupEventsPosted) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events{makeProximityEvent()};
+    subHal.postEvents(events, true /* wakeup */);
+
+    // Not sending any acks back through wakeLockQueue
+
+    eventQueue = makeEventFMQ(kQueueSize);
+    wakeLockQueue = makeWakelockFMQ(kQueueSize);
+
+    Result secondInitResult =
+            proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    EXPECT_EQ(secondInitResult, Result::OK);
+}
+
+TEST(HalProxyTest, InitializeManyTimesInARow) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumTimesToInit = 100;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+
+    for (size_t i = 0; i < kNumTimesToInit; i++) {
+        Result secondInitResult =
+                proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+        EXPECT_EQ(secondInitResult, Result::OK);
+    }
+}
+
+TEST(HalProxyTest, OperationModeResetOnInitialize) {
+    constexpr size_t kQueueSize = 5;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.setOperationMode(OperationMode::DATA_INJECTION);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+    Event event = makeAccelerometerEvent();
+    // Should not be able to inject a non AdditionInfo type event because operation mode should
+    // have been reset to NORMAL
+    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, DynamicSensorsDiscardedOnInitialize) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumSensors = 5;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    HalProxy proxy(subHals);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToAttemptToRemove;
+    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> nonDynamicSensorHandles;
+    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+        nonDynamicSensorHandles.push_back(sensorHandle);
+    }
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallback> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(sensorsToConnect);
+
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> sensorHandlesActuallyRemoved = callback->getSensorHandlesDisconnected();
+
+    // Should not have received the sensorHandles for any dynamic sensors that were removed since
+    // all of them should have been removed in the second initialize call.
+    EXPECT_TRUE(sensorHandlesActuallyRemoved.empty());
+}
+
+TEST(HalProxyTest, DynamicSensorsConnectedTest) {
+    constexpr size_t kNumSensors = 3;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToExpect;
+    makeSensorsAndSensorHandlesStartingAndOfSize(1, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToExpect);
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallback> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(sensorsToConnect);
+
+    std::vector<SensorInfo> sensorsSeen = callback->getSensorsConnected();
+    EXPECT_EQ(kNumSensors, sensorsSeen.size());
+    for (size_t i = 0; i < kNumSensors; i++) {
+        auto sensorHandleSeen = sensorsSeen[i].sensorHandle;
+        // Note since only one subhal we do not need to change first byte for expected
+        auto sensorHandleExpected = sensorHandlesToExpect[i];
+        EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+    }
+}
+
+TEST(HalProxyTest, DynamicSensorsDisconnectedTest) {
+    constexpr size_t kNumSensors = 3;
+    AddAndRemoveDynamicSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(0);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(0);
+
+    std::vector<SensorInfo> sensorsToConnect;
+    std::vector<int32_t> sensorHandlesToExpect;
+    makeSensorsAndSensorHandlesStartingAndOfSize(20, kNumSensors, sensorsToConnect,
+                                                 sensorHandlesToExpect);
+
+    std::vector<int32_t> nonDynamicSensorHandles;
+    for (int32_t sensorHandle = 1; sensorHandle < 10; sensorHandle++) {
+        nonDynamicSensorHandles.push_back(sensorHandle);
+    }
+
+    std::set<int32_t> nonDynamicSensorHandlesSet(nonDynamicSensorHandles.begin(),
+                                                 nonDynamicSensorHandles.end());
+
+    std::vector<int32_t> sensorHandlesToAttemptToRemove;
+    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+                                          sensorHandlesToExpect.begin(),
+                                          sensorHandlesToExpect.end());
+    sensorHandlesToAttemptToRemove.insert(sensorHandlesToAttemptToRemove.end(),
+                                          nonDynamicSensorHandles.begin(),
+                                          nonDynamicSensorHandles.end());
+
+    TestSensorsCallback* callback = new TestSensorsCallback();
+    ::android::sp<ISensorsCallback> callbackPtr = callback;
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callbackPtr);
+    subHal.addDynamicSensors(sensorsToConnect);
+    subHal.removeDynamicSensors(sensorHandlesToAttemptToRemove);
+
+    std::vector<int32_t> sensorHandlesSeen = callback->getSensorHandlesDisconnected();
+    EXPECT_EQ(kNumSensors, sensorHandlesSeen.size());
+    for (size_t i = 0; i < kNumSensors; i++) {
+        auto sensorHandleSeen = sensorHandlesSeen[i];
+        // Note since only one subhal we do not need to change first byte for expected
+        auto sensorHandleExpected = sensorHandlesToExpect[i];
+        EXPECT_EQ(sensorHandleSeen, sensorHandleExpected);
+        EXPECT_TRUE(nonDynamicSensorHandlesSet.find(sensorHandleSeen) ==
+                    nonDynamicSensorHandlesSet.end());
+    }
+}
+
+TEST(HalProxyTest, InvalidSensorHandleSubHalIndexProxyCalls) {
+    constexpr size_t kNumSubHals = 3;
+    constexpr size_t kQueueSize = 5;
+    int32_t kNumSubHalsInt32 = static_cast<int32_t>(kNumSubHals);
+    std::vector<AllSensorsSubHal> subHalObjs(kNumSubHals);
+    std::vector<ISensorsSubHal*> subHals;
+    for (const auto& subHal : subHalObjs) {
+        subHals.push_back((ISensorsSubHal*)(&subHal));
+    }
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    // Initialize for the injectSensorData call so callback postEvents is valid
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    // For testing proxy.injectSensorData properly
+    proxy.setOperationMode(OperationMode::DATA_INJECTION);
+
+    // kNumSubHalsInt32 index is one off the end of mSubHalList in proxy object
+    EXPECT_EQ(proxy.activate(0x00000001 | (kNumSubHalsInt32 << 24), true), Result::BAD_VALUE);
+    EXPECT_EQ(proxy.batch(0x00000001 | (kNumSubHalsInt32 << 24), 0, 0), Result::BAD_VALUE);
+    EXPECT_EQ(proxy.flush(0x00000001 | (kNumSubHalsInt32 << 24)), Result::BAD_VALUE);
+    Event event;
+    event.sensorHandle = 0x00000001 | (kNumSubHalsInt32 << 24);
+    EXPECT_EQ(proxy.injectSensorData(event), Result::BAD_VALUE);
+}
+
+TEST(HalProxyTest, PostedEventSensorHandleSubHalIndexValid) {
+    constexpr size_t kQueueSize = 5;
+    constexpr int32_t subhal1Index = 0;
+    constexpr int32_t subhal2Index = 1;
+    AllSensorsSubHal subhal1;
+    AllSensorsSubHal subhal2;
+    std::vector<ISensorsSubHal*> subHals{&subhal1, &subhal2};
+
+    std::unique_ptr<EventMessageQueue> eventQueue = makeEventFMQ(kQueueSize);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue = makeWakelockFMQ(kQueueSize);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    int32_t sensorHandleToPost = 0x00000001;
+    Event eventIn = makeAccelerometerEvent();
+    eventIn.sensorHandle = sensorHandleToPost;
+    std::vector<Event> eventsToPost{eventIn};
+    subhal1.postEvents(eventsToPost, false);
+
+    Event eventOut;
+    EXPECT_TRUE(eventQueue->read(&eventOut));
+
+    EXPECT_EQ(eventOut.sensorHandle, (subhal1Index << 24) | sensorHandleToPost);
+
+    subhal2.postEvents(eventsToPost, false);
+
+    EXPECT_TRUE(eventQueue->read(&eventOut));
+
+    EXPECT_EQ(eventOut.sensorHandle, (subhal2Index << 24) | sensorHandleToPost);
+}
+
+// Helper implementations follow
+void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
+                                       const std::vector<SensorInfo>& subHalSensorsList) {
+    EXPECT_EQ(proxySensorsList.size(), subHalSensorsList.size());
+
+    for (size_t i = 0; i < proxySensorsList.size(); i++) {
+        const SensorInfo& proxySensor = proxySensorsList[i];
+        const SensorInfo& subHalSensor = subHalSensorsList[i];
+
+        EXPECT_EQ(proxySensor.type, subHalSensor.type);
+        EXPECT_EQ(proxySensor.sensorHandle & 0x00FFFFFF, subHalSensor.sensorHandle);
+    }
+}
+
+void testSensorsListForOneDirectChannelEnabledSubHal(const std::vector<SensorInfo>& sensorsList,
+                                                     size_t enabledSubHalIndex) {
+    for (const SensorInfo& sensor : sensorsList) {
+        size_t subHalIndex = static_cast<size_t>(sensor.sensorHandle >> 24);
+        if (subHalIndex == enabledSubHalIndex) {
+            // First subhal should have been picked as the direct channel subhal
+            // and so have direct channel enabled on all of its sensors
+            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+            EXPECT_NE(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+        } else {
+            // All other subhals should have direct channel disabled for all sensors
+            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_REPORT, 0);
+            EXPECT_EQ(sensor.flags & SensorFlagBits::MASK_DIRECT_CHANNEL, 0);
+        }
+    }
+}
+
+void ackWakeupEventsToHalProxy(size_t numEvents, std::unique_ptr<WakeupMessageQueue>& wakelockQueue,
+                               EventFlag* wakelockQueueFlag) {
+    uint32_t numEventsUInt32 = static_cast<uint32_t>(numEvents);
+    wakelockQueue->write(&numEventsUInt32);
+    wakelockQueueFlag->wake(static_cast<uint32_t>(WakeLockQueueFlagBits::DATA_WRITTEN));
+}
+
+bool readEventsOutOfQueue(size_t numEvents, std::unique_ptr<EventMessageQueue>& eventQueue,
+                          EventFlag* eventQueueFlag) {
+    constexpr int64_t kReadBlockingTimeout = INT64_C(500000000);
+    std::vector<Event> events(numEvents);
+    return eventQueue->readBlocking(events.data(), numEvents,
+                                    static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+                                    static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+                                    kReadBlockingTimeout, eventQueueFlag);
+}
+
+std::unique_ptr<EventMessageQueue> makeEventFMQ(size_t size) {
+    return std::make_unique<EventMessageQueue>(size, true);
+}
+
+std::unique_ptr<WakeupMessageQueue> makeWakelockFMQ(size_t size) {
+    return std::make_unique<WakeupMessageQueue>(size, true);
+}
+
+Event makeProximityEvent() {
+    Event event;
+    event.timestamp = 0xFF00FF00;
+    // This is the sensorhandle of proximity, which is wakeup type
+    event.sensorHandle = 0x00000008;
+    event.sensorType = SensorType::PROXIMITY;
+    event.u = EventPayload();
+    return event;
+}
+
+Event makeAccelerometerEvent() {
+    Event event;
+    event.timestamp = 0xFF00FF00;
+    // This is the sensorhandle of proximity, which is wakeup type
+    event.sensorHandle = 0x00000001;
+    event.sensorType = SensorType::ACCELEROMETER;
+    event.u = EventPayload();
+    return event;
+}
+
+std::vector<Event> makeMultipleProximityEvents(size_t numEvents) {
+    std::vector<Event> events;
+    for (size_t i = 0; i < numEvents; i++) {
+        events.push_back(makeProximityEvent());
+    }
+    return events;
+}
+
+std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents) {
+    std::vector<Event> events;
+    for (size_t i = 0; i < numEvents; i++) {
+        events.push_back(makeAccelerometerEvent());
+    }
+    return events;
+}
+
+void makeSensorsAndSensorHandlesStartingAndOfSize(int32_t start, size_t size,
+                                                  std::vector<SensorInfo>& sensors,
+                                                  std::vector<int32_t>& sensorHandles) {
+    for (int32_t sensorHandle = start; sensorHandle < start + static_cast<int32_t>(size);
+         sensorHandle++) {
+        SensorInfo sensor;
+        // Just set the sensorHandle field to the correct value so as to not have
+        // to compare every field
+        sensor.sensorHandle = sensorHandle;
+        sensors.push_back(sensor);
+        sensorHandles.push_back(sensorHandle);
+    }
+}
+
+}  // namespace
diff --git a/sensors/2.0/multihal/tests/fake_subhal/README b/sensors/2.0/multihal/tests/fake_subhal/README
new file mode 100644
index 0000000..ddcc584
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/README
@@ -0,0 +1,19 @@
+This directory contains a modified version of the default implementation
+provided for sensors HAL 2.0 to support multi-HAL 2.0. It should be used as a
+means to verify the multi-HAL 2.0 implementation can successfully load and
+interact with sub-HALs.
+
+This sub-HAL implementation has two macros that can be used to configure support
+for different sets of sensors. One "SUPPORT_CONTINUOUS_SENSORS", enables
+support for continuous sensors like accel, and gyro whereas the other
+"SUPPORT_ON_CHANGE_SENSORS" enables support for on change sensors like the
+light and proximity sensor. A build target is defined for each of these macros,
+but more targets could be added to support both in one sub-HAL or none at all,
+if necessary.
+
+When built, the library will be written to
+out/target/product/<device>/vendor/lib64/android.hardware.sensors@2.0-fakesubhal.so
+
+Take this .so and place it where the multi-HAL config will cause the HalProxy to
+look and then restart the system server with adb shell stop / adb shell start
+to cause the multi-HAL to restart and attempt to load in the sub-HAL.
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
new file mode 100644
index 0000000..de89a00
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.cpp
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "Sensor.h"
+
+#include <hardware/sensors.h>
+#include <utils/SystemClock.h>
+
+#include <cmath>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::MetaDataEventType;
+using ::android::hardware::sensors::V1_0::SensorFlagBits;
+using ::android::hardware::sensors::V1_0::SensorStatus;
+
+Sensor::Sensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : mIsEnabled(false),
+      mSamplingPeriodNs(0),
+      mLastSampleTimeNs(0),
+      mCallback(callback),
+      mMode(OperationMode::NORMAL) {
+    mSensorInfo.sensorHandle = sensorHandle;
+    mSensorInfo.vendor = "Vendor String";
+    mSensorInfo.version = 1;
+    constexpr float kDefaultMaxDelayUs = 1000 * 1000;
+    mSensorInfo.maxDelay = kDefaultMaxDelayUs;
+    mSensorInfo.fifoReservedEventCount = 0;
+    mSensorInfo.fifoMaxEventCount = 0;
+    mSensorInfo.requiredPermission = "";
+    mSensorInfo.flags = 0;
+    mRunThread = std::thread(startThread, this);
+}
+
+Sensor::~Sensor() {
+    // Ensure that lock is unlocked before calling mRunThread.join() or a
+    // deadlock will occur.
+    {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mStopThread = true;
+        mIsEnabled = false;
+        mWaitCV.notify_all();
+    }
+    mRunThread.join();
+}
+
+const SensorInfo& Sensor::getSensorInfo() const {
+    return mSensorInfo;
+}
+
+void Sensor::batch(int32_t samplingPeriodNs) {
+    samplingPeriodNs =
+            std::clamp(samplingPeriodNs, mSensorInfo.minDelay * 1000, mSensorInfo.maxDelay * 1000);
+
+    if (mSamplingPeriodNs != samplingPeriodNs) {
+        mSamplingPeriodNs = samplingPeriodNs;
+        // Wake up the 'run' thread to check if a new event should be generated now
+        mWaitCV.notify_all();
+    }
+}
+
+void Sensor::activate(bool enable) {
+    if (mIsEnabled != enable) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mIsEnabled = enable;
+        mWaitCV.notify_all();
+    }
+}
+
+Result Sensor::flush() {
+    // Only generate a flush complete event if the sensor is enabled and if the sensor is not a
+    // one-shot sensor.
+    if (!mIsEnabled || (mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::ONE_SHOT_MODE))) {
+        return Result::BAD_VALUE;
+    }
+
+    // Note: If a sensor supports batching, write all of the currently batched events for the sensor
+    // to the Event FMQ prior to writing the flush complete event.
+    Event ev;
+    ev.sensorHandle = mSensorInfo.sensorHandle;
+    ev.sensorType = SensorType::META_DATA;
+    ev.u.meta.what = MetaDataEventType::META_DATA_FLUSH_COMPLETE;
+    std::vector<Event> evs{ev};
+    mCallback->postEvents(evs, isWakeUpSensor());
+
+    return Result::OK;
+}
+
+void Sensor::startThread(Sensor* sensor) {
+    sensor->run();
+}
+
+void Sensor::run() {
+    std::unique_lock<std::mutex> runLock(mRunMutex);
+    constexpr int64_t kNanosecondsInSeconds = 1000 * 1000 * 1000;
+
+    while (!mStopThread) {
+        if (!mIsEnabled || mMode == OperationMode::DATA_INJECTION) {
+            mWaitCV.wait(runLock, [&] {
+                return ((mIsEnabled && mMode == OperationMode::NORMAL) || mStopThread);
+            });
+        } else {
+            timespec curTime;
+            clock_gettime(CLOCK_REALTIME, &curTime);
+            int64_t now = (curTime.tv_sec * kNanosecondsInSeconds) + curTime.tv_nsec;
+            int64_t nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+
+            if (now >= nextSampleTime) {
+                mLastSampleTimeNs = now;
+                nextSampleTime = mLastSampleTimeNs + mSamplingPeriodNs;
+                mCallback->postEvents(readEvents(), isWakeUpSensor());
+            }
+
+            mWaitCV.wait_for(runLock, std::chrono::nanoseconds(nextSampleTime - now));
+        }
+    }
+}
+
+bool Sensor::isWakeUpSensor() {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::WAKE_UP);
+}
+
+std::vector<Event> Sensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = 0;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+void Sensor::setOperationMode(OperationMode mode) {
+    if (mMode != mode) {
+        std::unique_lock<std::mutex> lock(mRunMutex);
+        mMode = mode;
+        mWaitCV.notify_all();
+    }
+}
+
+bool Sensor::supportsDataInjection() const {
+    return mSensorInfo.flags & static_cast<uint32_t>(SensorFlagBits::DATA_INJECTION);
+}
+
+Result Sensor::injectEvent(const Event& event) {
+    Result result = Result::OK;
+    if (event.sensorType == SensorType::ADDITIONAL_INFO) {
+        // When in OperationMode::NORMAL, SensorType::ADDITIONAL_INFO is used to push operation
+        // environment data into the device.
+    } else if (!supportsDataInjection()) {
+        result = Result::INVALID_OPERATION;
+    } else if (mMode == OperationMode::DATA_INJECTION) {
+        mCallback->postEvents(std::vector<Event>{event}, isWakeUpSensor());
+    } else {
+        result = Result::BAD_VALUE;
+    }
+    return result;
+}
+
+OnChangeSensor::OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(sensorHandle, callback), mPreviousEventSet(false) {
+    mSensorInfo.flags |= SensorFlagBits::ON_CHANGE_MODE;
+}
+
+void OnChangeSensor::activate(bool enable) {
+    Sensor::activate(enable);
+    if (!enable) {
+        mPreviousEventSet = false;
+    }
+}
+
+std::vector<Event> OnChangeSensor::readEvents() {
+    std::vector<Event> events = Sensor::readEvents();
+    std::vector<Event> outputEvents;
+
+    for (auto iter = events.begin(); iter != events.end(); ++iter) {
+        Event ev = *iter;
+        if (ev.u.vec3 != mPreviousEvent.u.vec3 || !mPreviousEventSet) {
+            outputEvents.push_back(ev);
+            mPreviousEvent = ev;
+            mPreviousEventSet = true;
+        }
+    }
+    return outputEvents;
+}
+
+ContinuousSensor::ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : Sensor(sensorHandle, callback) {
+    mSensorInfo.flags |= SensorFlagBits::CONTINUOUS_MODE;
+}
+
+AccelSensor::AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Accel Sensor";
+    mSensorInfo.type = SensorType::ACCELEROMETER;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_ACCELEROMETER;
+    mSensorInfo.maxRange = 78.4f;  // +/- 8g
+    mSensorInfo.resolution = 1.52e-5;
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+    mSensorInfo.flags |= SensorFlagBits::DATA_INJECTION;
+}
+
+std::vector<Event> AccelSensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = -9.815;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+PressureSensor::PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Pressure Sensor";
+    mSensorInfo.type = SensorType::PRESSURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PRESSURE;
+    mSensorInfo.maxRange = 1100.0f;     // hPa
+    mSensorInfo.resolution = 0.005f;    // hPa
+    mSensorInfo.power = 0.001f;         // mA
+    mSensorInfo.minDelay = 100 * 1000;  // microseconds
+}
+
+MagnetometerSensor::MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Magnetic Field Sensor";
+    mSensorInfo.type = SensorType::MAGNETIC_FIELD;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_MAGNETIC_FIELD;
+    mSensorInfo.maxRange = 1300.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;        // mA
+    mSensorInfo.minDelay = 20 * 1000;  // microseconds
+}
+
+LightSensor::LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Light Sensor";
+    mSensorInfo.type = SensorType::LIGHT;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_LIGHT;
+    mSensorInfo.maxRange = 43000.0f;
+    mSensorInfo.resolution = 10.0f;
+    mSensorInfo.power = 0.001f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+}
+
+ProximitySensor::ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Proximity Sensor";
+    mSensorInfo.type = SensorType::PROXIMITY;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_PROXIMITY;
+    mSensorInfo.maxRange = 5.0f;
+    mSensorInfo.resolution = 1.0f;
+    mSensorInfo.power = 0.012f;         // mA
+    mSensorInfo.minDelay = 200 * 1000;  // microseconds
+    mSensorInfo.flags |= SensorFlagBits::WAKE_UP;
+}
+
+GyroSensor::GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Gyro Sensor";
+    mSensorInfo.type = SensorType::GYROSCOPE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_GYROSCOPE;
+    mSensorInfo.maxRange = 1000.0f * M_PI / 180.0f;
+    mSensorInfo.resolution = 1000.0f * M_PI / (180.0f * 32768.0f);
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 2.5f * 1000;  // microseconds
+}
+
+std::vector<Event> GyroSensor::readEvents() {
+    std::vector<Event> events;
+    Event event;
+    event.sensorHandle = mSensorInfo.sensorHandle;
+    event.sensorType = mSensorInfo.type;
+    event.timestamp = ::android::elapsedRealtimeNano();
+    event.u.vec3.x = 0;
+    event.u.vec3.y = 0;
+    event.u.vec3.z = 0;
+    event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+    events.push_back(event);
+    return events;
+}
+
+AmbientTempSensor::AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Ambient Temp Sensor";
+    mSensorInfo.type = SensorType::AMBIENT_TEMPERATURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_AMBIENT_TEMPERATURE;
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+DeviceTempSensor::DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback)
+    : ContinuousSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Device Temp Sensor";
+    mSensorInfo.type = SensorType::TEMPERATURE;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_TEMPERATURE;
+    mSensorInfo.maxRange = 80.0f;
+    mSensorInfo.resolution = 0.01f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+RelativeHumiditySensor::RelativeHumiditySensor(int32_t sensorHandle,
+                                               ISensorsEventCallback* callback)
+    : OnChangeSensor(sensorHandle, callback) {
+    mSensorInfo.name = "Relative Humidity Sensor";
+    mSensorInfo.type = SensorType::RELATIVE_HUMIDITY;
+    mSensorInfo.typeAsString = SENSOR_STRING_TYPE_RELATIVE_HUMIDITY;
+    mSensorInfo.maxRange = 100.0f;
+    mSensorInfo.resolution = 0.1f;
+    mSensorInfo.power = 0.001f;
+    mSensorInfo.minDelay = 40 * 1000;  // microseconds
+}
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/Sensor.h b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
new file mode 100644
index 0000000..60f5d3d
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/Sensor.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <android/hardware/sensors/1.0/types.h>
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SensorInfo;
+using ::android::hardware::sensors::V1_0::SensorType;
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+class ISensorsEventCallback {
+  public:
+    virtual ~ISensorsEventCallback(){};
+    virtual void postEvents(const std::vector<Event>& events, bool wakeup) = 0;
+};
+
+class Sensor {
+  public:
+    Sensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+    virtual ~Sensor();
+
+    const SensorInfo& getSensorInfo() const;
+    void batch(int32_t samplingPeriodNs);
+    virtual void activate(bool enable);
+    Result flush();
+
+    void setOperationMode(OperationMode mode);
+    bool supportsDataInjection() const;
+    Result injectEvent(const Event& event);
+
+  protected:
+    void run();
+    virtual std::vector<Event> readEvents();
+    static void startThread(Sensor* sensor);
+
+    bool isWakeUpSensor();
+
+    bool mIsEnabled;
+    int64_t mSamplingPeriodNs;
+    int64_t mLastSampleTimeNs;
+    SensorInfo mSensorInfo;
+
+    std::atomic_bool mStopThread;
+    std::condition_variable mWaitCV;
+    std::mutex mRunMutex;
+    std::thread mRunThread;
+
+    ISensorsEventCallback* mCallback;
+
+    OperationMode mMode;
+};
+
+class OnChangeSensor : public Sensor {
+  public:
+    OnChangeSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+    virtual void activate(bool enable) override;
+
+  protected:
+    virtual std::vector<Event> readEvents() override;
+
+  protected:
+    Event mPreviousEvent;
+    bool mPreviousEventSet;
+};
+
+class ContinuousSensor : public Sensor {
+  public:
+    ContinuousSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AccelSensor : public ContinuousSensor {
+  public:
+    AccelSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    std::vector<Event> readEvents() override;
+};
+
+class GyroSensor : public ContinuousSensor {
+  public:
+    GyroSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+
+  protected:
+    std::vector<Event> readEvents() override;
+};
+
+class DeviceTempSensor : public ContinuousSensor {
+  public:
+    DeviceTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class PressureSensor : public ContinuousSensor {
+  public:
+    PressureSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class MagnetometerSensor : public ContinuousSensor {
+  public:
+    MagnetometerSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class AmbientTempSensor : public OnChangeSensor {
+  public:
+    AmbientTempSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class LightSensor : public OnChangeSensor {
+  public:
+    LightSensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class ProximitySensor : public OnChangeSensor {
+  public:
+    ProximitySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+class RelativeHumiditySensor : public OnChangeSensor {
+  public:
+    RelativeHumiditySensor(int32_t sensorHandle, ISensorsEventCallback* callback);
+};
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
new file mode 100644
index 0000000..ff5ff38
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "SensorsSubHal.h"
+
+#include <android/hardware/sensors/2.0/types.h>
+#include <log/log.h>
+
+ISensorsSubHal* sensorsHalGetSubHal(uint32_t* version) {
+#if defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::AllSensorsSubHal subHal;
+#elif defined SUPPORT_CONTINUOUS_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::ContinuousSensorsSubHal
+            subHal;
+#elif defined SUPPORT_ON_CHANGE_SENSORS
+    static ::android::hardware::sensors::V2_0::subhal::implementation::OnChangeSensorsSubHal subHal;
+#else
+    static ::android::hardware::sensors::V2_0::subhal::implementation::SensorsSubHal subHal;
+#endif  // defined SUPPORT_CONTINUOUS_SENSORS && defined SUPPORT_ON_CHANGE_SENSORS
+    *version = SUB_HAL_2_0_VERSION;
+    return &subHal;
+}
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::Void;
+using ::android::hardware::sensors::V1_0::Event;
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::RateLevel;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V1_0::SharedMemInfo;
+using ::android::hardware::sensors::V2_0::SensorTimeout;
+using ::android::hardware::sensors::V2_0::WakeLockQueueFlagBits;
+using ::android::hardware::sensors::V2_0::implementation::ScopedWakelock;
+
+SensorsSubHal::SensorsSubHal() : mCallback(nullptr), mNextHandle(1) {}
+
+// Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+Return<void> SensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        sensors.push_back(sensor.second->getSensorInfo());
+    }
+
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<Result> SensorsSubHal::setOperationMode(OperationMode mode) {
+    for (auto sensor : mSensors) {
+        sensor.second->setOperationMode(mode);
+    }
+    mCurrentOperationMode = mode;
+    return Result::OK;
+}
+
+Return<Result> SensorsSubHal::activate(int32_t sensorHandle, bool enabled) {
+    auto sensor = mSensors.find(sensorHandle);
+    if (sensor != mSensors.end()) {
+        sensor->second->activate(enabled);
+        return Result::OK;
+    }
+    return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                                    int64_t /* maxReportLatencyNs */) {
+    auto sensor = mSensors.find(sensorHandle);
+    if (sensor != mSensors.end()) {
+        sensor->second->batch(samplingPeriodNs);
+        return Result::OK;
+    }
+    return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::flush(int32_t sensorHandle) {
+    auto sensor = mSensors.find(sensorHandle);
+    if (sensor != mSensors.end()) {
+        return sensor->second->flush();
+    }
+    return Result::BAD_VALUE;
+}
+
+Return<Result> SensorsSubHal::injectSensorData(const Event& event) {
+    auto sensor = mSensors.find(event.sensorHandle);
+    if (sensor != mSensors.end()) {
+        return sensor->second->injectEvent(event);
+    }
+
+    return Result::BAD_VALUE;
+}
+
+Return<void> SensorsSubHal::registerDirectChannel(const SharedMemInfo& /* mem */,
+                                                  registerDirectChannel_cb _hidl_cb) {
+    _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+    return Return<void>();
+}
+
+Return<Result> SensorsSubHal::unregisterDirectChannel(int32_t /* channelHandle */) {
+    return Result::INVALID_OPERATION;
+}
+
+Return<void> SensorsSubHal::configDirectReport(int32_t /* sensorHandle */,
+                                               int32_t /* channelHandle */, RateLevel /* rate */,
+                                               configDirectReport_cb _hidl_cb) {
+    _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+    return Return<void>();
+}
+
+Return<void> SensorsSubHal::debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) {
+    if (fd.getNativeHandle() == nullptr || fd->numFds < 1) {
+        ALOGE("%s: missing fd for writing", __FUNCTION__);
+        return Void();
+    }
+
+    FILE* out = fdopen(dup(fd->data[0]), "w");
+
+    if (args.size() != 0) {
+        fprintf(out,
+                "Note: sub-HAL %s currently does not support args. Input arguments are "
+                "ignored.\n",
+                getName().c_str());
+    }
+
+    std::ostringstream stream;
+    stream << "Available sensors:" << std::endl;
+    for (auto sensor : mSensors) {
+        SensorInfo info = sensor.second->getSensorInfo();
+        stream << "Name: " << info.name << std::endl;
+        stream << "Min delay: " << info.minDelay << std::endl;
+        stream << "Flags: " << info.flags << std::endl;
+    }
+    stream << std::endl;
+
+    fprintf(out, "%s", stream.str().c_str());
+
+    fclose(out);
+    return Return<void>();
+}
+
+Return<Result> SensorsSubHal::initialize(const sp<IHalProxyCallback>& halProxyCallback) {
+    mCallback = halProxyCallback;
+    setOperationMode(OperationMode::NORMAL);
+    return Result::OK;
+}
+
+void SensorsSubHal::postEvents(const std::vector<Event>& events, bool wakeup) {
+    ScopedWakelock wakelock = mCallback->createScopedWakelock(wakeup);
+    mCallback->postEvents(events, std::move(wakelock));
+}
+
+ContinuousSensorsSubHal::ContinuousSensorsSubHal() {
+    AddSensor<AccelSensor>();
+    AddSensor<GyroSensor>();
+    AddSensor<MagnetometerSensor>();
+    AddSensor<PressureSensor>();
+    AddSensor<DeviceTempSensor>();
+}
+
+OnChangeSensorsSubHal::OnChangeSensorsSubHal() {
+    AddSensor<AmbientTempSensor>();
+    AddSensor<LightSensor>();
+    AddSensor<ProximitySensor>();
+    AddSensor<RelativeHumiditySensor>();
+}
+
+AllSensorsSubHal::AllSensorsSubHal() {
+    AddSensor<AccelSensor>();
+    AddSensor<GyroSensor>();
+    AddSensor<MagnetometerSensor>();
+    AddSensor<PressureSensor>();
+    AddSensor<DeviceTempSensor>();
+    AddSensor<AmbientTempSensor>();
+    AddSensor<LightSensor>();
+    AddSensor<ProximitySensor>();
+    AddSensor<RelativeHumiditySensor>();
+}
+
+Return<Result> SetOperationModeFailingSensorsSubHal::setOperationMode(OperationMode /*mode*/) {
+    return Result::BAD_VALUE;
+}
+
+Return<void> AllSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        SensorInfo sensorInfo = sensor.second->getSensorInfo();
+        sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL;
+        sensorInfo.flags |= V1_0::SensorFlagBits::MASK_DIRECT_REPORT;
+        sensors.push_back(sensorInfo);
+    }
+    _hidl_cb(sensors);
+    return Void();
+}
+
+Return<void> DoesNotSupportDirectChannelSensorsSubHal::getSensorsList(getSensorsList_cb _hidl_cb) {
+    std::vector<SensorInfo> sensors;
+    for (const auto& sensor : mSensors) {
+        SensorInfo sensorInfo = sensor.second->getSensorInfo();
+        sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_CHANNEL);
+        sensorInfo.flags &= ~static_cast<uint32_t>(V1_0::SensorFlagBits::MASK_DIRECT_REPORT);
+        sensors.push_back(sensorInfo);
+    }
+    _hidl_cb(sensors);
+    return Void();
+}
+
+void AddAndRemoveDynamicSensorsSubHal::addDynamicSensors(
+        const std::vector<SensorInfo>& sensorsAdded) {
+    mCallback->onDynamicSensorsConnected(sensorsAdded);
+}
+
+void AddAndRemoveDynamicSensorsSubHal::removeDynamicSensors(
+        const std::vector<int32_t>& sensorHandlesRemoved) {
+    mCallback->onDynamicSensorsDisconnected(sensorHandlesRemoved);
+}
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
new file mode 100644
index 0000000..c1e3647
--- /dev/null
+++ b/sensors/2.0/multihal/tests/fake_subhal/SensorsSubHal.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include "SubHal.h"
+
+#include "Sensor.h"
+
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace sensors {
+namespace V2_0 {
+namespace subhal {
+namespace implementation {
+
+using ::android::hardware::sensors::V1_0::OperationMode;
+using ::android::hardware::sensors::V1_0::Result;
+using ::android::hardware::sensors::V2_0::implementation::IHalProxyCallback;
+
+/**
+ * Implementation of a ISensorsSubHal that can be used to test the implementation of multihal 2.0.
+ * See the README file for more details on how this class can be used for testing.
+ */
+class SensorsSubHal : public ISensorsSubHal, public ISensorsEventCallback {
+    using Event = ::android::hardware::sensors::V1_0::Event;
+    using RateLevel = ::android::hardware::sensors::V1_0::RateLevel;
+    using SharedMemInfo = ::android::hardware::sensors::V1_0::SharedMemInfo;
+
+  public:
+    SensorsSubHal();
+
+    // Methods from ::android::hardware::sensors::V2_0::ISensors follow.
+    virtual Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+
+    virtual Return<Result> setOperationMode(OperationMode mode) override;
+
+    OperationMode getOperationMode() const { return mCurrentOperationMode; }
+
+    Return<Result> activate(int32_t sensorHandle, bool enabled) override;
+
+    Return<Result> batch(int32_t sensorHandle, int64_t samplingPeriodNs,
+                         int64_t maxReportLatencyNs) override;
+
+    Return<Result> flush(int32_t sensorHandle) override;
+
+    Return<Result> injectSensorData(const Event& event) override;
+
+    Return<void> registerDirectChannel(const SharedMemInfo& mem,
+                                       registerDirectChannel_cb _hidl_cb) override;
+
+    Return<Result> unregisterDirectChannel(int32_t channelHandle) override;
+
+    Return<void> configDirectReport(int32_t sensorHandle, int32_t channelHandle, RateLevel rate,
+                                    configDirectReport_cb _hidl_cb) override;
+
+    Return<void> debug(const hidl_handle& fd, const hidl_vec<hidl_string>& args) override;
+
+    // Methods from ::android::hardware::sensors::V2_0::implementation::ISensorsSubHal follow.
+    const std::string getName() override {
+#ifdef SUB_HAL_NAME
+        return SUB_HAL_NAME;
+#else   // SUB_HAL_NAME
+        return "FakeSubHal";
+#endif  // SUB_HAL_NAME
+    }
+
+    Return<Result> initialize(const sp<IHalProxyCallback>& halProxyCallback) override;
+
+    // Method from ISensorsEventCallback.
+    void postEvents(const std::vector<Event>& events, bool wakeup) override;
+
+  protected:
+    template <class SensorType>
+    void AddSensor() {
+        std::shared_ptr<SensorType> sensor =
+                std::make_shared<SensorType>(mNextHandle++ /* sensorHandle */, this /* callback */);
+        mSensors[sensor->getSensorInfo().sensorHandle] = sensor;
+    }
+
+    /**
+     * A map of the available sensors
+     */
+    std::map<int32_t, std::shared_ptr<Sensor>> mSensors;
+
+    /**
+     * Callback used to communicate to the HalProxy when dynamic sensors are connected /
+     * disconnected, sensor events need to be sent to the framework, and when a wakelock should be
+     * acquired.
+     */
+    sp<IHalProxyCallback> mCallback;
+
+  private:
+    /**
+     * The current operation mode of the multihal framework. Ensures that all subhals are set to
+     * the same operation mode.
+     */
+    OperationMode mCurrentOperationMode = OperationMode::NORMAL;
+
+    /**
+     * The next available sensor handle
+     */
+    int32_t mNextHandle;
+};
+
+// SubHal that has continuous sensors for testing purposes.
+class ContinuousSensorsSubHal : public SensorsSubHal {
+  public:
+    ContinuousSensorsSubHal();
+};
+
+// SubHal that has on-change sensors for testing purposes.
+class OnChangeSensorsSubHal : public SensorsSubHal {
+  public:
+    OnChangeSensorsSubHal();
+};
+
+// SubHal that has both continuous and on-change sensors for testing purposes.
+class AllSensorsSubHal : public SensorsSubHal {
+  public:
+    AllSensorsSubHal();
+};
+
+class SetOperationModeFailingSensorsSubHal : public AllSensorsSubHal {
+  public:
+    Return<Result> setOperationMode(OperationMode mode) override;
+};
+
+class AllSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
+  public:
+    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+};
+
+class DoesNotSupportDirectChannelSensorsSubHal : public AllSensorsSubHal {
+  public:
+    Return<void> getSensorsList(getSensorsList_cb _hidl_cb) override;
+};
+
+class AddAndRemoveDynamicSensorsSubHal : public AllSensorsSubHal {
+  public:
+    void addDynamicSensors(const std::vector<SensorInfo>& sensorsAdded);
+    void removeDynamicSensors(const std::vector<int32_t>& sensorHandlesAdded);
+};
+
+}  // namespace implementation
+}  // namespace subhal
+}  // namespace V2_0
+}  // namespace sensors
+}  // namespace hardware
+}  // namespace android
diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
index 09265f7..d78f3f2 100644
--- a/tv/tuner/1.0/Android.bp
+++ b/tv/tuner/1.0/Android.bp
@@ -9,15 +9,21 @@
     srcs: [
         "types.hal",
         "IDemux.hal",
-        "IDemuxCallback.hal",
         "IDescrambler.hal",
+        "IDvr.hal",
+        "IDvrCallback.hal",
+        "IFilter.hal",
+        "IFilterCallback.hal",
         "IFrontend.hal",
         "IFrontendCallback.hal",
         "ILnb.hal",
+        "ILnbCallback.hal",
+        "ITimeFilter.hal",
         "ITuner.hal",
     ],
     interfaces: [
         "android.hidl.base@1.0",
+        "android.hidl.safe_union@1.0",
     ],
     gen_java: false,
     gen_java_constants: true,
diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal
index 7ead34b..9e799b4 100644
--- a/tv/tuner/1.0/IDemux.hal
+++ b/tv/tuner/1.0/IDemux.hal
@@ -16,7 +16,11 @@
 
 package android.hardware.tv.tuner@1.0;
 
-import IDemuxCallback;
+import IDvr;
+import IDvrCallback;
+import IFilter;
+import IFilterCallback;
+import ITimeFilter;
 
 /**
  * Demultiplexer(Demux) takes a single multiplexed input and splits it into
@@ -24,7 +28,6 @@
  *
  */
 interface IDemux {
-
     /**
      * Set a frontend resource as data input of the demux
      *
@@ -39,134 +42,51 @@
     setFrontendDataSource(FrontendId frontendId) generates (Result result);
 
     /**
-     * Add a filter to the demux
+     * Open a new filter in the demux
      *
-     * It is used by the client to add a filter to the demux.
+     * It is used by the client to open a filter in the demux.
      *
      * @param type the type of the filter to be added.
-     * @param bufferSize the buffer size of the filter to be added. It's used to
-     * create a FMQ(Fast Message Queue) to hold data output from the filter.
+     * @param bufferSize the buffer size of the filter to be opened. It's used
+     * to create a FMQ(Fast Message Queue) to hold data output from the filter.
      * @param cb the callback for the filter to be used to send notifications
      * back to the client.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
      *         INVALID_STATE if failed for wrong state.
      *         UNKNOWN_ERROR if failed for other reasons.
-     * @return filterId the ID of the newly added filter.
+     * @return filter the filter instance of the newly added.
      */
-    addFilter(DemuxFilterType type, uint32_t bufferSize, IDemuxCallback cb)
-        generates (Result result, DemuxFilterId filterId);
+    openFilter(DemuxFilterType type, uint32_t bufferSize, IFilterCallback cb)
+        generates (Result result, IFilter filter);
 
     /**
-     * Get the descriptor of the filter's FMQ
+     * Open time filter of the demux
      *
-     * It is used by the client to get the descriptor of the filter's Fast
-     * Message Queue. The data in FMQ is filtered out from MPEG transport
-     * stream. The data is origanized to data blocks which may have
-     * different length. The length's information of one or multiple data blocks
-     * is sent to client throught DemuxFilterEvent.
+     * It is used by the client to open time filter of the demux.
      *
-     * @param filterId the ID of the filter.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
-     *         INVALID_ARGUMENT if failed for wrong filter ID.
+     *         UNAVAILABLE if time filter is not supported.
      *         INVALID_STATE if failed for wrong state.
      *         UNKNOWN_ERROR if failed for other reasons.
-     * @return queue the descriptor of the filter's FMQ
+     * @return timeFilter the time filter instance of the newly added.
      */
-    getFilterQueueDesc(DemuxFilterId filterId)
-        generates (Result result, fmq_sync<uint8_t> queue);
-
-    /**
-     * Configure the filter.
-     *
-     * It is used by the client to configure the filter so that it can filter out
-     * intended data.
-     *
-     * @param filterId the ID of the filter.
-     * @param settings the settings of the filter.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_ARGUMENT if failed for wrong filter ID.
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    configureFilter(DemuxFilterId filterId, DemuxFilterSettings settings)
-        generates(Result result);
-
-    /**
-     * Start the filter.
-     *
-     * It is used by the client to ask the filter to start filterring data.
-     *
-     * @param filterId the ID of the filter.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_ARGUMENT if failed for wrong filter ID.
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    startFilter(DemuxFilterId filterId) generates (Result result);
-
-    /**
-     * Stop the filter.
-     *
-     * It is used by the client to ask the filter to stop filterring data.
-     * It won't discard the data already filtered out by the filter. The filter
-     * will be stopped and removed automatically if the demux is closed.
-     *
-     * @param filterId the ID of the filter.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_ARGUMENT if failed for wrong filter ID.
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    stopFilter(DemuxFilterId filterId) generates (Result result);
-
-    /**
-     * Flush the filter.
-     *
-     * It is used by the client to ask the filter to flush the data which is
-     * already produced but not consumed yet.
-     *
-     * @param filterId the ID of the filter.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_ARGUMENT if failed for wrong filter ID.
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    flushFilter(DemuxFilterId filterId) generates (Result result);
-
-    /**
-     * Remove a filter from the demux
-     *
-     * It is used by the client to remove a filter from the demux.
-     *
-     * @param filterId the ID of the removed filter.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_ARGUMENT if failed for wrong filter ID.
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    removeFilter(DemuxFilterId filterId) generates (Result result);
+    openTimeFilter() generates (Result result, ITimeFilter timeFilter);
 
     /**
      * Get hardware sync ID for audio and video.
      *
      * It is used by the client to get the hardware sync ID for audio and video.
      *
-     * @param filterId the ID of the filter.
+     * @param filter the filter instance.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
      *         INVALID_ARGUMENT if failed for a wrong filter ID.
      *         UNKNOWN_ERROR if failed for other reasons.
      * @return avSyncHwId the id of hardware A/V sync.
      */
-    getAvSyncHwId(DemuxFilterId filterId)
-        generates (Result result, AvSyncHwId avSyncHwId);
+    getAvSyncHwId(IFilter filter) generates (Result result, AvSyncHwId avSyncHwId);
 
     /**
      * Get current time stamp to use for A/V sync
@@ -182,8 +102,7 @@
      * @return time the current time stamp of hardware A/V sync. The time stamp
      * based on 90KHz has the same format as PTS (Presentation Time Stamp).
      */
-    getAvSyncTime(AvSyncHwId avSyncHwId)
-        generates (Result result, uint64_t time);
+    getAvSyncTime(AvSyncHwId avSyncHwId) generates (Result result, uint64_t time);
 
     /**
      * Close the Demux instance
@@ -198,218 +117,21 @@
     close() generates (Result result);
 
     /**
-     * Add output to the demux
+     * Open a DVR (Digital Video Record) instance in the demux
      *
-     * It is used by the client to record output data from selected filters.
+     * It is used by the client to record and playback.
      *
+     * @param type specify which kind of DVR to open.
      * @param bufferSize the buffer size of the output to be added. It's used to
      * create a FMQ(Fast Message Queue) to hold data from selected filters.
-     * @param cb the callback for the demux to be used to send notifications
+     * @param cb the callback for the DVR to be used to send notifications
      * back to the client.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
      *         OUT_OF_MEMORY if failed for not enough memory.
      *         UNKNOWN_ERROR if failed for other reasons.
+     * @return dvr a DVR instance.
      */
-    addOutput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result);
-
-    /**
-     * Get the descriptor of the output's FMQ
-     *
-     * It is used by the client to get the descriptor of the output's Fast
-     * Message Queue. The data in FMQ is muxed packets output from selected
-     * filters. The packet's format is specifed by DemuxDataFormat in
-     * DemuxOutputSettings.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         UNKNOWN_ERROR if failed for other reasons.
-     * @return queue the descriptor of the output's FMQ
-     */
-    getOutputQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
-
-    /**
-     * Configure the demux's output.
-     *
-     * It is used by the client to configure the demux's output for recording.
-     *
-     * @param settings the settings of the demux's output.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    configureOutput(DemuxOutputSettings settings) generates (Result result);
-
-    /**
-     * Attach one filter to the demux's output.
-     *
-     * It is used by the client to mux one filter's output to demux's output.
-     *
-     * @param filterId the ID of the attached filter.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    attachOutputFilter(DemuxFilterId filterId) generates (Result result);
-
-    /**
-     * Detach one filter from the demux's output.
-     *
-     * It is used by the client to remove one filter's output from demux's
-     * output.
-     *
-     * @param filterId the ID of the detached filter.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    detachOutputFilter(DemuxFilterId filterId) generates (Result result);
-
-    /**
-     * Start to take data to the demux's output.
-     *
-     * It is used by the client to ask the output to start to take data from
-     * attached filters.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    startOutput() generates (Result result);
-
-    /**
-     * Stop to take data to the demux's output.
-     *
-     * It is used by the client to ask the output to stop to take data from
-     * attached filters.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    stopOutput() generates (Result result);
-
-    /**
-     * Flush unconsumed data in the demux's output.
-     *
-     * It is used by the client to ask the demux to flush the data which is
-     * already produced but not consumed yet in the demux's output.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    flushOutput() generates (Result result);
-
-    /**
-     * Remove the demux's output.
-     *
-     * It is used by the client to remove the demux's output.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    removeOutput() generates (Result result);
-
-    /**
-     * Add input to the demux
-     *
-     * It is used by the client to add the demux's input for playback content.
-     *
-     * @param bufferSize the buffer size of the demux's input to be added.
-     * It's used to create a FMQ(Fast Message Queue) to hold input data.
-     * @param cb the callback for the demux to be used to send notifications
-     * back to the client.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         OUT_OF_MEMORY if failed for not enough memory.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    addInput(uint32_t bufferSize, IDemuxCallback cb) generates (Result result);
-
-    /**
-     * Get the descriptor of the input's FMQ
-     *
-     * It is used by the client to get the descriptor of the input's Fast
-     * Message Queue. The data in FMQ is fed by client. Data format is specifed
-     * by DemuxDataFormat in DemuxInputSettings.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         UNKNOWN_ERROR if failed for other reasons.
-     * @return queue the descriptor of the output's FMQ
-     */
-    getInputQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
-
-    /**
-     * Configure the demux's input.
-     *
-     * It is used by the client to configure the demux's input for playback.
-     *
-     * @param settings the settings of the demux's input.
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    configureInput(DemuxInputSettings settings) generates (Result result);
-
-    /**
-     * Start to consume the data from the demux's input.
-     *
-     * It is used by the client to ask the demux to start to consume data from
-     * the demux's input.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    startInput() generates (Result result);
-
-    /**
-     * Stop to consume the data from the demux's input.
-     *
-     * It is used by the client to ask the demux to stop to consume data from
-     * the demux's input.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    stopInput() generates (Result result);
-
-    /**
-     * Flush unconsumed data in the demux's input.
-     *
-     * It is used by the client to ask the demux to flush the data which is
-     * already produced but not consumed yet in the demux's input.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    flushInput() generates (Result result);
-
-    /**
-     * Remove the demux's input.
-     *
-     * It is used by the client to remove the demux's input.
-     *
-     * @return result Result status of the operation.
-     *         SUCCESS if successful,
-     *         INVALID_STATE if failed for wrong state.
-     *         UNKNOWN_ERROR if failed for other reasons.
-     */
-    removeInput() generates (Result result);
+    openDvr(DvrType type, uint32_t bufferSize, IDvrCallback cb)
+        generates (Result result, IDvr dvr);
 };
diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal
deleted file mode 100644
index 7bce9ef..0000000
--- a/tv/tuner/1.0/IDemuxCallback.hal
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (C) 2019 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.
- */
-
-package android.hardware.tv.tuner@1.0;
-
-interface IDemuxCallback {
-    /**
-     * Notify the client that a new filter event happened.
-     *
-     * @param filterEvent a demux filter event.
-     */
-    oneway onFilterEvent(DemuxFilterEvent filterEvent);
-
-    /**
-     * Notify the client a new status of a demux filter.
-     *
-     * @param filterId the demux filter ID.
-     * @param status a new status of the demux filter.
-     */
-    oneway onFilterStatus(DemuxFilterId filterId, DemuxFilterStatus status);
-
-    /**
-     * Notify the client a new status of the demux's output.
-     *
-     * @param status a new status of the demux's output.
-     */
-    oneway onOutputStatus(DemuxOutputStatus status);
-
-    /**
-     * Notify the client a new status of the demux's input.
-     *
-     * @param status a new status of the demux's input.
-     */
-    oneway onInputStatus(DemuxInputStatus status);
-};
-
diff --git a/tv/tuner/1.0/IDescrambler.hal b/tv/tuner/1.0/IDescrambler.hal
index 61ff1df..7f98865 100644
--- a/tv/tuner/1.0/IDescrambler.hal
+++ b/tv/tuner/1.0/IDescrambler.hal
@@ -15,6 +15,9 @@
  */
 
 package android.hardware.tv.tuner@1.0;
+
+import IFilter;
+
 /**
  * Descrambler is used to descramble input data.
  *
@@ -59,12 +62,13 @@
      * packets from different PIDs.
      *
      * @param pid the PID of packets to start to be descrambled.
+     * @param filter an optional filter instance to identify upper stream.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
      *         INVALID_STATE if failed for wrong state.
      *         UNKNOWN_ERROR if failed for other reasons.
      */
-    addPid(DemuxTpid pid) generates (Result result);
+    addPid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result);
 
     /**
      * Remove packets' PID from the descrambler
@@ -73,12 +77,13 @@
      * descrambler stop to descramble.
      *
      * @param pid the PID of packets to stop to be descrambled.
+     * @param filter an optional filter instance to identify upper stream.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
      *         INVALID_STATE if failed for wrong state.
      *         UNKNOWN_ERROR if failed for other reasons.
      */
-    removePid(DemuxTpid pid) generates (Result result);
+    removePid(DemuxPid pid, IFilter optionalSourceFilter) generates (Result result);
 
     /**
      * Release the descrambler instance
@@ -92,4 +97,3 @@
      */
     close() generates (Result result);
 };
-
diff --git a/tv/tuner/1.0/IDvr.hal b/tv/tuner/1.0/IDvr.hal
new file mode 100644
index 0000000..f57e4b6
--- /dev/null
+++ b/tv/tuner/1.0/IDvr.hal
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+import IFilter;
+
+/**
+ * Digtal Video Record (DVR) interface provides record control on Demux's
+ * output buffer and playback control on Demux's input buffer.
+ */
+interface IDvr {
+    /**
+     * Get the descriptor of the DVR's FMQ
+     *
+     * It is used by the client to get the descriptor of the DVR's Fast
+     * Message Queue. The FMQ is used to transfer record or playback data
+     * between the client and the HAL.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return queue the descriptor of the DVR's FMQ
+     */
+    getQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
+
+    /**
+     * Configure the DVR.
+     *
+     * It is used by the client to configure the DVR interface.
+     *
+     * @param settings the settings of the DVR interface.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    configure(DvrSettings settings) generates (Result result);
+
+    /**
+     * Attach one filter to DVR interface for recording.
+     *
+     * It is used by the client to add the data filtered out from the filter
+     * to record.
+     *
+     * @param filter the instance of the attached filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    attachFilter(IFilter filter) generates (Result result);
+
+    /**
+     * Detach one filter from the DVR's recording.
+     *
+     * It is used by the client to remove the data of the filter from DVR's
+     * recording.
+     *
+     * @param filter the instance of the detached filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    detachFilter(IFilter filter) generates (Result result);
+
+    /**
+     * Start DVR.
+     *
+     * It is used by the client to ask the DVR to start consuming playback data
+     * or producing data for record.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    start() generates (Result result);
+
+    /**
+     * Stop DVR.
+     *
+     * It is used by the client to ask the DVR to stop consuming playback data
+     * or producing data for record.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stop() generates (Result result);
+
+    /**
+     * Flush DVR data.
+     *
+     * It is used by the client to ask the DVR to flush the data which is
+     * not consumed by HAL for playback or the client for record yet.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    flush() generates (Result result);
+
+    /**
+     * close the DVR instance to release resource for DVR.
+     *
+     * It is used by the client to close the DVR instance, and HAL clears
+     * underneath resource for this DVR instance. Client mustn't access the
+     * instance any more and all methods should return a failure.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IDvrCallback.hal b/tv/tuner/1.0/IDvrCallback.hal
new file mode 100644
index 0000000..337eddc
--- /dev/null
+++ b/tv/tuner/1.0/IDvrCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+interface IDvrCallback {
+    /**
+     * Notify the client a new status of the demux's record.
+     *
+     * @param status a new status of the demux's record.
+     */
+    oneway onRecordStatus(RecordStatus status);
+
+    /**
+     * Notify the client a new status of the demux's playback.
+     *
+     * @param status a new status of the demux's playback.
+     */
+    oneway onPlaybackStatus(PlaybackStatus status);
+};
diff --git a/tv/tuner/1.0/IFilter.hal b/tv/tuner/1.0/IFilter.hal
new file mode 100644
index 0000000..deaf3d4
--- /dev/null
+++ b/tv/tuner/1.0/IFilter.hal
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+import IFilterCallback;
+
+/**
+ * The Filter is used to filter wanted data according to the filter's
+ * configuration.
+ */
+interface IFilter {
+    /**
+     * Get the descriptor of the filter's FMQ
+     *
+     * It is used by the client to get the descriptor of the filter's Fast
+     * Message Queue. The data in FMQ is filtered out from demux input or upper
+     * stream's filter. The data is origanized to data blocks which may have
+     * different length. The length's information of one or multiple data blocks
+     * is sent to client through DemuxFilterEvent. The data in each block
+     * follows the stardard specified by filter's type.
+     * E.X. one data block from the filter with Main_Type==TS and Sub_Type==PES
+     * is Packetized Elementary Stream from Transport Stream according to
+     * ISO/IEC 13818-1.
+     *
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNAVAILABLE if the filter doesn't have FMQ.
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return queue the descriptor of the filter's FMQ
+     */
+    getQueueDesc() generates (Result result, fmq_sync<uint8_t> queue);
+
+    /**
+     * Configure the filter.
+     *
+     * It is used by the client to configure the filter so that it can filter out
+     * intended data.
+     *
+     * @param settings the settings of the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    configure(DemuxFilterSettings settings) generates (Result result);
+
+    /**
+     * Start the filter.
+     *
+     * It is used by the client to ask the filter to start filterring data.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    start() generates (Result result);
+
+    /**
+     * Stop the filter.
+     *
+     * It is used by the client to ask the filter to stop filterring data.
+     * It won't discard the data already filtered out by the filter. The filter
+     * will be stopped and removed automatically if the demux is closed.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stop() generates (Result result);
+
+    /**
+     * Flush the filter.
+     *
+     * It is used by the client to ask the filter to flush the data which is
+     * already produced but not consumed yet.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    flush() generates (Result result);
+
+    /**
+     * Get the filter Id.
+     *
+     * It is used by the client to ask the hardware resource id for the filter.
+     *
+     * @param filterId the hardware resource Id for the filter.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    getId() generates (Result result, uint32_t filterId);
+
+    /**
+     * Set the filter's data source.
+     *
+     * A filter uses demux as data source by default. If the data was packetized
+     * by multiple protocols, multiple filters may need to work together to
+     * extract all protocols' header. Then a filter's data source can be output
+     * from another filter.
+     *
+     * @param filter the filter instance which provides data input. Switch to
+     * use demux as data source if the filter instance is NULL.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setDataSource(IFilter filter) generates (Result result);
+
+    /**
+     * Release the Filter instance
+     *
+     * It is used by the client to release the Filter instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/IFilterCallback.hal b/tv/tuner/1.0/IFilterCallback.hal
new file mode 100644
index 0000000..a0ff62e
--- /dev/null
+++ b/tv/tuner/1.0/IFilterCallback.hal
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+interface IFilterCallback {
+    /**
+     * Notify the client that a new filter event happened.
+     *
+     * @param filterEvent a filter event.
+     */
+    oneway onFilterEvent(DemuxFilterEvent filterEvent);
+
+    /**
+     * Notify the client a new status of a filter.
+     *
+     * @param status a new status of the filter.
+     */
+    oneway onFilterStatus(DemuxFilterStatus status);
+};
diff --git a/tv/tuner/1.0/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
index 962e4ba..ceda2b3 100644
--- a/tv/tuner/1.0/IFrontend.hal
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.hardware.tv.tuner@1.0;
 
 import IFrontendCallback;
@@ -126,7 +127,8 @@
      * @return statuses an array of statuses which response the caller's
      *         request.
      */
-    getStatus(vec<FrontendStatusType> statusTypes) generates (Result result, vec<FrontendStatus> statuses);
+    getStatus(vec<FrontendStatusType> statusTypes)
+        generates (Result result, vec<FrontendStatus> statuses);
 
     /**
      * Sets Low-Noise Block downconverter (LNB) for satellite frontend.
diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal
index 8896a09..88b96c4 100644
--- a/tv/tuner/1.0/IFrontendCallback.hal
+++ b/tv/tuner/1.0/IFrontendCallback.hal
@@ -26,16 +26,6 @@
 
     /**
      * The callback function that must be called by HAL implementation to notify
-     * the client of new DiSEqC message.
-     *
-     * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite
-     * Equipment Control) message which is specified by EUTELSAT Bus Functional
-     * Specification Version 4.2.
-     */
-    oneway onDiseqcMessage(vec<uint8_t> diseqcMessage);
-
-    /**
-     * The callback function that must be called by HAL implementation to notify
      * the client of scan messages.
      *
      * @param type the type of scan message.
diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal
index 6b7119e..5070519 100644
--- a/tv/tuner/1.0/ILnb.hal
+++ b/tv/tuner/1.0/ILnb.hal
@@ -13,8 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package android.hardware.tv.tuner@1.0;
 
+import ILnbCallback;
+
 /**
  * A Tuner LNB (low-noise block downconverter) is used by satellite frontend
  * to receive the microwave signal from the satellite, amplify it, and
@@ -22,6 +25,23 @@
  */
 interface ILnb {
     /**
+     * Set the lnb callback.
+     *
+     * ILnbCallback is used by the client to receive events from the Lnb.
+     * Only one callback per ILnb instance is supported. The callback
+     * will be replaced if it's set again.
+     *
+     * @param callback Callback object to pass Lnb events to the system.
+     *        The previously registered callback must be replaced with this one.
+     *        It can be null.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if callback can't be set at current stage,
+     *         UNKNOWN_ERROR if callback setting failed for other reasons.
+     */
+    setCallback(ILnbCallback callback) generates (Result result);
+
+    /**
      * Set the lnb's power voltage.
      *
      * @param voltage the power's voltage the Lnb to use.
@@ -30,7 +50,7 @@
      *         INVALID_ARGUMENT if the selected voltage isn't allowed,
      *         UNKNOWN_ERROR if failed for other reasons.
      */
-    setVoltage(FrontendLnbVoltage voltage) generates (Result result);
+    setVoltage(LnbVoltage voltage) generates (Result result);
 
     /**
      * Set the lnb's tone mode.
@@ -41,7 +61,7 @@
      *         INVALID_ARGUMENT if the selected tone mode isn't allowed,
      *         UNKNOWN_ERROR if failed for other reasons.
      */
-    setTone(FrontendLnbTone tone) generates (Result result);
+    setTone(LnbTone tone) generates (Result result);
 
     /**
      * Select the lnb's position.
@@ -52,7 +72,7 @@
      *         INVALID_ARGUMENT if the selected position isn't allowed,
      *         UNKNOWN_ERROR if failed for other reasons.
      */
-    setSatellitePosition(FrontendLnbPosition position) generates (Result result);
+    setSatellitePosition(LnbPosition position) generates (Result result);
 
     /**
      *  Sends DiSEqC (Digital Satellite Equipment Control) message.
diff --git a/tv/tuner/1.0/ILnbCallback.hal b/tv/tuner/1.0/ILnbCallback.hal
new file mode 100644
index 0000000..68e9c35
--- /dev/null
+++ b/tv/tuner/1.0/ILnbCallback.hal
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+interface ILnbCallback {
+    /**
+     * Notify the client that a new event happened on the Lnb.
+     *
+     * @param LnbEventType the event type.
+     */
+    oneway onEvent(LnbEventType lnbEventType);
+
+    /**
+     * The callback function that must be called by HAL implementation to notify
+     * the client of new DiSEqC message.
+     *
+     * @param diseqcMessage a byte array of data for DiSEqC (Digital Satellite
+     * Equipment Control) message which is specified by EUTELSAT Bus Functional
+     * Specification Version 4.2.
+     */
+    oneway onDiseqcMessage(vec<uint8_t> diseqcMessage);
+};
diff --git a/tv/tuner/1.0/ITimeFilter.hal b/tv/tuner/1.0/ITimeFilter.hal
new file mode 100644
index 0000000..ce285db
--- /dev/null
+++ b/tv/tuner/1.0/ITimeFilter.hal
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.tv.tuner@1.0;
+
+/**
+ * Timer Filter is used by Demux to filter data based on time stamp.
+ */
+interface ITimeFilter {
+    /**
+     * Set time stamp for time based filter.
+     *
+     * It is used by the client to set initial time stamp and enable time
+     * filtering. The time will be incremented locally. The demux discards
+     * the content which time stamp is older than the time in the time filter.
+     *
+     * @param timeStamp initial time stamp for the time filter. It based on
+     * 90KHz has the same format as PTS (Presentation Time Stamp).
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setTimeStamp(uint64_t timeStamp) generates (Result result);
+
+    /**
+     * Clear the time stamp in the time filter.
+     *
+     * It is used by the client to clear the time value of the time filter,
+     * then disable time filter.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    clearTimeStamp() generates (Result result);
+
+    /**
+     * Get the current time in the time filter.
+     *
+     * It is used by the client to inquiry current time in the time filter.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return timeStamp current time stamp in the time filter.
+     */
+    getTimeStamp() generates (Result result, uint64_t timeStamp);
+
+    /**
+     * Get the time from the beginning of current data source.
+     *
+     * It is used by the client to inquiry the time stamp from the beginning
+     * of current data source.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if failed for wrong state.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     * @return timeStamp time stamp from the beginning of current data source.
+     */
+    getSourceTime() generates (Result result, uint64_t timeStamp);
+
+    /**
+     * Close the Time Filter instance
+     *
+     * It is used by the client to release the demux instance. HAL clear
+     * underneath resource. client mustn't access the instance any more.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    close() generates (Result result);
+};
diff --git a/tv/tuner/1.0/ITuner.hal b/tv/tuner/1.0/ITuner.hal
index 0d63442..2712c13 100644
--- a/tv/tuner/1.0/ITuner.hal
+++ b/tv/tuner/1.0/ITuner.hal
@@ -50,8 +50,7 @@
      *         UNKNOWN_ERROR if creation failed for other reasons.
      * @return frontend the newly created frontend interface.
      */
-    openFrontendById(FrontendId frontendId)
-        generates (Result result, IFrontend frontend);
+    openFrontendById(FrontendId frontendId) generates (Result result, IFrontend frontend);
 
     /**
      * Create a new instance of Demux.
@@ -64,8 +63,7 @@
      * @return demuxId newly created demux id.
      * @return demux the newly created demux interface.
      */
-    openDemux()
-         generates (Result result, DemuxId demuxId, IDemux demux);
+    openDemux() generates (Result result, DemuxId demuxId, IDemux demux);
 
     /**
      * Retrieve the Demux's Capabilities.
@@ -87,8 +85,7 @@
      *         UNKNOWN_ERROR if creation failed for other reasons.
      * @return descrambler the newly created descrambler interface.
      */
-    openDescrambler()
-         generates (Result result, IDescrambler descrambler);
+    openDescrambler() generates (Result result, IDescrambler descrambler);
 
     /**
      * Retrieve the frontend's information.
@@ -99,8 +96,7 @@
      *         UNKNOWN_ERROR if the inquiry failed for other reasons.
      * @return info the frontend's information.
      */
-    getFrontendInfo(FrontendId frontendId)
-        generates (Result result, FrontendInfo info);
+    getFrontendInfo(FrontendId frontendId) generates (Result result, FrontendInfo info);
 
     /**
      * Get low-noise block downconverter (LNB) IDs.
@@ -126,7 +122,5 @@
      *         UNKNOWN_ERROR if creation failed for other reasons.
      * @return lnb the newly created Lnb interface.
      */
-    openLnbById(LnbId lnbId)
-        generates (Result result, ILnb lnb);
+    openLnbById(LnbId lnbId) generates (Result result, ILnb lnb);
 };
-
diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp
index 0ae8bcd..989e25c 100644
--- a/tv/tuner/1.0/default/Android.bp
+++ b/tv/tuner/1.0/default/Android.bp
@@ -4,9 +4,12 @@
     vendor: true,
     relative_install_path: "hw",
     srcs: [
+        "Filter.cpp",
         "Frontend.cpp",
         "Descrambler.cpp",
         "Demux.cpp",
+        "Dvr.cpp",
+        "TimeFilter.cpp",
         "Tuner.cpp",
         "Lnb.cpp",
         "service.cpp",
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index 3a750c2..c5921f7 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -28,45 +28,6 @@
 
 #define WAIT_TIMEOUT 3000000000
 
-const std::vector<uint8_t> fakeDataInputBuffer{
-        0x00, 0x00, 0x00, 0x01, 0x09, 0xf0, 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1e, 0xdb,
-        0x01, 0x40, 0x16, 0xec, 0x04, 0x40, 0x00, 0x00, 0x03, 0x00, 0x40, 0x00, 0x00, 0x0f, 0x03,
-        0xc5, 0x8b, 0xb8, 0x00, 0x00, 0x00, 0x01, 0x68, 0xca, 0x8c, 0xb2, 0x00, 0x00, 0x01, 0x06,
-        0x05, 0xff, 0xff, 0x70, 0xdc, 0x45, 0xe9, 0xbd, 0xe6, 0xd9, 0x48, 0xb7, 0x96, 0x2c, 0xd8,
-        0x20, 0xd9, 0x23, 0xee, 0xef, 0x78, 0x32, 0x36, 0x34, 0x20, 0x2d, 0x20, 0x63, 0x6f, 0x72,
-        0x65, 0x20, 0x31, 0x34, 0x32, 0x20, 0x2d, 0x20, 0x48, 0x2e, 0x32, 0x36, 0x34, 0x2f, 0x4d,
-        0x50, 0x45, 0x47, 0x2d, 0x34, 0x20, 0x41, 0x56, 0x43, 0x20, 0x63, 0x6f, 0x64, 0x65, 0x63,
-        0x20, 0x2d, 0x20, 0x43, 0x6f, 0x70, 0x79, 0x6c, 0x65, 0x66, 0x74, 0x20, 0x32, 0x30, 0x30,
-        0x33, 0x2d, 0x32, 0x30, 0x31, 0x34, 0x20, 0x2d, 0x20, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f,
-        0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x6c, 0x61, 0x6e, 0x2e, 0x6f,
-        0x72, 0x67, 0x2f, 0x78, 0x32, 0x36, 0x34, 0x2e, 0x68, 0x74, 0x6d, 0x6c, 0x20, 0x2d, 0x20,
-        0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x3a, 0x20, 0x63, 0x61, 0x62, 0x61, 0x63, 0x3d,
-        0x30, 0x20, 0x72, 0x65, 0x66, 0x3d, 0x32, 0x20, 0x64, 0x65, 0x62, 0x6c, 0x6f, 0x63, 0x6b,
-        0x3d, 0x31, 0x3a, 0x30, 0x3a, 0x30, 0x20, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x65, 0x3d,
-        0x30, 0x78, 0x31, 0x3a, 0x30, 0x78, 0x31, 0x31, 0x31, 0x20, 0x6d, 0x65, 0x3d, 0x68, 0x65,
-        0x78, 0x20, 0x73, 0x75, 0x62, 0x6d, 0x65, 0x3d, 0x37, 0x20, 0x70, 0x73, 0x79, 0x3d, 0x31,
-        0x20, 0x70, 0x73, 0x79, 0x5f, 0x72, 0x64, 0x3d, 0x31, 0x2e, 0x30, 0x30, 0x3a, 0x30, 0x2e,
-        0x30, 0x30, 0x20, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x3d, 0x31, 0x20,
-        0x6d, 0x65, 0x5f, 0x72, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x31, 0x36, 0x20, 0x63, 0x68, 0x72,
-        0x6f, 0x6d, 0x61, 0x5f, 0x6d, 0x65, 0x3d, 0x31, 0x20, 0x74, 0x72, 0x65, 0x6c, 0x6c, 0x69,
-        0x73, 0x3d, 0x31, 0x20, 0x38, 0x78, 0x38, 0x64, 0x63, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x71,
-        0x6d, 0x3d, 0x30, 0x20, 0x64, 0x65, 0x61, 0x64, 0x7a, 0x6f, 0x6e, 0x65, 0x3d, 0x32, 0x31,
-        0x2c, 0x31, 0x31, 0x20, 0x66, 0x61, 0x73, 0x74, 0x5f, 0x70, 0x73, 0x6b, 0x69, 0x70, 0x3d,
-        0x31, 0x20, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x61, 0x5f, 0x71, 0x70, 0x5f, 0x6f, 0x66, 0x66,
-        0x73, 0x65, 0x74, 0x3d, 0x2d, 0x32, 0x20, 0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d,
-        0x36, 0x30, 0x20, 0x6c, 0x6f, 0x6f, 0x6b, 0x61, 0x68, 0x65, 0x61, 0x64, 0x5f, 0x74, 0x68,
-        0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x35, 0x20, 0x73, 0x6c, 0x69, 0x63, 0x65, 0x64, 0x5f,
-        0x74, 0x68, 0x72, 0x65, 0x61, 0x64, 0x73, 0x3d, 0x30, 0x20, 0x6e, 0x72, 0x3d, 0x30, 0x20,
-        0x64, 0x65, 0x63, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x3d, 0x31, 0x20, 0x69, 0x6e, 0x74, 0x65,
-        0x72, 0x6c, 0x61, 0x63, 0x65, 0x64, 0x3d, 0x30, 0x20, 0x62, 0x6c, 0x75, 0x72, 0x61, 0x79,
-        0x5f, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x74, 0x3d, 0x30, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74,
-        0x72, 0x61, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x69, 0x6e, 0x74, 0x72, 0x61, 0x3d, 0x30, 0x20,
-        0x62, 0x66, 0x72, 0x61, 0x6d, 0x65, 0x73, 0x3d, 0x30, 0x20, 0x77, 0x65, 0x69, 0x67, 0x68,
-        0x74, 0x70, 0x3d, 0x30, 0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x3d, 0x32, 0x35, 0x30,
-        0x20, 0x6b, 0x65, 0x79, 0x69, 0x6e, 0x74, 0x5f, 0x6d, 0x69, 0x6e, 0x3d, 0x32, 0x35, 0x20,
-        0x73, 0x63, 0x65, 0x6e, 0x65,
-};
-
 Demux::Demux(uint32_t demuxId, sp<Tuner> tuner) {
     mDemuxId = demuxId;
     mTunerService = tuner;
@@ -93,8 +54,8 @@
     return startBroadcastInputLoop();
 }
 
-Return<void> Demux::addFilter(DemuxFilterType type, uint32_t bufferSize,
-                              const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) {
+Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+                               const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
     uint32_t filterId;
@@ -105,137 +66,39 @@
         mUnusedFilterIds.erase(filterId);
     } else {
         filterId = ++mLastUsedFilterId;
-
-        mFilterCallbacks.resize(filterId + 1);
-        mFilterMQs.resize(filterId + 1);
-        mFilterEvents.resize(filterId + 1);
-        mFilterEventFlags.resize(filterId + 1);
-        mFilterThreadRunning.resize(filterId + 1);
-        mFilterThreads.resize(filterId + 1);
-        mFilterPids.resize(filterId + 1);
-        mFilterOutputs.resize(filterId + 1);
-        mFilterStatus.resize(filterId + 1);
     }
 
     mUsedFilterIds.insert(filterId);
 
-    if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) {
+    if (cb == nullptr) {
         ALOGW("callback can't be null");
-        _hidl_cb(Result::INVALID_ARGUMENT, filterId);
+        _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
         return Void();
     }
 
-    // Add callback
-    mFilterCallbacks[filterId] = cb;
+    sp<Filter> filter = new Filter(type, filterId, bufferSize, cb, this);
 
-    // Mapping from the filter ID to the filter event
-    DemuxFilterEvent event{
-            .filterId = filterId,
-            .filterType = type,
-    };
-    mFilterEvents[filterId] = event;
-
-    if (!createFilterMQ(bufferSize, filterId)) {
-        _hidl_cb(Result::UNKNOWN_ERROR, -1);
+    if (!filter->createFilterMQ()) {
+        _hidl_cb(Result::UNKNOWN_ERROR, filter);
         return Void();
     }
 
-    _hidl_cb(Result::SUCCESS, filterId);
+    mFilters[filterId] = filter;
+
+    _hidl_cb(Result::SUCCESS, filter);
     return Void();
 }
 
-Return<void> Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) {
+Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) {
-        ALOGW("No filter with id: %d exists to get desc", filterId);
-        _hidl_cb(Result::INVALID_ARGUMENT, FilterMQ::Descriptor());
-        return Void();
-    }
+    sp<TimeFilter> timeFilter = new TimeFilter(this);
 
-    _hidl_cb(Result::SUCCESS, *mFilterMQs[filterId]->getDesc());
+    _hidl_cb(Result::SUCCESS, timeFilter);
     return Void();
 }
 
-Return<Result> Demux::configureFilter(uint32_t filterId, const DemuxFilterSettings& settings) {
-    ALOGV("%s", __FUNCTION__);
-
-    switch (mFilterEvents[filterId].filterType) {
-        case DemuxFilterType::SECTION:
-            mFilterPids[filterId] = settings.section().tpid;
-            break;
-        case DemuxFilterType::PES:
-            mFilterPids[filterId] = settings.pesData().tpid;
-            break;
-        case DemuxFilterType::TS:
-            mFilterPids[filterId] = settings.ts().tpid;
-            break;
-        case DemuxFilterType::AUDIO:
-            mFilterPids[filterId] = settings.audio().tpid;
-            break;
-        case DemuxFilterType::VIDEO:
-            mFilterPids[filterId] = settings.video().tpid;
-            break;
-        case DemuxFilterType::RECORD:
-            mFilterPids[filterId] = settings.record().tpid;
-            break;
-        case DemuxFilterType::PCR:
-            mFilterPids[filterId] = settings.pcr().tpid;
-            break;
-        default:
-            return Result::UNKNOWN_ERROR;
-    }
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::startFilter(uint32_t filterId) {
-    ALOGV("%s", __FUNCTION__);
-    Result result;
-
-    if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) {
-        ALOGW("No filter with id: %d exists to start filter", filterId);
-        return Result::INVALID_ARGUMENT;
-    }
-
-    result = startFilterLoop(filterId);
-
-    return result;
-}
-
-Return<Result> Demux::stopFilter(uint32_t filterId) {
-    ALOGV("%s", __FUNCTION__);
-
-    mFilterThreadRunning[filterId] = false;
-
-    std::lock_guard<std::mutex> lock(mFilterThreadLock);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::flushFilter(uint32_t filterId) {
-    ALOGV("%s", __FUNCTION__);
-
-    // temp implementation to flush the FMQ
-    int size = mFilterMQs[filterId]->availableToRead();
-    char* buffer = new char[size];
-    mOutputMQ->read((unsigned char*)&buffer[0], size);
-    delete[] buffer;
-    mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY;
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::removeFilter(uint32_t filterId) {
-    ALOGV("%s", __FUNCTION__);
-
-    // resetFilterRecords(filterId);
-    mUsedFilterIds.erase(filterId);
-    mUnusedFilterIds.insert(filterId);
-
-    return Result::SUCCESS;
-}
-
-Return<void> Demux::getAvSyncHwId(uint32_t /* filterId */, getAvSyncHwId_cb _hidl_cb) {
+Return<void> Demux::getAvSyncHwId(const sp<IFilter>& /* filter */, getAvSyncHwId_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
     AvSyncHwId avSyncHwId = 0;
@@ -256,588 +119,81 @@
 Return<Result> Demux::close() {
     ALOGV("%s", __FUNCTION__);
 
-    set<uint32_t>::iterator it;
-    mInputThread = 0;
-    mOutputThread = 0;
-    mFilterThreads.clear();
     mUnusedFilterIds.clear();
     mUsedFilterIds.clear();
-    mFilterCallbacks.clear();
-    mFilterMQs.clear();
-    mFilterEvents.clear();
-    mFilterEventFlags.clear();
-    mFilterOutputs.clear();
-    mFilterPids.clear();
     mLastUsedFilterId = -1;
 
     return Result::SUCCESS;
 }
 
-Return<Result> Demux::addOutput(uint32_t bufferSize, const sp<IDemuxCallback>& cb) {
+Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+                            openDvr_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    // Create a synchronized FMQ that supports blocking read/write
-    std::unique_ptr<FilterMQ> tmpFilterMQ =
-            std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(bufferSize, true));
-    if (!tmpFilterMQ->isValid()) {
-        ALOGW("Failed to create output FMQ");
-        return Result::UNKNOWN_ERROR;
-    }
-
-    mOutputMQ = std::move(tmpFilterMQ);
-
-    if (EventFlag::createEventFlag(mOutputMQ->getEventFlagWord(), &mOutputEventFlag) != OK) {
-        return Result::UNKNOWN_ERROR;
-    }
-
-    mOutputCallback = cb;
-
-    return Result::SUCCESS;
-}
-
-Return<void> Demux::getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) {
-    ALOGV("%s", __FUNCTION__);
-
-    if (!mOutputMQ) {
-        _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor());
+    if (cb == nullptr) {
+        ALOGW("DVR callback can't be null");
+        _hidl_cb(Result::INVALID_ARGUMENT, new Dvr());
         return Void();
     }
 
-    _hidl_cb(Result::SUCCESS, *mOutputMQ->getDesc());
-    return Void();
-}
+    sp<Dvr> dvr = new Dvr(type, bufferSize, cb, this);
 
-Return<Result> Demux::configureOutput(const DemuxOutputSettings& settings) {
-    ALOGV("%s", __FUNCTION__);
-
-    mOutputConfigured = true;
-    mOutputSettings = settings;
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::attachOutputFilter(uint32_t /*filterId*/) {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::detachOutputFilter(uint32_t /* filterId */) {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::startOutput() {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::stopOutput() {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::flushOutput() {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::removeOutput() {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::addInput(uint32_t bufferSize, const sp<IDemuxCallback>& cb) {
-    ALOGV("%s", __FUNCTION__);
-
-    // Create a synchronized FMQ that supports blocking read/write
-    std::unique_ptr<FilterMQ> tmpInputMQ =
-            std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(bufferSize, true));
-    if (!tmpInputMQ->isValid()) {
-        ALOGW("Failed to create input FMQ");
-        return Result::UNKNOWN_ERROR;
-    }
-
-    mInputMQ = std::move(tmpInputMQ);
-
-    if (EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputEventFlag) != OK) {
-        return Result::UNKNOWN_ERROR;
-    }
-
-    mInputCallback = cb;
-
-    return Result::SUCCESS;
-}
-
-Return<void> Demux::getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) {
-    ALOGV("%s", __FUNCTION__);
-
-    if (!mInputMQ) {
-        _hidl_cb(Result::NOT_INITIALIZED, FilterMQ::Descriptor());
+    if (!dvr->createDvrMQ()) {
+        _hidl_cb(Result::UNKNOWN_ERROR, dvr);
         return Void();
     }
 
-    _hidl_cb(Result::SUCCESS, *mInputMQ->getDesc());
+    _hidl_cb(Result::SUCCESS, dvr);
     return Void();
 }
 
-Return<Result> Demux::configureInput(const DemuxInputSettings& settings) {
+Result Demux::removeFilter(uint32_t filterId) {
     ALOGV("%s", __FUNCTION__);
 
-    mInputConfigured = true;
-    mInputSettings = settings;
+    // resetFilterRecords(filterId);
+    mUsedFilterIds.erase(filterId);
+    mUnusedFilterIds.insert(filterId);
+    mFilters.erase(filterId);
 
     return Result::SUCCESS;
 }
 
-Return<Result> Demux::startInput() {
-    ALOGV("%s", __FUNCTION__);
-
-    if (!mInputCallback) {
-        return Result::NOT_INITIALIZED;
-    }
-
-    if (!mInputConfigured) {
-        return Result::INVALID_STATE;
-    }
-
-    pthread_create(&mInputThread, NULL, __threadLoopInput, this);
-    pthread_setname_np(mInputThread, "demux_input_waiting_loop");
-
-    // TODO start another thread to send filter status callback to the framework
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::stopInput() {
-    ALOGV("%s", __FUNCTION__);
-
-    mInputThreadRunning = false;
-
-    std::lock_guard<std::mutex> lock(mInputThreadLock);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::flushInput() {
-    ALOGV("%s", __FUNCTION__);
-
-    return Result::SUCCESS;
-}
-
-Return<Result> Demux::removeInput() {
-    ALOGV("%s", __FUNCTION__);
-
-    mInputMQ = nullptr;
-
-    return Result::SUCCESS;
-}
-
-Result Demux::startFilterLoop(uint32_t filterId) {
-    struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs));
-    threadArgs->user = this;
-    threadArgs->filterId = filterId;
-
-    pthread_t mFilterThread;
-    pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
-    mFilterThreads[filterId] = mFilterThread;
-    pthread_setname_np(mFilterThread, "demux_filter_waiting_loop");
-
-    return Result::SUCCESS;
-}
-
-Result Demux::startSectionFilterHandler(uint32_t filterId) {
-    if (mFilterOutputs[filterId].empty()) {
-        return Result::SUCCESS;
-    }
-    if (!writeSectionsAndCreateEvent(filterId, mFilterOutputs[filterId])) {
-        ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId);
-        return Result::UNKNOWN_ERROR;
-    }
-
-    mFilterOutputs[filterId].clear();
-
-    return Result::SUCCESS;
-}
-
-Result Demux::startPesFilterHandler(uint32_t filterId) {
-    std::lock_guard<std::mutex> lock(mFilterEventLock);
-    if (mFilterOutputs[filterId].empty()) {
-        return Result::SUCCESS;
-    }
-
-    for (int i = 0; i < mFilterOutputs[filterId].size(); i += 188) {
-        if (mPesSizeLeft == 0) {
-            uint32_t prefix = (mFilterOutputs[filterId][i + 4] << 16) |
-                              (mFilterOutputs[filterId][i + 5] << 8) |
-                              mFilterOutputs[filterId][i + 6];
-            ALOGD("[Demux] prefix %d", prefix);
-            if (prefix == 0x000001) {
-                // TODO handle mulptiple Pes filters
-                mPesSizeLeft =
-                        (mFilterOutputs[filterId][i + 8] << 8) | mFilterOutputs[filterId][i + 9];
-                mPesSizeLeft += 6;
-                ALOGD("[Demux] pes data length %d", mPesSizeLeft);
-            } else {
-                continue;
-            }
-        }
-
-        int endPoint = min(184, mPesSizeLeft);
-        // append data and check size
-        vector<uint8_t>::const_iterator first = mFilterOutputs[filterId].begin() + i + 4;
-        vector<uint8_t>::const_iterator last = mFilterOutputs[filterId].begin() + i + 4 + endPoint;
-        mPesOutput.insert(mPesOutput.end(), first, last);
-        // size does not match then continue
-        mPesSizeLeft -= endPoint;
-        if (mPesSizeLeft > 0) {
-            continue;
-        }
-        // size match then create event
-        if (!writeDataToFilterMQ(mPesOutput, filterId)) {
-            mFilterOutputs[filterId].clear();
-            return Result::INVALID_STATE;
-        }
-        maySendFilterStatusCallback(filterId);
-        DemuxFilterPesEvent pesEvent;
-        pesEvent = {
-                // temp dump meta data
-                .streamId = mPesOutput[3],
-                .dataLength = static_cast<uint16_t>(mPesOutput.size()),
-        };
-        ALOGD("[Demux] assembled pes data length %d", pesEvent.dataLength);
-
-        int size = mFilterEvents[filterId].events.size();
-        mFilterEvents[filterId].events.resize(size + 1);
-        mFilterEvents[filterId].events[size].pes(pesEvent);
-        mPesOutput.clear();
-    }
-
-    mFilterOutputs[filterId].clear();
-
-    return Result::SUCCESS;
-}
-
-Result Demux::startTsFilterHandler() {
-    // TODO handle starting TS filter
-    return Result::SUCCESS;
-}
-
-Result Demux::startMediaFilterHandler(uint32_t filterId) {
-    DemuxFilterMediaEvent mediaEvent;
-    mediaEvent = {
-            // temp dump meta data
-            .pts = 0,
-            .dataLength = 530,
-            .secureMemory = nullptr,
-    };
-    mFilterEvents[filterId].events.resize(1);
-    mFilterEvents[filterId].events[0].media() = mediaEvent;
-
-    mFilterOutputs[filterId].clear();
-    // TODO handle write FQM for media stream
-    return Result::SUCCESS;
-}
-
-Result Demux::startRecordFilterHandler(uint32_t filterId) {
-    DemuxFilterRecordEvent recordEvent;
-    recordEvent = {
-            // temp dump meta data
-            .tpid = 0,
-            .packetNum = 0,
-    };
-    recordEvent.indexMask.tsIndexMask() = 0x01;
-    mFilterEvents[filterId].events.resize(1);
-    mFilterEvents[filterId].events[0].ts() = recordEvent;
-
-    mFilterOutputs[filterId].clear();
-    return Result::SUCCESS;
-}
-
-Result Demux::startPcrFilterHandler() {
-    // TODO handle starting PCR filter
-    return Result::SUCCESS;
-}
-
-bool Demux::createFilterMQ(uint32_t bufferSize, uint32_t filterId) {
-    ALOGV("%s", __FUNCTION__);
-
-    // Create a synchronized FMQ that supports blocking read/write
-    std::unique_ptr<FilterMQ> tmpFilterMQ =
-            std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(bufferSize, true));
-    if (!tmpFilterMQ->isValid()) {
-        ALOGW("Failed to create FMQ of filter with id: %d", filterId);
-        return false;
-    }
-
-    mFilterMQs[filterId] = std::move(tmpFilterMQ);
-
-    EventFlag* filterEventFlag;
-    if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &filterEventFlag) !=
-        OK) {
-        return false;
-    }
-    mFilterEventFlags[filterId] = filterEventFlag;
-
-    return true;
-}
-
-bool Demux::writeSectionsAndCreateEvent(uint32_t filterId, vector<uint8_t> data) {
-    // TODO check how many sections has been read
-    std::lock_guard<std::mutex> lock(mFilterEventLock);
-    if (!writeDataToFilterMQ(data, filterId)) {
-        return false;
-    }
-    int size = mFilterEvents[filterId].events.size();
-    mFilterEvents[filterId].events.resize(size + 1);
-    DemuxFilterSectionEvent secEvent;
-    secEvent = {
-            // temp dump meta data
-            .tableId = 0,
-            .version = 1,
-            .sectionNum = 1,
-            .dataLength = static_cast<uint16_t>(data.size()),
-    };
-    mFilterEvents[filterId].events[size].section(secEvent);
-    return true;
-}
-
-bool Demux::writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId) {
-    std::lock_guard<std::mutex> lock(mWriteLock);
-    if (mFilterMQs[filterId]->write(data.data(), data.size())) {
-        return true;
-    }
-    return false;
-}
-
-bool Demux::readInputFMQ() {
-    // Read input data from the input FMQ
-    int size = mInputMQ->availableToRead();
-    int inputPacketSize = mInputSettings.packetSize;
-    vector<uint8_t> dataOutputBuffer;
-    dataOutputBuffer.resize(inputPacketSize);
-
-    // Dispatch the packet to the PID matching filter output buffer
-    for (int i = 0; i < size / inputPacketSize; i++) {
-        if (!mInputMQ->read(dataOutputBuffer.data(), inputPacketSize)) {
-            return false;
-        }
-        startTsFilter(dataOutputBuffer);
-    }
-
-    return true;
-}
-
 void Demux::startTsFilter(vector<uint8_t> data) {
     set<uint32_t>::iterator it;
     for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
         uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
-        ALOGW("start ts filter pid: %d", pid);
-        if (pid == mFilterPids[*it]) {
-            mFilterOutputs[*it].insert(mFilterOutputs[*it].end(), data.begin(), data.end());
+        if (DEBUG_FILTER) {
+            ALOGW("start ts filter pid: %d", pid);
+        }
+        if (pid == mFilters[*it]->getTpid()) {
+            mFilters[*it]->updateFilterOutput(data);
         }
     }
 }
 
 bool Demux::startFilterDispatcher() {
-    Result result;
     set<uint32_t>::iterator it;
 
     // Handle the output data per filter type
     for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
-        switch (mFilterEvents[*it].filterType) {
-            case DemuxFilterType::SECTION:
-                result = startSectionFilterHandler(*it);
-                break;
-            case DemuxFilterType::PES:
-                result = startPesFilterHandler(*it);
-                break;
-            case DemuxFilterType::TS:
-                result = startTsFilterHandler();
-                break;
-            case DemuxFilterType::AUDIO:
-            case DemuxFilterType::VIDEO:
-                result = startMediaFilterHandler(*it);
-                break;
-            case DemuxFilterType::RECORD:
-                result = startRecordFilterHandler(*it);
-                break;
-            case DemuxFilterType::PCR:
-                result = startPcrFilterHandler();
-                break;
-            default:
-                return false;
+        if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
+            return false;
         }
     }
 
-    return result == Result::SUCCESS;
+    return true;
 }
 
-void* Demux::__threadLoopFilter(void* threadArg) {
-    Demux* const self = static_cast<Demux*>(((struct ThreadArgs*)threadArg)->user);
-    self->filterThreadLoop(((struct ThreadArgs*)threadArg)->filterId);
-    return 0;
+Result Demux::startFilterHandler(uint32_t filterId) {
+    return mFilters[filterId]->startFilterHandler();
 }
 
-void* Demux::__threadLoopInput(void* user) {
-    Demux* const self = static_cast<Demux*>(user);
-    self->inputThreadLoop();
-    return 0;
+void Demux::updateFilterOutput(uint16_t filterId, vector<uint8_t> data) {
+    mFilters[filterId]->updateFilterOutput(data);
 }
 
-void Demux::filterThreadLoop(uint32_t filterId) {
-    ALOGD("[Demux] filter %d threadLoop start.", filterId);
-    std::lock_guard<std::mutex> lock(mFilterThreadLock);
-    mFilterThreadRunning[filterId] = true;
-
-    // For the first time of filter output, implementation needs to send the filter
-    // Event Callback without waiting for the DATA_CONSUMED to init the process.
-    while (mFilterThreadRunning[filterId]) {
-        if (mFilterEvents[filterId].events.size() == 0) {
-            ALOGD("[Demux] wait for filter data output.");
-            usleep(1000 * 1000);
-            continue;
-        }
-        // After successfully write, send a callback and wait for the read to be done
-        mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
-        mFilterEvents[filterId].events.resize(0);
-        mFilterStatus[filterId] = DemuxFilterStatus::DATA_READY;
-        mFilterCallbacks[filterId]->onFilterStatus(filterId, mFilterStatus[filterId]);
-        break;
-    }
-
-    while (mFilterThreadRunning[filterId]) {
-        uint32_t efState = 0;
-        // We do not wait for the last round of writen data to be read to finish the thread
-        // because the VTS can verify the reading itself.
-        for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
-            while (mFilterThreadRunning[filterId]) {
-                status_t status = mFilterEventFlags[filterId]->wait(
-                        static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
-                        WAIT_TIMEOUT, true /* retry on spurious wake */);
-                if (status != OK) {
-                    ALOGD("[Demux] wait for data consumed");
-                    continue;
-                }
-                break;
-            }
-
-            if (mFilterCallbacks[filterId] == nullptr) {
-                ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId);
-                break;
-            }
-
-            maySendFilterStatusCallback(filterId);
-
-            while (mFilterThreadRunning[filterId]) {
-                std::lock_guard<std::mutex> lock(mFilterEventLock);
-                if (mFilterEvents[filterId].events.size() == 0) {
-                    continue;
-                }
-                // After successfully write, send a callback and wait for the read to be done
-                mFilterCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
-                mFilterEvents[filterId].events.resize(0);
-                break;
-            }
-            // We do not wait for the last read to be done
-            // VTS can verify the read result itself.
-            if (i == SECTION_WRITE_COUNT - 1) {
-                ALOGD("[Demux] filter %d writing done. Ending thread", filterId);
-                break;
-            }
-        }
-        mFilterThreadRunning[filterId] = false;
-    }
-
-    ALOGD("[Demux] filter thread ended.");
-}
-
-void Demux::inputThreadLoop() {
-    ALOGD("[Demux] input threadLoop start.");
-    std::lock_guard<std::mutex> lock(mInputThreadLock);
-    mInputThreadRunning = true;
-
-    while (mInputThreadRunning) {
-        uint32_t efState = 0;
-        status_t status =
-                mInputEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
-                                      &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
-        if (status != OK) {
-            ALOGD("[Demux] wait for data ready on the input FMQ");
-            continue;
-        }
-        // Our current implementation filter the data and write it into the filter FMQ immedaitely
-        // after the DATA_READY from the VTS/framework
-        if (!readInputFMQ() || !startFilterDispatcher()) {
-            ALOGD("[Demux] input data failed to be filtered. Ending thread");
-            break;
-        }
-
-        maySendInputStatusCallback();
-    }
-
-    mInputThreadRunning = false;
-    ALOGD("[Demux] input thread ended.");
-}
-
-void Demux::maySendInputStatusCallback() {
-    std::lock_guard<std::mutex> lock(mInputStatusLock);
-    int availableToRead = mInputMQ->availableToRead();
-    int availableToWrite = mInputMQ->availableToWrite();
-
-    DemuxInputStatus newStatus =
-            checkInputStatusChange(availableToWrite, availableToRead, mInputSettings.highThreshold,
-                                   mInputSettings.lowThreshold);
-    if (mIntputStatus != newStatus) {
-        mInputCallback->onInputStatus(newStatus);
-        mIntputStatus = newStatus;
-    }
-}
-
-void Demux::maySendFilterStatusCallback(uint32_t filterId) {
-    std::lock_guard<std::mutex> lock(mFilterStatusLock);
-    int availableToRead = mFilterMQs[filterId]->availableToRead();
-    int availableToWrite = mFilterMQs[filterId]->availableToWrite();
-    int fmqSize = mFilterMQs[filterId]->getQuantumCount();
-
-    DemuxFilterStatus newStatus =
-            checkFilterStatusChange(filterId, availableToWrite, availableToRead,
-                                    ceil(fmqSize * 0.75), ceil(fmqSize * 0.25));
-    if (mFilterStatus[filterId] != newStatus) {
-        mFilterCallbacks[filterId]->onFilterStatus(filterId, newStatus);
-        mFilterStatus[filterId] = newStatus;
-    }
-}
-
-DemuxInputStatus Demux::checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
-                                               uint32_t highThreshold, uint32_t lowThreshold) {
-    if (availableToWrite == 0) {
-        return DemuxInputStatus::SPACE_FULL;
-    } else if (availableToRead > highThreshold) {
-        return DemuxInputStatus::SPACE_ALMOST_FULL;
-    } else if (availableToRead < lowThreshold) {
-        return DemuxInputStatus::SPACE_ALMOST_EMPTY;
-    } else if (availableToRead == 0) {
-        return DemuxInputStatus::SPACE_EMPTY;
-    }
-    return mIntputStatus;
-}
-
-DemuxFilterStatus Demux::checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite,
-                                                 uint32_t availableToRead, uint32_t highThreshold,
-                                                 uint32_t lowThreshold) {
-    if (availableToWrite == 0) {
-        return DemuxFilterStatus::OVERFLOW;
-    } else if (availableToRead > highThreshold) {
-        return DemuxFilterStatus::HIGH_WATER;
-    } else if (availableToRead < lowThreshold) {
-        return DemuxFilterStatus::LOW_WATER;
-    }
-    return mFilterStatus[filterId];
+uint16_t Demux::getFilterTpid(uint32_t filterId) {
+    return mFilters[filterId]->getTpid();
 }
 
 Result Demux::startBroadcastInputLoop() {
@@ -876,6 +232,7 @@
             for (int i = 0; i < writePacketAmount; i++) {
                 inputData.read(buffer, packetSize);
                 if (!inputData) {
+                    mKeepFetchingDataFromFrontend = false;
                     mBroadcastInputThreadRunning = false;
                     break;
                 }
@@ -888,7 +245,7 @@
                 startTsFilter(byteBuffer);
             }
             startFilterDispatcher();
-            sleep(1);
+            usleep(100);
         }
     }
 
@@ -898,6 +255,7 @@
 }
 
 void Demux::stopBroadcastInput() {
+    ALOGD("[Demux] stop frontend on demux");
     mKeepFetchingDataFromFrontend = false;
     mBroadcastInputThreadRunning = false;
     std::lock_guard<std::mutex> lock(mBroadcastInputThreadLock);
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index ba0b9b0..a9756cc 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -21,7 +21,10 @@
 #include <fmq/MessageQueue.h>
 #include <math.h>
 #include <set>
+#include "Dvr.h"
+#include "Filter.h"
 #include "Frontend.h"
+#include "TimeFilter.h"
 #include "Tuner.h"
 
 using namespace std;
@@ -38,13 +41,17 @@
 using ::android::hardware::MessageQueue;
 using ::android::hardware::MQDescriptorSync;
 using ::android::hardware::tv::tuner::V1_0::IDemux;
-using ::android::hardware::tv::tuner::V1_0::IDemuxCallback;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
 using ::android::hardware::tv::tuner::V1_0::Result;
 
 using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 
-class Tuner;
+class Dvr;
+class Filter;
 class Frontend;
+class TimeFilter;
+class Tuner;
 
 class Demux : public IDemux {
   public:
@@ -54,63 +61,27 @@
 
     virtual Return<Result> setFrontendDataSource(uint32_t frontendId) override;
 
-    virtual Return<Result> close() override;
+    virtual Return<void> openFilter(const DemuxFilterType& type, uint32_t bufferSize,
+                                    const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) override;
 
-    virtual Return<void> addFilter(DemuxFilterType type, uint32_t bufferSize,
-                                   const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) override;
+    virtual Return<void> openTimeFilter(openTimeFilter_cb _hidl_cb) override;
 
-    virtual Return<void> getFilterQueueDesc(uint32_t filterId,
-                                            getFilterQueueDesc_cb _hidl_cb) override;
-
-    virtual Return<Result> configureFilter(uint32_t filterId,
-                                           const DemuxFilterSettings& settings) override;
-
-    virtual Return<Result> startFilter(uint32_t filterId) override;
-
-    virtual Return<Result> stopFilter(uint32_t filterId) override;
-
-    virtual Return<Result> flushFilter(uint32_t filterId) override;
-
-    virtual Return<Result> removeFilter(uint32_t filterId) override;
-
-    virtual Return<void> getAvSyncHwId(uint32_t filterId, getAvSyncHwId_cb _hidl_cb) override;
+    virtual Return<void> getAvSyncHwId(const sp<IFilter>& filter,
+                                       getAvSyncHwId_cb _hidl_cb) override;
 
     virtual Return<void> getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) override;
 
-    virtual Return<Result> addInput(uint32_t bufferSize, const sp<IDemuxCallback>& cb) override;
+    virtual Return<Result> close() override;
 
-    virtual Return<void> getInputQueueDesc(getInputQueueDesc_cb _hidl_cb) override;
-
-    virtual Return<Result> configureInput(const DemuxInputSettings& settings) override;
-
-    virtual Return<Result> startInput() override;
-
-    virtual Return<Result> stopInput() override;
-
-    virtual Return<Result> flushInput() override;
-
-    virtual Return<Result> removeInput() override;
-
-    virtual Return<Result> addOutput(uint32_t bufferSize, const sp<IDemuxCallback>& cb) override;
-
-    virtual Return<void> getOutputQueueDesc(getOutputQueueDesc_cb _hidl_cb) override;
-
-    virtual Return<Result> configureOutput(const DemuxOutputSettings& settings) override;
-
-    virtual Return<Result> attachOutputFilter(uint32_t filterId) override;
-
-    virtual Return<Result> detachOutputFilter(uint32_t filterId) override;
-
-    virtual Return<Result> startOutput() override;
-
-    virtual Return<Result> stopOutput() override;
-
-    virtual Return<Result> flushOutput() override;
-
-    virtual Return<Result> removeOutput() override;
+    virtual Return<void> openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
+                                 openDvr_cb _hidl_cb) override;
 
     // Functions interacts with Tuner Service
     void stopBroadcastInput();
+    Result removeFilter(uint32_t filterId);
+    Result startFilterHandler(uint32_t filterId);
+    void updateFilterOutput(uint16_t filterId, vector<uint8_t> data);
+    uint16_t getFilterTpid(uint32_t filterId);
 
   private:
     // Tuner service
@@ -126,19 +97,9 @@
         uint32_t filterId;
     };
 
-    /**
-     * Filter handlers to handle the data filtering.
-     * They are also responsible to write the filtered output into the filter FMQ
-     * and update the filterEvent bound with the same filterId.
-     */
-    Result startSectionFilterHandler(uint32_t filterId);
-    Result startPesFilterHandler(uint32_t filterId);
-    Result startTsFilterHandler();
-    Result startMediaFilterHandler(uint32_t filterId);
-    Result startRecordFilterHandler(uint32_t filterId);
-    Result startPcrFilterHandler();
-    Result startFilterLoop(uint32_t filterId);
     Result startBroadcastInputLoop();
+    static void* __threadLoopBroadcast(void* user);
+    void broadcastInputThreadLoop();
 
     /**
      * To create a FilterMQ with the the next available Filter ID.
@@ -147,32 +108,14 @@
      *
      * Return false is any of the above processes fails.
      */
-    bool createFilterMQ(uint32_t bufferSize, uint32_t filterId);
-    bool createMQ(FilterMQ* queue, EventFlag* eventFlag, uint32_t bufferSize);
     void deleteEventFlag();
-    bool writeDataToFilterMQ(const std::vector<uint8_t>& data, uint32_t filterId);
     bool readDataFromMQ();
-    bool writeSectionsAndCreateEvent(uint32_t filterId, vector<uint8_t> data);
-    void maySendInputStatusCallback();
-    void maySendFilterStatusCallback(uint32_t filterId);
-    DemuxInputStatus checkInputStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
-                                            uint32_t highThreshold, uint32_t lowThreshold);
-    DemuxFilterStatus checkFilterStatusChange(uint32_t filterId, uint32_t availableToWrite,
-                                              uint32_t availableToRead, uint32_t highThreshold,
-                                              uint32_t lowThreshold);
     /**
      * A dispatcher to read and dispatch input data to all the started filters.
      * Each filter handler handles the data filtering/output writing/filterEvent updating.
      */
-    bool readInputFMQ();
-    void startTsFilter(vector<uint8_t> data);
     bool startFilterDispatcher();
-    static void* __threadLoopFilter(void* data);
-    static void* __threadLoopInput(void* user);
-    static void* __threadLoopBroadcast(void* user);
-    void filterThreadLoop(uint32_t filterId);
-    void inputThreadLoop();
-    void broadcastInputThreadLoop();
+    void startTsFilter(vector<uint8_t> data);
 
     uint32_t mDemuxId;
     /**
@@ -196,40 +139,13 @@
      * A list of created FilterMQ ptrs.
      * The array number is the filter ID.
      */
-    vector<uint16_t> mFilterPids;
-    vector<vector<uint8_t>> mFilterOutputs;
-    vector<unique_ptr<FilterMQ>> mFilterMQs;
-    vector<EventFlag*> mFilterEventFlags;
-    vector<DemuxFilterEvent> mFilterEvents;
-    unique_ptr<FilterMQ> mInputMQ;
-    unique_ptr<FilterMQ> mOutputMQ;
-    EventFlag* mInputEventFlag;
-    EventFlag* mOutputEventFlag;
-    /**
-     * Demux callbacks used on filter events or IO buffer status
-     */
-    vector<sp<IDemuxCallback>> mFilterCallbacks;
-    sp<IDemuxCallback> mInputCallback;
-    sp<IDemuxCallback> mOutputCallback;
-    bool mInputConfigured = false;
-    bool mOutputConfigured = false;
-    DemuxInputSettings mInputSettings;
-    DemuxOutputSettings mOutputSettings;
+    std::map<uint32_t, sp<Filter>> mFilters;
 
     // Thread handlers
-    pthread_t mInputThread;
-    pthread_t mOutputThread;
     pthread_t mBroadcastInputThread;
-    vector<pthread_t> mFilterThreads;
-
-    // FMQ status local records
-    DemuxInputStatus mIntputStatus;
-    vector<DemuxFilterStatus> mFilterStatus;
     /**
      * If a specific filter's writing loop is still running
      */
-    vector<bool> mFilterThreadRunning;
-    bool mInputThreadRunning;
     bool mBroadcastInputThreadRunning;
     bool mKeepFetchingDataFromFrontend;
     /**
@@ -237,28 +153,16 @@
      */
     std::mutex mWriteLock;
     /**
-     * Lock to protect writes to the filter event
-     */
-    // TODO make each filter separate event lock
-    std::mutex mFilterEventLock;
-    /**
      * Lock to protect writes to the input status
      */
-    std::mutex mInputStatusLock;
-    std::mutex mFilterStatusLock;
     std::mutex mBroadcastInputThreadLock;
-    std::mutex mFilterThreadLock;
-    std::mutex mInputThreadLock;
-    /**
-     * How many times a filter should write
-     * TODO make this dynamic/random/can take as a parameter
-     */
-    const uint16_t SECTION_WRITE_COUNT = 10;
 
     // temp handle single PES filter
     // TODO handle mulptiple Pes filters
     int mPesSizeLeft = 0;
     vector<uint8_t> mPesOutput;
+
+    const bool DEBUG_FILTER = false;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Descrambler.cpp b/tv/tuner/1.0/default/Descrambler.cpp
index 085f2c8..e3f5b22 100644
--- a/tv/tuner/1.0/default/Descrambler.cpp
+++ b/tv/tuner/1.0/default/Descrambler.cpp
@@ -50,13 +50,15 @@
     return Result::SUCCESS;
 }
 
-Return<Result> Descrambler::addPid(uint16_t /* pid */) {
+Return<Result> Descrambler::addPid(const DemuxPid& /* pid */,
+                                   const sp<IFilter>& /* optionalSourceFilter */) {
     ALOGV("%s", __FUNCTION__);
 
     return Result::SUCCESS;
 }
 
-Return<Result> Descrambler::removePid(uint16_t /* pid */) {
+Return<Result> Descrambler::removePid(const DemuxPid& /* pid */,
+                                      const sp<IFilter>& /* optionalSourceFilter */) {
     ALOGV("%s", __FUNCTION__);
 
     return Result::SUCCESS;
diff --git a/tv/tuner/1.0/default/Descrambler.h b/tv/tuner/1.0/default/Descrambler.h
index 436adcf..c889820 100644
--- a/tv/tuner/1.0/default/Descrambler.h
+++ b/tv/tuner/1.0/default/Descrambler.h
@@ -40,9 +40,11 @@
 
     virtual Return<Result> setKeyToken(const hidl_vec<uint8_t>& keyToken) override;
 
-    virtual Return<Result> addPid(uint16_t pid) override;
+    virtual Return<Result> addPid(const DemuxPid& pid,
+                                  const sp<IFilter>& optionalSourceFilter) override;
 
-    virtual Return<Result> removePid(uint16_t pid) override;
+    virtual Return<Result> removePid(const DemuxPid& pid,
+                                     const sp<IFilter>& optionalSourceFilter) override;
 
     virtual Return<Result> close() override;
 
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
new file mode 100644
index 0000000..eb38f90
--- /dev/null
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2019 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 "android.hardware.tv.tuner@1.0-Dvr"
+
+#include "Dvr.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Dvr::Dvr() {}
+
+Dvr::Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux) {
+    mType = type;
+    mBufferSize = bufferSize;
+    mCallback = cb;
+    mDemux = demux;
+}
+
+Dvr::~Dvr() {}
+
+Return<void> Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Dvr::configure(const DvrSettings& settings) {
+    ALOGV("%s", __FUNCTION__);
+
+    mDvrSettings = settings;
+    mDvrConfigured = true;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::attachFilter(const sp<IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint32_t filterId;
+    Result status;
+
+    filter->getId([&](Result result, uint32_t id) {
+        filterId = id;
+        status = result;
+    });
+
+    if (status != Result::SUCCESS) {
+        return status;
+    }
+
+    mFilters[filterId] = filter;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint32_t filterId;
+    Result status;
+
+    filter->getId([&](Result result, uint32_t id) {
+        filterId = id;
+        status = result;
+    });
+
+    if (status != Result::SUCCESS) {
+        return status;
+    }
+
+    std::map<uint32_t, sp<IFilter>>::iterator it;
+
+    it = mFilters.find(filterId);
+    if (it != mFilters.end()) {
+        mFilters.erase(filterId);
+    }
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::start() {
+    ALOGV("%s", __FUNCTION__);
+
+    if (!mCallback) {
+        return Result::NOT_INITIALIZED;
+    }
+
+    if (!mDvrConfigured) {
+        return Result::INVALID_STATE;
+    }
+
+    if (mType == DvrType::PLAYBACK) {
+        pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
+        pthread_setname_np(mDvrThread, "playback_waiting_loop");
+    } else if (mType == DvrType::RECORD) {
+        /*pthread_create(&mInputThread, NULL, __threadLoopInput, this);
+        pthread_setname_np(mInputThread, "playback_waiting_loop");*/
+    }
+
+    // TODO start another thread to send filter status callback to the framework
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::stop() {
+    ALOGV("%s", __FUNCTION__);
+
+    mDvrThreadRunning = false;
+
+    std::lock_guard<std::mutex> lock(mDvrThreadLock);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::flush() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Dvr::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+bool Dvr::createDvrMQ() {
+    ALOGV("%s", __FUNCTION__);
+
+    // Create a synchronized FMQ that supports blocking read/write
+    std::unique_ptr<DvrMQ> tmpDvrMQ =
+            std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
+    if (!tmpDvrMQ->isValid()) {
+        ALOGW("Failed to create FMQ of DVR");
+        return false;
+    }
+
+    mDvrMQ = std::move(tmpDvrMQ);
+
+    if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
+        return false;
+    }
+
+    return true;
+}
+
+void* Dvr::__threadLoopPlayback(void* user) {
+    Dvr* const self = static_cast<Dvr*>(user);
+    self->playbackThreadLoop();
+    return 0;
+}
+
+void Dvr::playbackThreadLoop() {
+    ALOGD("[Dvr] playback threadLoop start.");
+    std::lock_guard<std::mutex> lock(mDvrThreadLock);
+    mDvrThreadRunning = true;
+
+    while (mDvrThreadRunning) {
+        uint32_t efState = 0;
+        status_t status =
+                mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
+                                    &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
+        if (status != OK) {
+            ALOGD("[Dvr] wait for data ready on the playback FMQ");
+            continue;
+        }
+        // Our current implementation filter the data and write it into the filter FMQ immediately
+        // after the DATA_READY from the VTS/framework
+        if (!readPlaybackFMQ() || !startFilterDispatcher()) {
+            ALOGD("[Dvr] playback data failed to be filtered. Ending thread");
+            break;
+        }
+
+        maySendPlaybackStatusCallback();
+    }
+
+    mDvrThreadRunning = false;
+    ALOGD("[Dvr] playback thread ended.");
+}
+
+void Dvr::maySendPlaybackStatusCallback() {
+    std::lock_guard<std::mutex> lock(mPlaybackStatusLock);
+    int availableToRead = mDvrMQ->availableToRead();
+    int availableToWrite = mDvrMQ->availableToWrite();
+
+    PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
+                                                         mDvrSettings.playback().highThreshold,
+                                                         mDvrSettings.playback().lowThreshold);
+    if (mPlaybackStatus != newStatus) {
+        mCallback->onPlaybackStatus(newStatus);
+        mPlaybackStatus = newStatus;
+    }
+}
+
+PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                              uint32_t highThreshold, uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return PlaybackStatus::SPACE_FULL;
+    } else if (availableToRead > highThreshold) {
+        return PlaybackStatus::SPACE_ALMOST_FULL;
+    } else if (availableToRead < lowThreshold) {
+        return PlaybackStatus::SPACE_ALMOST_EMPTY;
+    } else if (availableToRead == 0) {
+        return PlaybackStatus::SPACE_EMPTY;
+    }
+    return mPlaybackStatus;
+}
+
+bool Dvr::readPlaybackFMQ() {
+    // Read playback data from the input FMQ
+    int size = mDvrMQ->availableToRead();
+    int playbackPacketSize = mDvrSettings.playback().packetSize;
+    vector<uint8_t> dataOutputBuffer;
+    dataOutputBuffer.resize(playbackPacketSize);
+
+    // Dispatch the packet to the PID matching filter output buffer
+    for (int i = 0; i < size / playbackPacketSize; i++) {
+        if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
+            return false;
+        }
+        startTpidFilter(dataOutputBuffer);
+    }
+
+    return true;
+}
+
+void Dvr::startTpidFilter(vector<uint8_t> data) {
+    std::map<uint32_t, sp<IFilter>>::iterator it;
+    for (it = mFilters.begin(); it != mFilters.end(); it++) {
+        uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
+        if (DEBUG_DVR) {
+            ALOGW("[Dvr] start ts filter pid: %d", pid);
+        }
+        if (pid == mDemux->getFilterTpid(it->first)) {
+            mDemux->updateFilterOutput(it->first, data);
+        }
+    }
+}
+
+bool Dvr::startFilterDispatcher() {
+    std::map<uint32_t, sp<IFilter>>::iterator it;
+
+    // Handle the output data per filter type
+    for (it = mFilters.begin(); it != mFilters.end(); it++) {
+        if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
new file mode 100644
index 0000000..fbb778c
--- /dev/null
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2019 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_TV_TUNER_V1_0_DVR_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_
+
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Demux.h"
+#include "Frontend.h"
+#include "Tuner.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using DvrMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux;
+class Filter;
+class Frontend;
+class Tuner;
+
+class Dvr : public IDvr {
+  public:
+    Dvr();
+
+    Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux);
+
+    ~Dvr();
+
+    virtual Return<void> getQueueDesc(getQueueDesc_cb _hidl_cb) override;
+
+    virtual Return<Result> configure(const DvrSettings& settings) override;
+
+    virtual Return<Result> attachFilter(const sp<IFilter>& filter) override;
+
+    virtual Return<Result> detachFilter(const sp<IFilter>& filter) override;
+
+    virtual Return<Result> start() override;
+
+    virtual Return<Result> stop() override;
+
+    virtual Return<Result> flush() override;
+
+    virtual Return<Result> close() override;
+
+    /**
+     * To create a DvrMQ and its Event Flag.
+     *
+     * Return false is any of the above processes fails.
+     */
+    bool createDvrMQ();
+
+  private:
+    // Demux service
+    sp<Demux> mDemux;
+
+    DvrType mType;
+    uint32_t mBufferSize;
+    sp<IDvrCallback> mCallback;
+    std::map<uint32_t, sp<IFilter>> mFilters;
+
+    void deleteEventFlag();
+    bool readDataFromMQ();
+    void maySendPlaybackStatusCallback();
+    void maySendRecordStatusCallback();
+    PlaybackStatus checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                             uint32_t highThreshold, uint32_t lowThreshold);
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     */
+    bool readPlaybackFMQ();
+    void startTpidFilter(vector<uint8_t> data);
+    bool startFilterDispatcher();
+    static void* __threadLoopPlayback(void* user);
+    static void* __threadLoopBroadcast(void* user);
+    void playbackThreadLoop();
+    void broadcastInputThreadLoop();
+
+    unique_ptr<DvrMQ> mDvrMQ;
+    EventFlag* mDvrEventFlag;
+    /**
+     * Demux callbacks used on filter events or IO buffer status
+     */
+    bool mDvrConfigured = false;
+    DvrSettings mDvrSettings;
+
+    // Thread handlers
+    pthread_t mDvrThread;
+    pthread_t mBroadcastInputThread;
+
+    // FMQ status local records
+    PlaybackStatus mPlaybackStatus;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    bool mDvrThreadRunning;
+    bool mBroadcastInputThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mPlaybackStatusLock;
+    std::mutex mBroadcastInputThreadLock;
+    std::mutex mDvrThreadLock;
+
+    const bool DEBUG_DVR = false;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_DVR_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
new file mode 100644
index 0000000..3d8a977
--- /dev/null
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -0,0 +1,456 @@
+/*
+ * Copyright (C) 2019 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 "android.hardware.tv.tuner@1.0-Filter"
+
+#include "Filter.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+#define WAIT_TIMEOUT 3000000000
+
+Filter::Filter() {}
+
+Filter::Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize,
+               const sp<IFilterCallback>& cb, sp<Demux> demux) {
+    mType = type;
+    mFilterId = filterId;
+    mBufferSize = bufferSize;
+    mCallback = cb;
+    mDemux = demux;
+}
+
+Filter::~Filter() {}
+
+Return<void> Filter::getId(getId_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, mFilterId);
+    return Void();
+}
+
+Return<Result> Filter::setDataSource(const sp<IFilter>& filter) {
+    ALOGV("%s", __FUNCTION__);
+
+    mDataSource = filter;
+    mIsDataSourceDemux = false;
+
+    return Result::SUCCESS;
+}
+
+Return<void> Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Filter::configure(const DemuxFilterSettings& settings) {
+    ALOGV("%s", __FUNCTION__);
+
+    mFilterSettings = settings;
+    switch (mType.mainType) {
+        case DemuxFilterMainType::TS:
+            mTpid = settings.ts().tpid;
+            break;
+        case DemuxFilterMainType::MMTP:
+            /*mmtpSettings*/
+            break;
+        case DemuxFilterMainType::IP:
+            /*ipSettings*/
+            break;
+        case DemuxFilterMainType::TLV:
+            /*tlvSettings*/
+            break;
+        case DemuxFilterMainType::ALP:
+            /*alpSettings*/
+            break;
+        default:
+            break;
+    }
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::start() {
+    ALOGV("%s", __FUNCTION__);
+
+    return startFilterLoop();
+}
+
+Return<Result> Filter::stop() {
+    ALOGV("%s", __FUNCTION__);
+
+    mFilterThreadRunning = false;
+
+    std::lock_guard<std::mutex> lock(mFilterThreadLock);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::flush() {
+    ALOGV("%s", __FUNCTION__);
+
+    // temp implementation to flush the FMQ
+    int size = mFilterMQ->availableToRead();
+    char* buffer = new char[size];
+    mFilterMQ->read((unsigned char*)&buffer[0], size);
+    delete[] buffer;
+    mFilterStatus = DemuxFilterStatus::DATA_READY;
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Filter::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return mDemux->removeFilter(mFilterId);
+}
+
+bool Filter::createFilterMQ() {
+    ALOGV("%s", __FUNCTION__);
+
+    // Create a synchronized FMQ that supports blocking read/write
+    std::unique_ptr<FilterMQ> tmpFilterMQ =
+            std::unique_ptr<FilterMQ>(new (std::nothrow) FilterMQ(mBufferSize, true));
+    if (!tmpFilterMQ->isValid()) {
+        ALOGW("Failed to create FMQ of filter with id: %d", mFilterId);
+        return false;
+    }
+
+    mFilterMQ = std::move(tmpFilterMQ);
+
+    if (EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterEventFlag) != OK) {
+        return false;
+    }
+
+    return true;
+}
+
+Result Filter::startFilterLoop() {
+    pthread_create(&mFilterThread, NULL, __threadLoopFilter, this);
+    pthread_setname_np(mFilterThread, "filter_waiting_loop");
+
+    return Result::SUCCESS;
+}
+
+void* Filter::__threadLoopFilter(void* user) {
+    Filter* const self = static_cast<Filter*>(user);
+    self->filterThreadLoop();
+    return 0;
+}
+
+void Filter::filterThreadLoop() {
+    ALOGD("[Filter] filter %d threadLoop start.", mFilterId);
+    std::lock_guard<std::mutex> lock(mFilterThreadLock);
+    mFilterThreadRunning = true;
+
+    // For the first time of filter output, implementation needs to send the filter
+    // Event Callback without waiting for the DATA_CONSUMED to init the process.
+    while (mFilterThreadRunning) {
+        if (mFilterEvent.events.size() == 0) {
+            ALOGD("[Filter] wait for filter data output.");
+            usleep(1000 * 1000);
+            continue;
+        }
+        // After successfully write, send a callback and wait for the read to be done
+        mCallback->onFilterEvent(mFilterEvent);
+        mFilterEvent.events.resize(0);
+        mFilterStatus = DemuxFilterStatus::DATA_READY;
+        mCallback->onFilterStatus(mFilterStatus);
+        break;
+    }
+
+    while (mFilterThreadRunning) {
+        uint32_t efState = 0;
+        // We do not wait for the last round of written data to be read to finish the thread
+        // because the VTS can verify the reading itself.
+        for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
+            while (mFilterThreadRunning) {
+                status_t status = mFilterEventFlag->wait(
+                        static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
+                        WAIT_TIMEOUT, true /* retry on spurious wake */);
+                if (status != OK) {
+                    ALOGD("[Filter] wait for data consumed");
+                    continue;
+                }
+                break;
+            }
+
+            if (mCallback == nullptr) {
+                ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId);
+                break;
+            }
+
+            maySendFilterStatusCallback();
+
+            while (mFilterThreadRunning) {
+                std::lock_guard<std::mutex> lock(mFilterEventLock);
+                if (mFilterEvent.events.size() == 0) {
+                    continue;
+                }
+                // After successfully write, send a callback and wait for the read to be done
+                mCallback->onFilterEvent(mFilterEvent);
+                mFilterEvent.events.resize(0);
+                break;
+            }
+            // We do not wait for the last read to be done
+            // VTS can verify the read result itself.
+            if (i == SECTION_WRITE_COUNT - 1) {
+                ALOGD("[Filter] filter %d writing done. Ending thread", mFilterId);
+                break;
+            }
+        }
+        mFilterThreadRunning = false;
+    }
+
+    ALOGD("[Filter] filter thread ended.");
+}
+
+void Filter::maySendFilterStatusCallback() {
+    std::lock_guard<std::mutex> lock(mFilterStatusLock);
+    int availableToRead = mFilterMQ->availableToRead();
+    int availableToWrite = mFilterMQ->availableToWrite();
+    int fmqSize = mFilterMQ->getQuantumCount();
+
+    DemuxFilterStatus newStatus = checkFilterStatusChange(
+            availableToWrite, availableToRead, ceil(fmqSize * 0.75), ceil(fmqSize * 0.25));
+    if (mFilterStatus != newStatus) {
+        mCallback->onFilterStatus(newStatus);
+        mFilterStatus = newStatus;
+    }
+}
+
+DemuxFilterStatus Filter::checkFilterStatusChange(uint32_t availableToWrite,
+                                                  uint32_t availableToRead, uint32_t highThreshold,
+                                                  uint32_t lowThreshold) {
+    if (availableToWrite == 0) {
+        return DemuxFilterStatus::OVERFLOW;
+    } else if (availableToRead > highThreshold) {
+        return DemuxFilterStatus::HIGH_WATER;
+    } else if (availableToRead < lowThreshold) {
+        return DemuxFilterStatus::LOW_WATER;
+    }
+    return mFilterStatus;
+}
+
+uint16_t Filter::getTpid() {
+    return mTpid;
+}
+
+void Filter::updateFilterOutput(vector<uint8_t> data) {
+    std::lock_guard<std::mutex> lock(mFilterOutputLock);
+    ALOGD("[Filter] handler output updated");
+    mFilterOutput.insert(mFilterOutput.end(), data.begin(), data.end());
+}
+
+Result Filter::startFilterHandler() {
+    std::lock_guard<std::mutex> lock(mFilterOutputLock);
+    switch (mType.mainType) {
+        case DemuxFilterMainType::TS:
+            switch (mType.subType.tsFilterType()) {
+                case DemuxTsFilterType::UNDEFINED:
+                    break;
+                case DemuxTsFilterType::SECTION:
+                    startSectionFilterHandler();
+                    break;
+                case DemuxTsFilterType::PES:
+                    startPesFilterHandler();
+                    break;
+                case DemuxTsFilterType::TS:
+                    startTsFilterHandler();
+                    break;
+                case DemuxTsFilterType::AUDIO:
+                case DemuxTsFilterType::VIDEO:
+                    startMediaFilterHandler();
+                    break;
+                case DemuxTsFilterType::PCR:
+                    startPcrFilterHandler();
+                    break;
+                case DemuxTsFilterType::RECORD:
+                    startRecordFilterHandler();
+                    break;
+            }
+            break;
+        case DemuxFilterMainType::MMTP:
+            /*mmtpSettings*/
+            break;
+        case DemuxFilterMainType::IP:
+            /*ipSettings*/
+            break;
+        case DemuxFilterMainType::TLV:
+            /*tlvSettings*/
+            break;
+        case DemuxFilterMainType::ALP:
+            /*alpSettings*/
+            break;
+        default:
+            break;
+    }
+    return Result::SUCCESS;
+}
+
+Result Filter::startSectionFilterHandler() {
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+    if (!writeSectionsAndCreateEvent(mFilterOutput)) {
+        ALOGD("[Filter] filter %d fails to write into FMQ. Ending thread", mFilterId);
+        return Result::UNKNOWN_ERROR;
+    }
+
+    mFilterOutput.clear();
+
+    return Result::SUCCESS;
+}
+
+Result Filter::startPesFilterHandler() {
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+
+    for (int i = 0; i < mFilterOutput.size(); i += 188) {
+        if (mPesSizeLeft == 0) {
+            uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
+                              mFilterOutput[i + 6];
+            ALOGD("[Filter] prefix %d", prefix);
+            if (prefix == 0x000001) {
+                // TODO handle mulptiple Pes filters
+                mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+                mPesSizeLeft += 6;
+                ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+            } else {
+                continue;
+            }
+        }
+
+        int endPoint = min(184, mPesSizeLeft);
+        // append data and check size
+        vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
+        vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
+        mPesOutput.insert(mPesOutput.end(), first, last);
+        // size does not match then continue
+        mPesSizeLeft -= endPoint;
+        ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+        if (mPesSizeLeft > 0) {
+            continue;
+        }
+        // size match then create event
+        if (!writeDataToFilterMQ(mPesOutput)) {
+            ALOGD("[Filter] pes data write failed");
+            mFilterOutput.clear();
+            return Result::INVALID_STATE;
+        }
+        maySendFilterStatusCallback();
+        DemuxFilterPesEvent pesEvent;
+        pesEvent = {
+                // temp dump meta data
+                .streamId = mPesOutput[3],
+                .dataLength = static_cast<uint16_t>(mPesOutput.size()),
+        };
+        ALOGD("[Filter] assembled pes data length %d", pesEvent.dataLength);
+
+        int size = mFilterEvent.events.size();
+        mFilterEvent.events.resize(size + 1);
+        mFilterEvent.events[size].pes(pesEvent);
+        mPesOutput.clear();
+    }
+
+    mFilterOutput.clear();
+
+    return Result::SUCCESS;
+}
+
+Result Filter::startTsFilterHandler() {
+    // TODO handle starting TS filter
+    return Result::SUCCESS;
+}
+
+Result Filter::startMediaFilterHandler() {
+    DemuxFilterMediaEvent mediaEvent;
+    mediaEvent = {
+            // temp dump meta data
+            .pts = 0,
+            .dataLength = 530,
+            .avMemory = nullptr,
+            .isSecureMemory = false,
+    };
+    mFilterEvent.events.resize(1);
+    mFilterEvent.events[0].media(mediaEvent);
+
+    mFilterOutput.clear();
+    // TODO handle write FQM for media stream
+    return Result::SUCCESS;
+}
+
+Result Filter::startRecordFilterHandler() {
+    DemuxFilterTsRecordEvent tsRecordEvent;
+    tsRecordEvent.pid.tPid(0);
+    tsRecordEvent.indexMask.tsIndexMask(0x01);
+    mFilterEvent.events.resize(1);
+    mFilterEvent.events[0].tsRecord(tsRecordEvent);
+
+    mFilterOutput.clear();
+    return Result::SUCCESS;
+}
+
+Result Filter::startPcrFilterHandler() {
+    // TODO handle starting PCR filter
+    return Result::SUCCESS;
+}
+
+bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) {
+    // TODO check how many sections has been read
+    ALOGD("[Filter] section hander");
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (!writeDataToFilterMQ(data)) {
+        return false;
+    }
+    int size = mFilterEvent.events.size();
+    mFilterEvent.events.resize(size + 1);
+    DemuxFilterSectionEvent secEvent;
+    secEvent = {
+            // temp dump meta data
+            .tableId = 0,
+            .version = 1,
+            .sectionNum = 1,
+            .dataLength = static_cast<uint16_t>(data.size()),
+    };
+    mFilterEvent.events[size].section(secEvent);
+    return true;
+}
+
+bool Filter::writeDataToFilterMQ(const std::vector<uint8_t>& data) {
+    std::lock_guard<std::mutex> lock(mWriteLock);
+    if (mFilterMQ->write(data.data(), data.size())) {
+        return true;
+    }
+    return false;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
new file mode 100644
index 0000000..21d4297
--- /dev/null
+++ b/tv/tuner/1.0/default/Filter.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2019 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_TV_TUNER_V1_0_FILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_
+
+#include <android/hardware/tv/tuner/1.0/IFilter.h>
+#include <fmq/MessageQueue.h>
+#include <math.h>
+#include <set>
+#include "Demux.h"
+#include "Frontend.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::EventFlag;
+using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux;
+
+class Filter : public IFilter {
+  public:
+    Filter();
+
+    Filter(DemuxFilterType type, uint32_t filterId, uint32_t bufferSize,
+           const sp<IFilterCallback>& cb, sp<Demux> demux);
+
+    ~Filter();
+
+    virtual Return<void> getId(getId_cb _hidl_cb) override;
+
+    virtual Return<Result> setDataSource(const sp<IFilter>& filter) override;
+
+    virtual Return<void> getQueueDesc(getQueueDesc_cb _hidl_cb) override;
+
+    virtual Return<Result> configure(const DemuxFilterSettings& settings) override;
+
+    virtual Return<Result> start() override;
+
+    virtual Return<Result> stop() override;
+
+    virtual Return<Result> flush() override;
+
+    virtual Return<Result> close() override;
+
+    /**
+     * To create a FilterMQ and its Event Flag.
+     *
+     * Return false is any of the above processes fails.
+     */
+    bool createFilterMQ();
+    uint16_t getTpid();
+    void updateFilterOutput(vector<uint8_t> data);
+    Result startFilterHandler();
+
+  private:
+    // Tuner service
+    sp<Demux> mDemux;
+    /**
+     * Filter callbacks used on filter events or FMQ status
+     */
+    sp<IFilterCallback> mCallback;
+
+    uint32_t mFilterId;
+    uint32_t mBufferSize;
+    DemuxFilterType mType;
+    DemuxFilterSettings mFilterSettings;
+
+    uint16_t mTpid;
+    sp<IFilter> mDataSource;
+    bool mIsDataSourceDemux = true;
+    vector<uint8_t> mFilterOutput;
+    unique_ptr<FilterMQ> mFilterMQ;
+    EventFlag* mFilterEventFlag;
+    DemuxFilterEvent mFilterEvent;
+
+    // Thread handlers
+    pthread_t mFilterThread;
+
+    // FMQ status local records
+    DemuxFilterStatus mFilterStatus;
+    /**
+     * If a specific filter's writing loop is still running
+     */
+    bool mFilterThreadRunning;
+    bool mKeepFetchingDataFromFrontend;
+
+    /**
+     * How many times a filter should write
+     * TODO make this dynamic/random/can take as a parameter
+     */
+    const uint16_t SECTION_WRITE_COUNT = 10;
+
+    /**
+     * Filter handlers to handle the data filtering.
+     * They are also responsible to write the filtered output into the filter FMQ
+     * and update the filterEvent bound with the same filterId.
+     */
+    Result startSectionFilterHandler();
+    Result startPesFilterHandler();
+    Result startTsFilterHandler();
+    Result startMediaFilterHandler();
+    Result startRecordFilterHandler();
+    Result startPcrFilterHandler();
+    Result startFilterLoop();
+
+    void deleteEventFlag();
+    bool writeDataToFilterMQ(const std::vector<uint8_t>& data);
+    bool readDataFromMQ();
+    bool writeSectionsAndCreateEvent(vector<uint8_t> data);
+    void maySendFilterStatusCallback();
+    DemuxFilterStatus checkFilterStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
+                                              uint32_t highThreshold, uint32_t lowThreshold);
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     */
+    void startTsFilter(vector<uint8_t> data);
+    bool startFilterDispatcher();
+    static void* __threadLoopFilter(void* user);
+    void filterThreadLoop();
+
+    /**
+     * Lock to protect writes to the FMQs
+     */
+    std::mutex mWriteLock;
+    /**
+     * Lock to protect writes to the filter event
+     */
+    // TODO make each filter separate event lock
+    std::mutex mFilterEventLock;
+    /**
+     * Lock to protect writes to the input status
+     */
+    std::mutex mFilterStatusLock;
+    std::mutex mFilterThreadLock;
+    std::mutex mFilterOutputLock;
+
+    // temp handle single PES filter
+    // TODO handle mulptiple Pes filters
+    int mPesSizeLeft = 0;
+    vector<uint8_t> mPesOutput;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_FILTER_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
index 07fa7b9..eab43a3 100644
--- a/tv/tuner/1.0/default/Frontend.h
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -75,7 +75,7 @@
     FrontendType mType = FrontendType::UNDEFINED;
     FrontendId mId = 0;
 
-    const string FRONTEND_STREAM_FILE = "/vendor/etc/test1.ts";
+    const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts";
     string mSourceStreamFile;
     std::ifstream mFrontendData;
 };
diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp
index 1446f7f..51931d6 100644
--- a/tv/tuner/1.0/default/Lnb.cpp
+++ b/tv/tuner/1.0/default/Lnb.cpp
@@ -30,19 +30,25 @@
 
 Lnb::~Lnb() {}
 
-Return<Result> Lnb::setVoltage(FrontendLnbVoltage /* voltage */) {
+Return<Result> Lnb::setCallback(const sp<ILnbCallback>& /* callback */) {
     ALOGV("%s", __FUNCTION__);
 
     return Result::SUCCESS;
 }
 
-Return<Result> Lnb::setTone(FrontendLnbTone /* tone */) {
+Return<Result> Lnb::setVoltage(LnbVoltage /* voltage */) {
     ALOGV("%s", __FUNCTION__);
 
     return Result::SUCCESS;
 }
 
-Return<Result> Lnb::setSatellitePosition(FrontendLnbPosition /* position */) {
+Return<Result> Lnb::setTone(LnbTone /* tone */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setSatellitePosition(LnbPosition /* position */) {
     ALOGV("%s", __FUNCTION__);
 
     return Result::SUCCESS;
diff --git a/tv/tuner/1.0/default/Lnb.h b/tv/tuner/1.0/default/Lnb.h
index 4c251f7..f285cb9 100644
--- a/tv/tuner/1.0/default/Lnb.h
+++ b/tv/tuner/1.0/default/Lnb.h
@@ -29,20 +29,23 @@
 namespace V1_0 {
 namespace implementation {
 
-using ::android::hardware::tv::tuner::V1_0::FrontendLnbPosition;
-using ::android::hardware::tv::tuner::V1_0::FrontendLnbTone;
-using ::android::hardware::tv::tuner::V1_0::FrontendLnbVoltage;
+using ::android::hardware::tv::tuner::V1_0::ILnbCallback;
+using ::android::hardware::tv::tuner::V1_0::LnbPosition;
+using ::android::hardware::tv::tuner::V1_0::LnbTone;
+using ::android::hardware::tv::tuner::V1_0::LnbVoltage;
 using ::android::hardware::tv::tuner::V1_0::Result;
 
 class Lnb : public ILnb {
   public:
     Lnb();
 
-    virtual Return<Result> setVoltage(FrontendLnbVoltage voltage) override;
+    virtual Return<Result> setCallback(const sp<ILnbCallback>& callback) override;
 
-    virtual Return<Result> setTone(FrontendLnbTone tone) override;
+    virtual Return<Result> setVoltage(LnbVoltage voltage) override;
 
-    virtual Return<Result> setSatellitePosition(FrontendLnbPosition position) override;
+    virtual Return<Result> setTone(LnbTone tone) override;
+
+    virtual Return<Result> setSatellitePosition(LnbPosition position) override;
 
     virtual Return<Result> sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override;
 
diff --git a/tv/tuner/1.0/default/TimeFilter.cpp b/tv/tuner/1.0/default/TimeFilter.cpp
new file mode 100644
index 0000000..0b1fd1c
--- /dev/null
+++ b/tv/tuner/1.0/default/TimeFilter.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 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 "android.hardware.tv.tuner@1.0-TimeFilter"
+
+#include "TimeFilter.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+TimeFilter::TimeFilter() {}
+
+TimeFilter::TimeFilter(sp<Demux> demux) {
+    mDemux = demux;
+}
+
+TimeFilter::~TimeFilter() {}
+
+Return<Result> TimeFilter::setTimeStamp(uint64_t /* timeStamp */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> TimeFilter::clearTimeStamp() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<void> TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t timeStamp = 0;
+
+    _hidl_cb(Result::SUCCESS, timeStamp);
+    return Void();
+}
+
+Return<void> TimeFilter::getSourceTime(getSourceTime_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    uint64_t time = 0;
+
+    _hidl_cb(Result::SUCCESS, time);
+    return Void();
+}
+
+Return<Result> TimeFilter::close() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/TimeFilter.h b/tv/tuner/1.0/default/TimeFilter.h
new file mode 100644
index 0000000..7131df8
--- /dev/null
+++ b/tv/tuner/1.0/default/TimeFilter.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2019 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_TV_TUNER_V1_0_TIMEFILTER_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_
+
+#include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
+#include "Demux.h"
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::android::hardware::tv::tuner::V1_0::IFilterCallback;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
+
+class Demux;
+
+class TimeFilter : public ITimeFilter {
+  public:
+    TimeFilter();
+
+    TimeFilter(sp<Demux> demux);
+
+    ~TimeFilter();
+
+    virtual Return<Result> setTimeStamp(uint64_t timeStamp) override;
+
+    virtual Return<Result> clearTimeStamp() override;
+
+    virtual Return<void> getTimeStamp(getTimeStamp_cb _hidl_cb) override;
+
+    virtual Return<void> getSourceTime(getSourceTime_cb _hidl_cb) override;
+
+    virtual Return<Result> close() override;
+
+  private:
+    sp<Demux> mDemux;
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_TIMEFILTER_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 897818b..a0cf0d9 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -17,6 +17,7 @@
 package android.hardware.tv.tuner@1.0;
 
 import android.hidl.safe_union@1.0;
+import android.hidl.safe_union@1.0::Monostate;
 
 @export
 enum Result : int32_t {
@@ -41,9 +42,13 @@
 enum FrontendType : uint32_t {
     UNDEFINED = 0,
     ANALOG,
-    /* Advanced Television Systems Committee (ATSC) Standard A/72. */
+    /**
+     * Advanced Television Systems Committee (ATSC) Standard A/72.
+     */
     ATSC,
-    /* Advanced Television Systems Committee (ATSC 3.0) Standard A/300. */
+    /**
+     * Advanced Television Systems Committee (ATSC 3.0) Standard A/300.
+     */
     ATSC3,
     /**
      * Digital Video Broadcasting - Cable
@@ -62,15 +67,18 @@
      * ETSI EN 302 755 V1.4.1.
      */
     DVBT,
-    /* Integrated Services Digital Broadcasting-Satellite (ISDB-S)
+    /**
+     * Integrated Services Digital Broadcasting-Satellite (ISDB-S)
      * ARIB STD-B20 is technical document of ISDB-S.
      */
     ISDBS,
-    /* Integrated Services Digital Broadcasting-Satellite (ISDB-S)
+    /**
+     * Integrated Services Digital Broadcasting-Satellite (ISDB-S)
      * ARIB STD-B44 is technical document of ISDB-S3.
      */
     ISDBS3,
-    /* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD)
+    /**
+     * Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD)
      * ABNT NBR 15603 is technical document of ISDB-T.
      */
     ISDBT,
@@ -82,79 +90,153 @@
  */
 @export
 enum FrontendInnerFec : uint64_t {
-    /* Not defined */
+    /**
+     * Not defined
+     */
     FEC_UNDEFINED = 0,
-    /* hardware is able to detect and set FEC automatically */
+    /**
+     * hardware is able to detect and set FEC automatically
+     */
     AUTO = 1 << 0,
-    /* 1/2 conv. code rate */
+    /**
+     * 1/2 conv. code rate
+     */
     FEC_1_2 = 1 << 1,
-    /* 1/3 conv. code rate */
+    /**
+     * 1/3 conv. code rate
+     */
     FEC_1_3 = 1 << 2,
-    /* 1/4 conv. code rate */
+    /**
+     * 1/4 conv. code rate
+     */
     FEC_1_4 = 1 << 3,
-    /* 1/5 conv. code rate */
+    /**
+     * 1/5 conv. code rate
+     */
     FEC_1_5 = 1 << 4,
-    /* 2/3 conv. code rate */
+    /**
+     * 2/3 conv. code rate
+     */
     FEC_2_3 = 1 << 5,
-    /* 2/5 conv. code rate */
+    /**
+     * 2/5 conv. code rate
+     */
     FEC_2_5 = 1 << 6,
-    /* 2/9 conv. code rate */
+    /**
+     * 2/9 conv. code rate
+     */
     FEC_2_9 = 1 << 7,
-    /* 3/4 conv. code rate */
+    /**
+     * 3/4 conv. code rate
+     */
     FEC_3_4 = 1 << 8,
-    /* 3/5 conv. code rate */
+    /**
+     * 3/5 conv. code rate
+     */
     FEC_3_5 = 1 << 9,
-    /* 4/5 conv. code rate */
+    /**
+     * 4/5 conv. code rate
+     */
     FEC_4_5 = 1 << 10,
-    /* 4/15 conv. code rate */
+    /**
+     * 4/15 conv. code rate
+     */
     FEC_4_15 = 1 << 11,
-    /* 5/6 conv. code rate */
+    /**
+     * 5/6 conv. code rate
+     */
     FEC_5_6 = 1 << 12,
-    /* 5/9 conv. code rate */
+    /**
+     * 5/9 conv. code rate
+     */
     FEC_5_9 = 1 << 13,
-    /* 6/7 conv. code rate */
+    /**
+     * 6/7 conv. code rate
+     */
     FEC_6_7 = 1 << 14,
-    /* 7/8 conv. code rate */
+    /**
+     * 7/8 conv. code rate
+     */
     FEC_7_8 = 1 << 15,
-    /* 7/9 conv. code rate */
+    /**
+     * 7/9 conv. code rate
+     */
     FEC_7_9 = 1 << 16,
-    /* 7/15 conv. code rate */
+    /**
+     * 7/15 conv. code rate
+     */
     FEC_7_15 = 1 << 17,
-    /* 8/9 conv. code rate */
+    /**
+     * 8/9 conv. code rate
+     */
     FEC_8_9 = 1 << 18,
-    /* 8/15 conv. code rate */
+    /**
+     * 8/15 conv. code rate
+     */
     FEC_8_15 = 1 << 19,
-    /* 9/10 conv. code rate */
+    /**
+     * 9/10 conv. code rate
+     */
     FEC_9_10 = 1 << 20,
-    /* 9/20 conv. code rate */
+    /**
+     * 9/20 conv. code rate
+     */
     FEC_9_20 = 1 << 21,
-    /* 11/15 conv. code rate */
+    /**
+     * 11/15 conv. code rate
+     */
     FEC_11_15 = 1 << 22,
-    /* 11/20 conv. code rate */
+    /**
+     * 11/20 conv. code rate
+     */
     FEC_11_20 = 1 << 23,
-    /* 11/45 conv. code rate */
+    /**
+     * 11/45 conv. code rate
+     */
     FEC_11_45 = 1 << 24,
-    /* 13/18 conv. code rate */
+    /**
+     * 13/18 conv. code rate
+     */
     FEC_13_18 = 1 << 25,
-    /* 13/45 conv. code rate */
+    /**
+     * 13/45 conv. code rate
+     */
     FEC_13_45 = 1 << 26,
-    /* 14/45 conv. code rate */
+    /**
+     * 14/45 conv. code rate
+     */
     FEC_14_45 = 1 << 27,
-    /* 23/36 conv. code rate */
+    /**
+     * 23/36 conv. code rate
+     */
     FEC_23_36 = 1 << 28,
-    /* 25/36 conv. code rate */
+    /**
+     * 25/36 conv. code rate
+     */
     FEC_25_36 = 1 << 29,
-    /* 26/45 conv. code rate */
+    /**
+     * 26/45 conv. code rate
+     */
     FEC_26_45 = 1 << 30,
-    /* 28/45 conv. code rate */
+    /**
+     * 28/45 conv. code rate
+     */
     FEC_28_45 = 1 << 31,
-    /* 29/45 conv. code rate */
+    /**
+     * 29/45 conv. code rate
+     */
     FEC_29_45 = 1 << 32,
-    /* 31/45 conv. code rate */
+    /**
+     * 31/45 conv. code rate
+     */
     FEC_31_45 = 1 << 33,
-    /* 32/45 conv. code rate */
+    /**
+     * 32/45 conv. code rate
+     */
     FEC_32_45 = 1 << 34,
-    /* 77/90 conv. code rate */
+    /**
+     * 77/90 conv. code rate
+     */
     FEC_77_90 = 1 << 35,
 };
 
@@ -164,9 +246,11 @@
 @export
 enum FrontendAtscModulation : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set modulation automatically */
-    AUTO      = 1 << 0,
-    MOD_8VSB  = 1 << 2,
+    /**
+     * hardware is able to detect and set modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_8VSB = 1 << 2,
     MOD_16VSB = 1 << 3,
 };
 
@@ -174,8 +258,11 @@
  *  Signal Setting for ATSC Frontend.
  */
 struct FrontendAtscSettings {
-    /** Signal frequencey in Herhz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
+
     FrontendAtscModulation modulation;
 };
 
@@ -183,7 +270,9 @@
  *  Capabilities for ATSC Frontend.
  */
 struct FrontendAtscCapabilities {
-    /** Modulation capability */
+    /**
+     * Modulation capability
+     */
     bitfield<FrontendAtscModulation> modulationCap;
 };
 
@@ -193,12 +282,14 @@
 @export
 enum FrontendAtsc3Modulation : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set modulation automatically */
-    AUTO        = 1 << 0,
-    MOD_QPSK    = 1 << 1,
-    MOD_16QAM   = 1 << 2,
-    MOD_64QAM   = 1 << 3,
-    MOD_256QAM  = 1 << 4,
+    /**
+     * hardware is able to detect and set modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_QPSK = 1 << 1,
+    MOD_16QAM = 1 << 2,
+    MOD_64QAM = 1 << 3,
+    MOD_256QAM = 1 << 4,
     MOD_1024QAM = 1 << 5,
     MOD_4096QAM = 1 << 6,
 };
@@ -209,7 +300,9 @@
 @export
 enum FrontendAtsc3Bandwidth : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set bandwidth automatically */
+    /**
+     * hardware is able to detect and set bandwidth automatically
+     */
     AUTO = 1 << 0,
     BANDWIDTH_6MHZ = 1 << 1,
     BANDWIDTH_7MHZ = 1 << 2,
@@ -222,10 +315,12 @@
 @export
 enum FrontendAtsc3TimeInterleaveMode : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set TimeInterleaveMode automatically */
+    /**
+     * hardware is able to detect and set TimeInterleaveMode automatically
+     */
     AUTO = 1 << 0,
-    CTI  = 1 << 1,
-    HTI  = 1 << 2,
+    CTI = 1 << 1,
+    HTI = 1 << 2,
 };
 
 /**
@@ -234,20 +329,22 @@
 @export
 enum FrontendAtsc3CodeRate : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Coderate automatically */
-    AUTO     = 1 << 0,
-    CODERATE_2_15      = 1 << 1,
-    CODERATE_3_15      = 1 << 2,
-    CODERATE_4_15      = 1 << 3,
-    CODERATE_5_15      = 1 << 4,
-    CODERATE_6_15      = 1 << 5,
-    CODERATE_7_15      = 1 << 6,
-    CODERATE_8_15      = 1 << 7,
-    CODERATE_9_15      = 1 << 8,
-    CODERATE_10_15     = 1 << 9,
-    CODERATE_11_15     = 1 << 10,
-    CODERATE_12_15     = 1 << 11,
-    CODERATE_13_15     = 1 << 12,
+    /**
+     * hardware is able to detect and set Coderate automatically
+     */
+    AUTO = 1 << 0,
+    CODERATE_2_15 = 1 << 1,
+    CODERATE_3_15 = 1 << 2,
+    CODERATE_4_15 = 1 << 3,
+    CODERATE_5_15 = 1 << 4,
+    CODERATE_6_15 = 1 << 5,
+    CODERATE_7_15 = 1 << 6,
+    CODERATE_8_15 = 1 << 7,
+    CODERATE_9_15 = 1 << 8,
+    CODERATE_10_15 = 1 << 9,
+    CODERATE_11_15 = 1 << 10,
+    CODERATE_12_15 = 1 << 11,
+    CODERATE_13_15 = 1 << 12,
 };
 
 /**
@@ -256,14 +353,16 @@
 @export
 enum FrontendAtsc3Fec : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set FEC automatically */
-    AUTO     = 1 << 0,
+    /**
+     * hardware is able to detect and set FEC automatically
+     */
+    AUTO = 1 << 0,
     BCH_LDPC_16K = 1 << 1,
     BCH_LDPC_64K = 1 << 2,
     CRC_LDPC_16K = 1 << 3,
     CRC_LDPC_64K = 1 << 4,
-    LDPC_16K     = 1 << 5,
-    LDPC_64K     = 1 << 6,
+    LDPC_16K = 1 << 5,
+    LDPC_64K = 1 << 6,
 };
 
 /**
@@ -271,12 +370,18 @@
  */
 @export
 enum FrontendAtsc3DemodOutputFormat : uint8_t {
-    /** Dummy. Scan uses this. */
+    /**
+     * Dummy. Scan uses this.
+     */
     UNDEFINED = 0,
-    /** ALP format. Typically used in US region. */
+    /**
+     * ALP format. Typically used in US region.
+     */
     ATSC3_LINKLAYER_PACKET = 1 << 0,
-    /** BaseBand packet format. Typically used in Korea region. */
-    BASEBAND_PACKET        = 1 << 1,
+    /**
+     * BaseBand packet format. Typically used in Korea region.
+     */
+    BASEBAND_PACKET = 1 << 1,
 };
 
 /**
@@ -284,9 +389,13 @@
  */
 struct FrontendAtsc3PlpSettings {
     uint8_t plpId;
+
     FrontendAtsc3Modulation modulation;
+
     FrontendAtsc3TimeInterleaveMode interleaveMode;
+
     FrontendAtsc3CodeRate codeRate;
+
     FrontendAtsc3Fec fec;
 };
 
@@ -294,11 +403,18 @@
  *  Signal Settings for an ATSC3 Frontend.
  */
 struct FrontendAtsc3Settings {
-    /** Signal frequency in Hertz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
-    /** Bandwidth of tuning band. */
+
+    /**
+     * Bandwidth of tuning band.
+     */
     FrontendAtsc3Bandwidth bandwidth;
+
     FrontendAtsc3DemodOutputFormat demodOutputFormat;
+
     vec<FrontendAtsc3PlpSettings> plpSettings;
 };
 
@@ -306,17 +422,34 @@
  *  Capabilities for ATSC3 Frontend.
  */
 struct FrontendAtsc3Capabilities {
-    /** Bandwidth capability */
+    /**
+     * Bandwidth capability
+     */
     bitfield<FrontendAtsc3Bandwidth> bandwidthCap;
-    /** Modulation capability */
+
+    /**
+     * Modulation capability
+     */
     bitfield<FrontendAtsc3Modulation> modulationCap;
-    /** TimeInterleaveMode capability */
+
+    /**
+     * TimeInterleaveMode capability
+     */
     bitfield<FrontendAtsc3TimeInterleaveMode> timeInterleaveModeCap;
-    /** CodeRate capability */
+
+    /**
+     * CodeRate capability
+     */
     bitfield<FrontendAtsc3CodeRate> codeRateCap;
-    /** FEC capability */
+
+    /**
+     * FEC capability
+     */
     bitfield<FrontendAtsc3Fec> fecCap;
-    /** Demodulator Output Format capability */
+
+    /**
+     * Demodulator Output Format capability
+     */
     bitfield<FrontendAtsc3DemodOutputFormat> demodOutputFormatCap;
 };
 
@@ -326,7 +459,9 @@
 @export
 enum FrontendDvbsModulation : int32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Modulation automatically */
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
     AUTO = 1 << 0,
     MOD_QPSK = 1 << 1,
     MOD_8PSK = 1 << 2,
@@ -340,7 +475,9 @@
     MOD_64APSK = 1 << 10,
     MOD_128APSK = 1 << 11,
     MOD_256APSK = 1 << 12,
-    /** Reserved for Proprietary modulation */
+    /**
+     * Reserved for Proprietary modulation
+     */
     MOD_RESERVED = 1 << 13,
 };
 
@@ -374,10 +511,17 @@
  */
 struct FrontendDvbsCodeRate {
     FrontendInnerFec fec;
+
     bool isLinear;
-    /* true if enable short frame */
+
+    /**
+     * true if enable short frame
+     */
     bool isShortFrames;
-    /* bits number in 1000 symbol. 0 if use the default. */
+
+    /**
+     * bits number in 1000 symbol. 0 if use the default.
+     */
     uint32_t bitsPer1000Symbol;
 };
 
@@ -396,15 +540,26 @@
  *  Signal Settings for an DVBS Frontend.
  */
 struct FrontendDvbsSettings {
-    /** Signal frequency in Hertz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
+
     FrontendDvbsModulation modulation;
+
     FrontendDvbsCodeRate coderate;
-    /** Symbols per second */
+
+    /**
+     * Symbols per second
+     */
     uint32_t symbolRate;
+
     FrontendDvbsRolloff rolloff;
+
     FrontendDvbsPilot pilot;
+
     uint32_t inputStreamId;
+
     FrontendDvbsStandard standard;
 };
 
@@ -413,8 +568,10 @@
  */
 struct FrontendDvbsCapabilities {
     bitfield<FrontendDvbsModulation> modulationCap;
+
     bitfield<FrontendInnerFec> innerfecCap;
-    bitfield<FrontendDvbsStandard>  standard;
+
+    bitfield<FrontendDvbsStandard> standard;
 };
 
 /**
@@ -423,7 +580,9 @@
 @export
 enum FrontendDvbcModulation : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Modulation automatically */
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
     AUTO = 1 << 0,
     MOD_16QAM = 1 << 1,
     MOD_32QAM = 1 << 2,
@@ -467,14 +626,24 @@
  *  Signal Settings for an DVBC Frontend.
  */
 struct FrontendDvbcSettings {
-    /** Signal frequency in Hertz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
+
     FrontendDvbcModulation modulation;
+
     FrontendInnerFec fec;
-    /** Symbols per second */
+
+    /**
+     * Symbols per second
+     */
     uint32_t symbolRate;
+
     FrontendDvbcOuterFec outerFec;
+
     FrontendDvbcAnnex annex;
+
     FrontendDvbcSpectralInversion spectralInversion;
 };
 
@@ -483,7 +652,9 @@
  */
 struct FrontendDvbcCapabilities {
     bitfield<FrontendDvbcModulation> modulationCap;
+
     bitfield<FrontendInnerFec> fecCap;
+
     bitfield<FrontendDvbcAnnex> annexCap;
 };
 
@@ -493,7 +664,9 @@
 @export
 enum FrontendDvbtBandwidth : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Bandwidth automatically */
+    /**
+     * hardware is able to detect and set Bandwidth automatically
+     */
     AUTO = 1 << 0,
     BANDWIDTH_8MHZ = 1 << 1,
     BANDWIDTH_7MHZ = 1 << 2,
@@ -509,7 +682,9 @@
 @export
 enum FrontendDvbtConstellation : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Constellation automatically */
+    /**
+     * hardware is able to detect and set Constellation automatically
+     */
     AUTO = 1 << 0,
     CONSTELLATION_QPSK = 1 << 1,
     CONSTELLATION_16QAM = 1 << 2,
@@ -523,7 +698,9 @@
 @export
 enum FrontendDvbtHierarchy : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Hierarchy automatically */
+    /**
+     * hardware is able to detect and set Hierarchy automatically
+     */
     AUTO = 1 << 0,
     HIERARCHY_NON_NATIVE = 1 << 1,
     HIERARCHY_1_NATIVE = 1 << 2,
@@ -541,7 +718,9 @@
 @export
 enum FrontendDvbtCoderate : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Hierarchy automatically */
+    /**
+     * hardware is able to detect and set Hierarchy automatically
+     */
     AUTO = 1 << 0,
     CODERATE_1_2 = 1 << 1,
     CODERATE_2_3 = 1 << 2,
@@ -560,7 +739,9 @@
 @export
 enum FrontendDvbtGuardInterval : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Guard Interval automatically */
+    /**
+     * hardware is able to detect and set Guard Interval automatically
+     */
     AUTO = 1 << 0,
     INTERVAL_1_32 = 1 << 1,
     INTERVAL_1_16 = 1 << 2,
@@ -577,7 +758,9 @@
 @export
 enum FrontendDvbtTransmissionMode : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Transmission Mode automatically */
+    /**
+     * hardware is able to detect and set Transmission Mode automatically
+     */
     AUTO = 1 << 0,
     MODE_2K = 1 << 1,
     MODE_8K = 1 << 2,
@@ -607,27 +790,50 @@
 };
 
 /**
- *  Signal Setting for DVBT Frontend.
+ *  Signal Settings for DVBT Frontend.
  */
 struct FrontendDvbtSettings {
-    /** Signal frequencey in Herhz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
+
     FrontendDvbtTransmissionMode transmissionMode;
+
     FrontendDvbtBandwidth bandwidth;
+
     FrontendDvbtConstellation constellation;
+
     FrontendDvbtHierarchy hierarchy;
-    /** Code Rate for High Priority level */
+
+    /**
+     * Code Rate for High Priority level
+     */
     FrontendDvbtCoderate hpCoderate;
-    /** Code Rate for Low Priority level */
+
+    /**
+     * Code Rate for Low Priority level
+     */
     FrontendDvbtCoderate lpCoderate;
+
     FrontendDvbtGuardInterval guardInterval;
+
     bool isHighPriority;
+
     FrontendDvbtStandard standard;
+
     bool isMiso;
+
     FrontendDvbtPlpMode plpMode;
-    /** Physical Layer Pipe (PLP) Id */
+
+    /**
+     * Physical Layer Pipe (PLP) Id
+     */
     uint8_t plpId;
-    /** Group Id for Physical Layer Pipe (PLP) */
+
+    /**
+     * Group Id for Physical Layer Pipe (PLP)
+     */
     uint8_t plpGroupId;
 };
 
@@ -636,12 +842,19 @@
  */
 struct FrontendDvbtCapabilities {
     bitfield<FrontendDvbtTransmissionMode> transmissionModeCap;
+
     bitfield<FrontendDvbtBandwidth> bandwidthCap;
+
     bitfield<FrontendDvbtConstellation> constellationCap;
+
     bitfield<FrontendDvbtCoderate> coderateCap;
+
     bitfield<FrontendDvbtHierarchy> hierarchyCap;
+
     bitfield<FrontendDvbtGuardInterval> guardIntervalCap;
+
     bool isT2Supported;
+
     bool isMisoSupported;
 };
 
@@ -660,11 +873,13 @@
 @export
 enum FrontendIsdbsModulation : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Modulation automatically */
-    AUTO      = 1 << 0,
-    MOD_BPSK      = 1 << 1,
-    MOD_QPSK      = 1 << 2,
-    MOD_TC8PSK    = 1 << 3,
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
+    AUTO = 1 << 0,
+    MOD_BPSK = 1 << 1,
+    MOD_QPSK = 1 << 2,
+    MOD_TC8PSK = 1 << 3,
 };
 
 /**
@@ -673,13 +888,15 @@
 @export
 enum FrontendIsdbsCoderate : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Code Rate automatically */
-    AUTO      = 1 << 0,
-    CODERATE_1_2       = 1 << 1,
-    CODERATE_2_3       = 1 << 2,
-    CODERATE_3_4       = 1 << 3,
-    CODERATE_5_6       = 1 << 4,
-    CODERATE_7_8       = 1 << 5,
+    /**
+     * hardware is able to detect and set Code Rate automatically
+     */
+    AUTO = 1 << 0,
+    CODERATE_1_2 = 1 << 1,
+    CODERATE_2_3 = 1 << 2,
+    CODERATE_3_4 = 1 << 3,
+    CODERATE_5_6 = 1 << 4,
+    CODERATE_7_8 = 1 << 5,
 };
 
 /**
@@ -692,17 +909,27 @@
 };
 
 /**
- *  Signal Setting for ISDBS Frontend.
+ *  Signal Settings for ISDBS Frontend.
  */
 struct FrontendIsdbsSettings {
-    /** Signal frequency in Hertz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
+
     uint16_t streamId;
+
     FrontendIsdbsStreamIdType streamIdType;
+
     FrontendIsdbsModulation modulation;
+
     FrontendIsdbsCoderate coderate;
-    /** Symbols per second */
+
+    /**
+     * Symbols per second
+     */
     uint32_t symbolRate;
+
     FrontendIsdbsRolloff rolloff;
 };
 
@@ -711,6 +938,7 @@
  */
 struct FrontendIsdbsCapabilities {
     bitfield<FrontendIsdbsModulation> modulationCap;
+
     bitfield<FrontendIsdbsCoderate> coderateCap;
 };
 
@@ -729,13 +957,15 @@
 @export
 enum FrontendIsdbs3Modulation : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Modulation automatically */
-    AUTO      = 1 << 5,
-    MOD_BPSK      = 1 << 1,
-    MOD_QPSK      = 1 << 2,
-    MOD_8PSK      = 1 << 3,
-    MOD_16APSK    = 1 << 4,
-    MOD_32APSK    = 1 << 5,
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
+    AUTO = 1 << 5,
+    MOD_BPSK = 1 << 1,
+    MOD_QPSK = 1 << 2,
+    MOD_8PSK = 1 << 3,
+    MOD_16APSK = 1 << 4,
+    MOD_32APSK = 1 << 5,
 };
 
 /**
@@ -744,33 +974,45 @@
 @export
 enum FrontendIsdbs3Coderate : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Code Rate automatically */
-    AUTO      = 1 << 0,
-    CODERATE_1_3       = 1 << 1,
-    CODERATE_2_5       = 1 << 2,
-    CODERATE_1_2       = 1 << 3,
-    CODERATE_3_5       = 1 << 4,
-    CODERATE_2_3       = 1 << 5,
-    CODERATE_3_4       = 1 << 6,
-    CODERATE_7_9       = 1 << 7,
-    CODERATE_4_5       = 1 << 8,
-    CODERATE_5_6       = 1 << 9,
-    CODERATE_7_8       = 1 << 10,
-    CODERATE_9_10      = 1 << 11,
+    /**
+     * hardware is able to detect and set Code Rate automatically
+     */
+    AUTO = 1 << 0,
+    CODERATE_1_3 = 1 << 1,
+    CODERATE_2_5 = 1 << 2,
+    CODERATE_1_2 = 1 << 3,
+    CODERATE_3_5 = 1 << 4,
+    CODERATE_2_3 = 1 << 5,
+    CODERATE_3_4 = 1 << 6,
+    CODERATE_7_9 = 1 << 7,
+    CODERATE_4_5 = 1 << 8,
+    CODERATE_5_6 = 1 << 9,
+    CODERATE_7_8 = 1 << 10,
+    CODERATE_9_10 = 1 << 11,
 };
 
 /**
- *  Signal Setting for ISDBS3 Frontend.
+ *  Signal Settings for ISDBS3 Frontend.
  */
 struct FrontendIsdbs3Settings {
-    /** Signal frequency in Hertz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
+
     uint16_t streamId;
+
     FrontendIsdbsStreamIdType streamIdType;
+
     FrontendIsdbs3Modulation modulation;
+
     FrontendIsdbs3Coderate coderate;
-    /** Symbols per second */
+
+    /**
+     * Symbols per second
+     */
     uint32_t symbolRate;
+
     FrontendIsdbs3Rolloff rolloff;
 };
 
@@ -779,6 +1021,7 @@
  */
 struct FrontendIsdbs3Capabilities {
     bitfield<FrontendIsdbs3Modulation> modulationCap;
+
     bitfield<FrontendIsdbs3Coderate> coderateCap;
 };
 
@@ -788,7 +1031,9 @@
 @export
 enum FrontendIsdbtMode : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Mode automatically */
+    /**
+     * hardware is able to detect and set Mode automatically
+     */
     AUTO = 1 << 0,
     MODE_1 = 1 << 1,
     MODE_2 = 1 << 2,
@@ -801,7 +1046,9 @@
 @export
 enum FrontendIsdbtBandwidth : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Bandwidth automatically */
+    /**
+     * hardware is able to detect and set Bandwidth automatically
+     */
     AUTO = 1 << 0,
     BANDWIDTH_8MHZ = 1 << 1,
     BANDWIDTH_7MHZ = 1 << 2,
@@ -814,7 +1061,9 @@
 @export
 enum FrontendIsdbtModulation : uint32_t {
     UNDEFINED = 0,
-    /** hardware is able to detect and set Modulation automatically */
+    /**
+     * hardware is able to detect and set Modulation automatically
+     */
     AUTO = 1 << 0,
     MOD_DQPSK = 1 << 1,
     MOD_QPSK = 1 << 2,
@@ -822,23 +1071,29 @@
     MOD_64QAM = 1 << 4,
 };
 
-/** Code Rate for ISDBT. */
 typedef FrontendDvbtCoderate FrontendIsdbtCoderate;
 
-/** Guard Interval for ISDBT. */
 typedef FrontendDvbtGuardInterval FrontendIsdbtGuardInterval;
 
 /**
- *  Signal Setting for ISDBT Frontend.
+ *  Signal Settings for ISDBT Frontend.
  */
 struct FrontendIsdbtSettings {
-    /** Signal frequency in Hertz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
+
     FrontendIsdbtModulation modulation;
+
     FrontendIsdbtBandwidth bandwidth;
+
     FrontendIsdbtMode mode;
+
     FrontendIsdbtCoderate coderate;
+
     FrontendIsdbtGuardInterval guardInterval;
+
     uint32_t serviceAreaId;
 };
 
@@ -847,9 +1102,13 @@
  */
 struct FrontendIsdbtCapabilities {
     bitfield<FrontendIsdbtMode> modeCap;
+
     bitfield<FrontendIsdbtBandwidth> bandwidthCap;
+
     bitfield<FrontendIsdbtModulation> constellationCap;
+
     bitfield<FrontendIsdbtCoderate> coderateCap;
+
     bitfield<FrontendIsdbtGuardInterval> guardIntervalCap;
 };
 
@@ -872,7 +1131,7 @@
     UNDEFINED = 0,
     BG = 1 << 0,
     BG_A2 = 1 << 1,
-    BG_NICAM  = 1 << 2,
+    BG_NICAM = 1 << 2,
     I = 1 << 3,
     DK = 1 << 4,
     DK1 = 1 << 5,
@@ -890,12 +1149,16 @@
 };
 
 /**
- *  Signal Setting for Analog Frontend.
+ *  Signal Settings for Analog Frontend.
  */
 struct FrontendAnalogSettings {
-    /** Signal frequency in Hertz */
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
+
     FrontendAnalogType type;
+
     FrontendAnalogSifStandard sifStandard;
 };
 
@@ -904,21 +1167,30 @@
  */
 struct FrontendAnalogCapabilities {
     bitfield<FrontendAnalogType> typeCap;
+
     bitfield<FrontendAnalogSifStandard> sifStandardCap;
 };
 
 /**
- *  Signal Setting for Frontend.
+ *  Signal Settings for Frontend.
  */
 safe_union FrontendSettings {
     FrontendAnalogSettings analog;
+
     FrontendAtscSettings atsc;
+
     FrontendAtsc3Settings atsc3;
+
     FrontendDvbsSettings dvbs;
+
     FrontendDvbcSettings dvbc;
+
     FrontendDvbtSettings dvbt;
+
     FrontendIsdbsSettings isdbs;
+
     FrontendIsdbs3Settings isdbs3;
+
     FrontendIsdbtSettings isdbt;
 };
 
@@ -935,25 +1207,45 @@
  *  Scan Message Type for Frontend.
  */
 enum FrontendScanMessageType : uint32_t {
-    /** Scan locked the signal. */
+    /**
+     * Scan locked the signal.
+     */
     LOCKED,
-    /** Scan stopped. */
+    /**
+     * Scan stopped.
+     */
     END,
-    /** Scan progress report. */
+    /**
+     * Scan progress report.
+     */
     PROGRESS_PERCENT,
-    /** Locked frequency report. */
+    /**
+     * Locked frequency report.
+     */
     FREQUENCY,
-    /** Locked symbol rate. */
+    /**
+     * Locked symbol rate.
+     */
     SYMBOL_RATE,
-    /** Locked Plp Ids for DVBT2 frontend. */
+    /**
+     * Locked Plp Ids for DVBT2 frontend.
+     */
     PLP_IDS,
-    /** Locked group Ids for DVBT2 frontend. */
+    /**
+     * Locked group Ids for DVBT2 frontend.
+     */
     GROUP_IDS,
-    /** Stream Ids. */
+    /**
+     * Stream Ids.
+     */
     INPUT_STREAM_IDS,
-    /** Locked signal stardard.  */
+    /**
+     * Locked signal standard.
+     */
     STANDARD,
-    /** PLP status in a tuned frequency band for ATSC3 frontend. */
+    /**
+     * PLP status in a tuned frequency band for ATSC3 frontend.
+     */
     ATSC3_PLP_INFO,
 };
 
@@ -962,6 +1254,7 @@
  */
 struct FrontendScanAtsc3PlpInfo {
     uint8_t plpId;
+
     bool bLlsFlag;
 };
 
@@ -969,22 +1262,40 @@
  *  Scan Message for Frontend.
  */
 safe_union FrontendScanMessage {
-    bool islocked;
+    bool isLocked;
+
     bool isEnd;
-    /** scan progress percent (0..100) */
+
+    /**
+     * scan progress percent (0..100)
+     */
     uint8_t progressPercent;
-    /** Signal frequency in Hertz */
+
+    /**
+     * Signal frequency in Hertz
+     */
     uint32_t frequency;
-    /** Symbols per second */
+
+    /**
+     * Symbols per second
+     */
     uint32_t symbolRate;
+
     vec<uint8_t> plpIds;
+
     vec<uint8_t> groupIds;
+
     vec<uint16_t> inputStreamIds;
+
     safe_union standard {
         FrontendDvbsStandard sStd;
+
         FrontendDvbtStandard tStd;
     } std;
-    /** A list of PLP status in a tuned frequency band for ATSC3 frontend. */
+
+    /**
+     * A list of PLP status in a tuned frequency band for ATSC3 frontend.
+     */
     vec<FrontendScanAtsc3PlpInfo> atsc3PlpInfos;
 };
 
@@ -1008,22 +1319,6 @@
      * event.
      */
     LOST_LOCK,
-    /**
-     * If frontend detect that incoming Diseqc message is overflow.
-     */
-    DISEQC_RX_OVERFLOW,
-    /**
-     * If frontend detect that outgoing Diseqc message isn't delivered on time.
-     */
-    DISEQC_RX_TIMEOUT,
-    /**
-     * If frontend detect that the incoming Diseqc message has parity error.
-     */
-    DISEQC_RX_PARITY_ERROR,
-    /**
-     * If frontend detect that the LNB is overload.
-     */
-    LNB_OVERLOAD,
 };
 
 /**
@@ -1031,60 +1326,106 @@
  */
 @export
 enum FrontendStatusType : uint32_t {
-    /** Lock status for Demod. */
+    /**
+     * Lock status for Demod.
+     */
     DEMOD_LOCK,
-    /** Signal to Noise Ratio. */
+    /**
+     * Signal to Noise Ratio.
+     */
     SNR,
-    /** Bit Error Ratio. */
+    /**
+     * Bit Error Ratio.
+     */
     BER,
-    /** Packages Error Ratio. */
+    /**
+     * Packages Error Ratio.
+     */
     PER,
-    /** Bit Error Ratio before FEC. */
+    /**
+     * Bit Error Ratio before FEC.
+     */
     PRE_BER,
-    /*
+    /**
      * Signal Quality (0..100). Good data over total data in percent can be
      * used as a way to present Signal Quality.
      */
     SIGNAL_QUALITY,
-    /** Signal Strength. */
+    /**
+     * Signal Strength.
+     */
     SIGNAL_STRENGTH,
-    /** Symbol Rate. */
+    /**
+     * Symbol Rate.
+     */
     SYMBOL_RATE,
-    /** Forward Error Correction Type. */
+    /**
+     * Forward Error Correction Type.
+     */
     FEC,
-    /** Modulation Type. */
+    /**
+     * Modulation Type.
+     */
     MODULATION,
-    /** Spectral Inversion Type. */
+    /**
+     * Spectral Inversion Type.
+     */
     SPECTRAL,
-    /** LNB Voltage. */
+    /**
+     * LNB Voltage.
+     */
     LNB_VOLTAGE,
-    /** Physical Layer Pipe ID. */
+    /**
+     * Physical Layer Pipe ID.
+     */
     PLP_ID,
-    /** Status for Emergency Warning Broadcasting System. */
+    /**
+     * Status for Emergency Warning Broadcasting System.
+     */
     EWBS,
-    /** Automatic Gain Control. */
+    /**
+     * Automatic Gain Control.
+     */
     AGC,
-    /** Low Noise Amplifier. */
+    /**
+     * Low Noise Amplifier.
+     */
     LNA,
-    /** Lock status for stream. */
-    STREAM_LOCK,
-    /** Error status by layer. */
+    /**
+     * Error status by layer.
+     */
     LAYER_ERROR,
-    /** CN value by VBER. */
+    /**
+     * CN value by VBER.
+     */
     VBER_CN,
-    /** CN value by LBER. */
+    /**
+     * CN value by LBER.
+     */
     LBER_CN,
-    /** CN value by XER. */
+    /**
+     * CN value by XER.
+     */
     XER_CN,
-    /** Moduration Error Ratio. */
+    /**
+     * Moduration Error Ratio.
+     */
     MER,
-    /** Difference between tuning frequency and actual locked frequency. */
+    /**
+     * Difference between tuning frequency and actual locked frequency.
+     */
     FREQ_OFFSET,
-    /* Hierarchy for DVBT. */
+    /**
+     * Hierarchy for DVBT.
+     */
     HIERARCHY,
-    /** Lock status for RF. */
+    /**
+     * Lock status for RF.
+     */
     RF_LOCK,
-    /** PLP information in a frequency band for ATSC3.0 frontend. */
+    /**
+     * PLP information in a frequency band for ATSC3.0 frontend.
+     */
     ATSC3_PLP_INFO,
 };
 
@@ -1092,23 +1433,34 @@
  * Status for each tuning PLPs
  */
 struct FrontendStatusAtsc3PlpInfo {
-    /** PLP Id value. */
+    /**
+     * PLP Id value.
+     */
     uint8_t plpId;
-    /** Demod Lock/Unlock status of this particular PLP. */
+
+    /**
+     * Demod Lock/Unlock status of this particular PLP.
+     */
     bool isLocked;
-    /** Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation. */
+
+    /**
+     * Uncorrectable Error Counts (UEC) of this particular PLP since last tune operation.
+     */
     uint32_t uec;
 };
 
-
 /**
  * Modulation Type for Frontend's status.
  */
 safe_union FrontendModulationStatus {
     FrontendDvbcModulation dvbc;
+
     FrontendDvbsModulation dvbs;
+
     FrontendIsdbsModulation isdbs;
+
     FrontendIsdbs3Modulation isdbs3;
+
     FrontendIsdbtModulation isdbt;
 };
 
@@ -1116,46 +1468,99 @@
  *  The status for Frontend.
  */
 safe_union FrontendStatus {
-    /** Lock status for Demod in True/False. */
+    /**
+     * Lock status for Demod in True/False.
+     */
     bool isDemodLocked;
-    /** SNR value measured by 0.001 dB. */
+
+    /**
+     * SNR value measured by 0.001 dB.
+     */
     int32_t snr;
-    /** The number of error bit per 1 billion bits. */
+
+    /**
+     * The number of error bit per 1 billion bits.
+     */
     uint32_t ber;
-    /** The number of error package per 1 billion packages. */
+
+    /**
+     * The number of error package per 1 billion packages.
+     */
     uint32_t per;
-    /** The number of error bit per 1 billion bits before FEC. */
+
+    /**
+     * The number of error bit per 1 billion bits before FEC.
+     */
     uint32_t preBer;
-    /** Signal Quality in percent. */
+
+    /**
+     * Signal Quality in percent.
+     */
     uint32_t signalQuality;
-    /** Signal Strength measured by 0.001 dBm. */
+
+    /**
+     * Signal Strength measured by 0.001 dBm.
+     */
     int32_t signalStrength;
-    /** Symbols per second */
+
+    /**
+     * Symbols per second
+     */
     uint32_t symbolRate;
+
     FrontendInnerFec innerFec;
+
     FrontendModulationStatus modulation;
+
     FrontendDvbcSpectralInversion inversion;
-    FrontendLnbVoltage lnbVoltage;
+
+    LnbVoltage lnbVoltage;
+
     uint8_t plpId;
+
     bool isEWBS;
-    /** AGC value is normalized from 0 to 255. */
+
+    /**
+     * AGC value is normalized from 0 to 255.
+     */
     uint8_t agc;
+
     bool isLnaOn;
-    bool isStreamLock;
+
     vec<bool> isLayerError;
-    /** CN value by VBER measured by 0.001 dB */
+
+    /**
+     * CN value by VBER measured by 0.001 dB
+     */
     int32_t vberCn;
-    /** CN value by LBER measured by 0.001 dB */
+
+    /**
+     * CN value by LBER measured by 0.001 dB
+     */
     int32_t lberCn;
-    /** CN value by XER measured by 0.001 dB */
+
+    /**
+     * CN value by XER measured by 0.001 dB
+     */
     int32_t xerCn;
-    /** MER value measured by 0.001 dB */
+
+    /**
+     * MER value measured by 0.001 dB
+     */
     int32_t mer;
-    /** Frequency difference in Hertz. */
+
+    /**
+     * Frequency difference in Hertz.
+     */
     int32_t freqOffset;
+
     FrontendDvbtHierarchy hierarchy;
+
     bool isRfLocked;
-    /** A list of PLP status for tuned PLPs for ATSC3 frontend. */
+
+    /**
+     * A list of PLP status for tuned PLPs for ATSC3 frontend.
+     */
     vec<FrontendStatusAtsc3PlpInfo> plpInfo;
 };
 
@@ -1164,32 +1569,60 @@
  */
 struct FrontendInfo {
     FrontendType type;
-    /** Frequency in Hertz */
+
+    /**
+     * Frequency in Hertz
+     */
     uint32_t minFrequency;
-    /** Frequency in Hertz */
+
+    /**
+     * Frequency in Hertz
+     */
     uint32_t maxFrequency;
-    /** Minimum symbols per second */
+
+    /**
+     * Minimum symbols per second
+     */
     uint32_t minSymbolRate;
-    /** Maximum symbols per second */
+
+    /**
+     * Maximum symbols per second
+     */
     uint32_t maxSymbolRate;
-    /** Range in Hertz */
+
+    /**
+     * Range in Hertz
+     */
     uint32_t acquireRange;
-    /*
+
+    /**
      * Frontends are assigned with the same exclusiveGroupId if they can't
      * function at same time. For instance, they share same hardware module.
      */
     uint32_t exclusiveGroupId;
-    /** A list of supported status types which client can inquiry */
+
+    /**
+     * A list of supported status types which client can inquiry
+     */
     vec<FrontendStatusType> statusCaps;
+
     safe_union FrontendCapabilities {
         FrontendAnalogCapabilities analogCaps;
+
         FrontendAtscCapabilities atscCaps;
+
         FrontendAtsc3Capabilities atsc3Caps;
+
         FrontendDvbsCapabilities dvbsCaps;
+
         FrontendDvbcCapabilities dvbcCaps;
+
         FrontendDvbtCapabilities dvbtCaps;
+
         FrontendIsdbsCapabilities isdbsCaps;
+
         FrontendIsdbs3Capabilities isdbs3Caps;
+
         FrontendIsdbtCapabilities isdbtCaps;
     } frontendCaps;
 };
@@ -1204,7 +1637,7 @@
  *  Power Voltage Type for LNB.
  */
 @export
-enum FrontendLnbVoltage : uint32_t {
+enum LnbVoltage : uint32_t {
     NONE,
     VOLTAGE_5V,
     VOLTAGE_11V,
@@ -1220,7 +1653,7 @@
  *  Tone Type for LNB.
  */
 @export
-enum FrontendLnbTone : int32_t {
+enum LnbTone : int32_t {
     NONE,
     CONTINUOUS,
 };
@@ -1229,41 +1662,92 @@
  *  The Position of LNB.
  */
 @export
-enum FrontendLnbPosition : int32_t {
+enum LnbPosition : int32_t {
     UNDEFINED,
     POSITION_A,
     POSITION_B,
 };
 
+/**
+ * Lnb Event Type.
+ */
+@export
+enum LnbEventType : uint32_t {
+    DISEQC_RX_OVERFLOW,
+    /**
+     * If LNB detect that outgoing Diseqc message isn't delivered on time.
+     */
+    DISEQC_RX_TIMEOUT,
+    /**
+     * If LNB detect that the incoming Diseqc message has parity error.
+     */
+    DISEQC_RX_PARITY_ERROR,
+    /**
+     * If LNB detect that the LNB is overload.
+     */
+    LNB_OVERLOAD,
+};
+
 /* Demux ID is used to associate with a hardware demux resource. */
 typedef uint32_t DemuxId;
 
-/* Filter ID is used to associate with a hardware filter resource. */
-typedef uint32_t DemuxFilterId;
-
 /**
- * Filter Type according to ISO/IEC 13818-1
+ * Filter Main Type specifies the protocol that the filter use to extract data
+ * from input stream.
  */
 @export
-enum DemuxFilterType : uint32_t {
+enum DemuxFilterMainType : uint32_t {
     /**
-     * A filter to filter section data out from input stream.
+     * Transport Stream according to ISO/IEC 13818-1.
+     */
+    TS = 1 << 0,
+    /**
+     * MPEG Media Transport Protocol according to ISO/IEC 23008-1.
+     */
+    MMTP = 1 << 1,
+    /**
+     * Internet Protocol.
+     */
+    IP = 1 << 2,
+    /**
+     * Type Length Value according to ITU-R BT.1869.
+     */
+    TLV = 1 << 3,
+    /**
+     * ATSC Link-Layer Protocol according to A/330 ATSC3.0.
+     */
+    ALP = 1 << 4,
+};
+
+/**
+ * TS Filter Type according to ISO/IEC 13818-1
+ */
+@export
+enum DemuxTsFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter Section data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
      */
     SECTION,
     /**
-     * A filter to filter PES data out from input stream.
+     * A filter to filter Packetized Elementary Stream data out from input
+     * stream, and queue the data to the filter's FMQ.
      */
     PES,
     /**
-     * A filter to filter TS payload out from input stream.
+     * A filter to filter a Transport Stream out from input stream, and queue
+     * the data to the filter's FMQ.
      */
     TS,
     /**
-     * A filter to filter Audio Metadata out from input stream.
+     * A filter to filter Audio data out from input stream, and send Audio's
+     * Metadata to client through onFilterEvent.
      */
     AUDIO,
     /**
-     * A filter to filter Video Metadata out from input stream.
+     * A filter to filter Video data out from input stream, and send Video's
+     * Metadata to client through onFilterEvent.
      */
     VIDEO,
     /**
@@ -1271,20 +1755,172 @@
      */
     PCR,
     /**
-     * A filter to filter data directly to output buffer for record.
+     * A filter to filter data out from input stream, and queue the data to the
+     * buffer of the record.
      */
     RECORD,
 };
 
+/**
+ * MMTP Filter Type according to ISO/IEC 23008-1
+ */
+@export
+enum DemuxMmtpFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter signaling data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to filter MFU (Media fragment unit) out from input stream, and
+     * queue the data to the filter's FMQ.
+     */
+    PES,
+    /**
+     * A filter to filter a MMTP stream out from input stream, and queue the
+     * data to the filter's FMQ.
+     */
+    MMTP,
+    /**
+     * A filter to filter Audio data out from input stream, and send Audio's
+     * Metadata to client through onFilterEvent.
+     */
+    AUDIO,
+    /**
+     * A filter to filter Video data out from input stream, and send Video's
+     * Metadata to client through onFilterEvent.
+     */
+    VIDEO,
+    /**
+     * A filter to filter data out from input stream, and queue the data to the
+     * buffer of the record.
+     */
+    RECORD,
+    /**
+     * A filter to filter application data out from input stream, and queue the
+     * data to the filter's FMQ.
+     */
+    DOWNLOAD,
+};
+
+/**
+ * IP Filter Type.
+ */
+@export
+enum DemuxIpFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter section data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to set NTP (Network Time Procotol) channel from input stream.
+     */
+    NTP,
+    /**
+     * A filter to strip out IP message header and queue the data to the
+     * filter's FMQ.
+     */
+    IP_PAYLOAD,
+    /**
+     * A filter to filter a IP stream out from input stream. The output can be
+     * either upper stream of another filter or queued to the filter's FMQ.
+     */
+    IP,
+    /**
+     * A filter to strip out IP message header and be a data source of another
+     * filter.
+     */
+    PAYLOAD_THROUGH,
+};
+
+/**
+ * TLV Filter Type according to ITU-R BT.1869.
+ */
+@export
+enum DemuxTlvFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter signaling data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to filter a TLV stream out from input stream. The output can be
+     * either upper stream of another filter or queued to the filter's FMQ.
+     */
+    TLV,
+    /**
+     * A filter to strip out TLV message header and be a data source of another
+     * filter.
+     */
+    PAYLOAD_THROUGH,
+};
+
+/**
+ * ALP Filter Type according to A/330 ATSC3.0.
+ */
+@export
+enum DemuxAlpFilterType : uint32_t {
+    UNDEFINED,
+    /**
+     * A filter to filter signaling data out from input stream, and queue the
+     * data to the filter's FMQ (Fast Message Queue).
+     */
+    SECTION,
+    /**
+     * A filter to set PTP (Precision Time Protocol) channel from input stream.
+     */
+    PTP,
+    /**
+     * A filter to strip out ALP message header and be a data source of another
+     * filter.
+     */
+    PAYLOAD_THROUGH,
+};
+
+/**
+ * Demux Filter Type.
+ */
+struct DemuxFilterType {
+    DemuxFilterMainType mainType;
+
+    safe_union DemuxFilterSubType {
+        DemuxTsFilterType tsFilterType;
+
+        DemuxMmtpFilterType mmtpFilterType;
+
+        DemuxIpFilterType ipFilterType;
+
+        DemuxTlvFilterType tlvFilterType;
+
+        DemuxAlpFilterType alpFilterType;
+    } subType;
+};
+
 /* Packet ID is used to specify packets in transport stream. */
 typedef uint16_t DemuxTpid;
 
+/* Packet ID is used to specify packets in MMTP */
+typedef uint16_t DemuxMmtpPid;
+
+/**
+ * Demux Packet ID.
+ */
+safe_union DemuxPid {
+    DemuxTpid tPid;
+
+    DemuxMmtpPid mmtpPid;
+};
+
 @export
 enum Constant : uint16_t {
     /**
      * An invalid packet ID in transport stream according to ISO/IEC 13818-1.
      */
-    INVALID_TPID = 0xFFFF,
+    INVALID_TS_PID = 0xFFFF,
     /**
      * An invalid Stream ID.
      */
@@ -1304,7 +1940,7 @@
      * The available data amount in the filter buffer is at low level which is
      * set to 25 percent by default.
      */
-    LOW_WATER  = 1 << 1,
+    LOW_WATER = 1 << 1,
     /**
      * The available data amount in the filter buffer is at high level which is
      * set to 75 percent by default.
@@ -1314,18 +1950,122 @@
      * The data in the filter buffer is full and newly filtered data is being
      * discarded.
      */
-    OVERFLOW   = 1 << 3,
+    OVERFLOW = 1 << 3,
 };
 
 /**
- *  Bits Setting for Section Filter.
+ * Indexes can be tagged through TS (Transport Stream) header.
+ */
+@export
+enum DemuxTsIndex : uint32_t {
+    FIRST_PACKET = 1 << 0,
+    PAYLOAD_UNIT_START_INDICATOR = 1 << 1,
+    CHANGE_TO_NOT_SCRAMBLED = 1 << 2,
+    CHANGE_TO_EVEN_SCRAMBLED = 1 << 3,
+    CHANGE_TO_ODD_SCRAMBLED = 1 << 4,
+    DISCONTINUITY_INDICATOR = 1 << 5,
+    RANDOM_ACCESS_INDICATOR = 1 << 6,
+    PRIORITY_INDICATOR = 1 << 7,
+    PCR_FLAG = 1 << 8,
+    OPCR_FLAG = 1 << 9,
+    SPLICING_POINT_FLAG = 1 << 10,
+    PRIVATE_DATA = 1 << 11,
+    ADAPTATION_EXTENSION_FLAG = 1 << 12,
+};
+
+/**
+ * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
+ * according to ISO/IEC 13818-1.
+ */
+@export
+enum DemuxScIndex : uint32_t {
+    /**
+     * Start Code is for a new I Frame
+     */
+    I_FRAME = 1 << 0,
+    /**
+     * Start Code is for a new P Frame
+     */
+    P_FRAME = 1 << 1,
+    /**
+     * Start Code is for a new B Frame
+     */
+    B_FRAME = 1 << 2,
+    /**
+     * Start Code is for a new Sequence
+     */
+    SEQUENCE = 1 << 3,
+};
+
+/**
+ * Indexes can be tagged by NAL unit group in HEVC
+ * according to ISO/IEC 23008-2.
+ */
+@export
+enum DemuxScHevcIndex : uint32_t {
+    SPS = 1 << 0,
+    AUD = 1 << 1,
+    SLICE_CE_BLA_W_LP = 1 << 2,
+    SLICE_BLA_W_RADL = 1 << 3,
+    SLICE_BLA_N_LP = 1 << 4,
+    SLICE_IDR_W_RADL = 1 << 5,
+    SLICE_IDR_N_LP = 1 << 6,
+    SLICE_TRAIL_CRA = 1 << 7,
+};
+
+/**
+ * Index type to be used in the filter for record
+ */
+@export
+enum DemuxRecordIndexType : uint32_t {
+    /**
+     * Don't use index
+     */
+    NONE,
+    /**
+     * Use TS index
+     */
+    TS,
+    /**
+     * Use Start Code index
+     */
+    SC,
+    /**
+     * Use Start Code index for HEVC
+     */
+    SC_HEVC,
+};
+
+/**
+ *  Filter Settings for Record data.
+ */
+struct DemuxFilterRecordSettings {
+    DemuxRecordIndexType indexType;
+
+    safe_union IndexMask {
+        bitfield<DemuxTsIndex> tsIndexMask;
+
+        bitfield<DemuxScIndex> scIndexMask;
+
+        bitfield<DemuxScHevcIndex> scHevcIndexMask;
+    } indexMask;
+};
+
+/**
+ *  Bits Settings for Section Filter.
  */
 struct DemuxFilterSectionBits {
-    /* The bytes are configured for Section Filter */
+    /**
+     * The bytes are configured for Section Filter
+     */
     vec<uint8_t> filter;
-    /* Active bits in the configured bytes to be used for filtering */
+
+    /**
+     * Active bits in the configured bytes to be used for filtering
+     */
     vec<uint8_t> mask;
-    /*
+
+    /**
      * Do positive match at the bit position of the configured bytes when the
      * bit at same position of the mode is 0.
      * Do negative match at the bit position of the configured bytes when the
@@ -1338,45 +2078,56 @@
  *  Filter Settings for Section data according to ISO/IEC 13818-1.
  */
 struct DemuxFilterSectionSettings {
-    DemuxTpid tpid;
-    DemuxFilterSectionBits bits;
-    /* Table ID for Section Filter */
-    uint16_t tableId;
-    /* Version number for Section Filter */
-    uint16_t version;
-    /* true if the filter checks CRC and discards data with wrong CRC */
+    safe_union Condition {
+        DemuxFilterSectionBits sectionBits;
+
+        struct TableInfo {
+            /**
+             * Table ID for Section Filter
+             */
+            uint16_t tableId;
+
+            /**
+             * Version number for Section Filter
+             */
+            uint16_t version;
+        } tableInfo;
+    } condition;
+
+    /**
+     * true if the filter checks CRC and discards data with wrong CRC
+     */
     bool isCheckCrc;
-    /* true if the filter repeats the data with the same version */
+
+    /**
+     * true if the filter repeats the data with the same version
+     */
     bool isRepeat;
-    /* true if the filter output raw data */
+
+    /**
+     * true if the filter send onFilterStatus instead of onFilterEvent.
+     */
     bool isRaw;
 };
 
-/* Stream ID is used to specify one elementary stream */
 typedef uint16_t DemuxStreamId;
 
 /**
  *  Filter Settings for a PES Data.
  */
 struct DemuxFilterPesDataSettings {
-    DemuxTpid tpid;
     DemuxStreamId streamId;
-    /* true if the filter output raw data */
+
+    /**
+     * true if the filter send onFilterStatus instead of onFilterEvent.
+     */
     bool isRaw;
 };
 
 /**
- *  Filter Settings for a TS Data.
+ *  Filter Settings for a Video and Audio.
  */
-struct DemuxFilterTsSettings {
-    DemuxTpid tpid;
-};
-
-/**
- *  Filter Settings for a Audio.
- */
-struct DemuxFilterAudioSettings {
-    DemuxTpid tpid;
+struct DemuxFilterAvSettings {
     /**
      * true if the filter output goes to decoder directly in pass through mode.
      */
@@ -1384,107 +2135,181 @@
 };
 
 /**
- *  Filter Settings for a Video.
+ *  Filter Settings for a Download.
  */
-struct DemuxFilterVideoSettings {
+struct DemuxFilterDownloadSettings {
+    uint32_t downloadId;
+};
+
+/**
+ *  IP Settings for a IP filter.
+ */
+struct DemuxIpAddress {
+    safe_union SrcIpAddress {
+        uint8_t[4] v4;
+
+        uint8_t[16] v6;
+    } srcIpAddress;
+
+    safe_union DstIpAddress {
+        uint8_t[4] v4;
+
+        uint8_t[16] v6;
+    } dstIpAddress;
+
+    uint16_t srcPort;
+
+    uint16_t dstPort;
+};
+
+/**
+ *  Filter Settings for a TS filter.
+ */
+struct DemuxTsFilterSettings {
     DemuxTpid tpid;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by PCR, TS subtype filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+
+        DemuxFilterAvSettings av;
+
+        DemuxFilterPesDataSettings pesData;
+
+        DemuxFilterRecordSettings record;
+    } filterSettings;
+};
+
+/**
+ *  Filter Settings for a MMTP filter.
+ */
+struct DemuxMmtpFilterSettings {
+    DemuxMmtpPid mmtpPid;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by MMTP subtype filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+
+        DemuxFilterAvSettings av;
+
+        DemuxFilterPesDataSettings pesData;
+
+        DemuxFilterRecordSettings record;
+
+        DemuxFilterDownloadSettings download;
+    } filterSettings;
+};
+
+/**
+ *  Filter Settings for a IP filter.
+ */
+struct DemuxIpFilterSettings {
+    DemuxIpAddress ipAddr;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by NTP, IP_PAYLOAD,
+         * PAYLOAD_THROUGH subtype filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+
+        DemuxFilterPesDataSettings pesData;
+
+        /**
+         * true if the data from IP subtype go to next filter directly
+         */
+        bool bPassthrough;
+    } filterSettings;
+};
+
+/**
+ *  Filter Settings for a TLV filter.
+ */
+struct DemuxTlvFilterSettings {
+    uint8_t packetType;
+
     /**
-     * true if the filter output goes to decoder directly in pass through mode.
+     * true if the filtered data is commpressed ip packet
      */
-    bool isPassthrough;
+    bool bIsCompressedIpPacket;
+
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by PAYLOAD_THROUGH subtype
+         * filters.
+         */
+        Monostate noinit;
+
+        DemuxFilterSectionSettings section;
+
+        /**
+         * true if the data from TLV subtype go to next filter directly
+         */
+        bool bPassthrough;
+    } filterSettings;
 };
 
 /**
- *  Filter Settings for a PCR (Program Clock Reference).
- */
-struct DemuxFilterPcrSettings {
-    DemuxTpid tpid;
-};
-
-/**
- * Indexes can be tagged through TS (Transport Stream) header.
+ * ALP Length Type
  */
 @export
-enum DemuxTsIndex : uint32_t {
-    FIRST_PACKET                 = 1 << 0,
-    PAYLOAD_UNIT_START_INDICATOR = 1 << 1,
-    CHANGE_TO_NOT_SCRAMBLED      = 1 << 2,
-    CHANGE_TO_EVEN_SCRAMBLED     = 1 << 3,
-    CHANGE_TO_ODD_SCRAMBLED      = 1 << 4,
-    DISCONTINUITY_INDICATOR      = 1 << 5,
-    RANDOM_ACCESS_INDICATOR      = 1 << 6,
-    PRIORITY_INDICATOR           = 1 << 7,
-    PCR_FLAG                     = 1 << 8,
-    OPCR_FLAG                    = 1 << 9,
-    SPLICING_POINT_FLAG          = 1 << 10,
-    PRIVATE_DATA                 = 1 << 11,
-    ADAPTATION_EXTENSION_FLAG    = 1 << 12,
+enum DemuxAlpLengthType : uint8_t {
+    UNDEFINED = 0,
+    /**
+     * Length does NOT include additional header. Used in US region.
+     */
+    WITHOUT_ADDITIONAL_HEADER,
+    /**
+     * Length includes additional header. Used in Korea region.
+     */
+    WITH_ADDITIONAL_HEADER,
 };
 
 /**
- * A mask of TS indexes
- *
- * It's a combination of TS indexes.
+ *  Filter Settings for a ALP filter.
  */
-typedef bitfield<DemuxTsIndex> DemuxTsIndexMask;
+struct DemuxAlpFilterSettings {
+    /**
+     * 0: IpV4, 2:Compressed Ip, 4:Signaling.
+     */
+    uint8_t packetType;
 
-/**
- * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream)
- * according to ISO/IEC 13818-1.
- */
-@export
-enum DemuxScIndex : uint32_t {
-    /* Start Code is for a new I Frame */
-    I_FRAME   = 1 << 0,
-    /* Start Code is for a new P Frame */
-    P_FRAME   = 1 << 1,
-    /* Start Code is for a new B Frame */
-    B_FRAME   = 1 << 2,
-    /* Start Code is for a new Sequence */
-    SEQUENCE  = 1 << 3,
-};
+    DemuxAlpLengthType lengthType;
 
-/**
- * A mask of Start Code Indexes
- *
- * It's a combination of Start Code Indexes.
- */
-typedef bitfield<DemuxScIndex> DemuxScIndexMask;
+    safe_union FilterSettings {
+        /**
+         * Not additional parameters. it's used by PTP, PAYLOAD_THROUGH subtype
+         * filters.
+         */
+        Monostate noinit;
 
-/* Index type to be used in the filter for record */
-@export
-enum DemuxRecordIndexType : uint32_t {
-    /* Don't use index */
-    NONE,
-    /* Use TS index */
-    TS,
-    /* Use Start Code index */
-    SC,
-};
-
-/**
- *  Filter Settings for Record data.
- */
-struct DemuxFilterRecordSettings {
-    DemuxTpid tpid;
-    DemuxRecordIndexType indexType;
-    safe_union IndexMask {
-        DemuxTsIndexMask tsIndexMask;
-        DemuxScIndexMask scIndexMask;
-    } indexMask;
+        DemuxFilterSectionSettings section;
+    } filterSettings;
 };
 
 /**
  *  Filter Settings.
  */
 safe_union DemuxFilterSettings {
-    DemuxFilterSectionSettings section;
-    DemuxFilterPesDataSettings pesData;
-    DemuxFilterTsSettings ts;
-    DemuxFilterAudioSettings audio;
-    DemuxFilterVideoSettings video;
-    DemuxFilterPcrSettings pcr;
-    DemuxFilterRecordSettings record;
+    DemuxTsFilterSettings ts;
+
+    DemuxMmtpFilterSettings mmtp;
+
+    DemuxIpFilterSettings ip;
+
+    DemuxTlvFilterSettings tlv;
+
+    DemuxAlpFilterSettings alp;
 };
 
 /**
@@ -1493,38 +2318,106 @@
  */
 @export
 enum DemuxQueueNotifyBits : uint32_t {
-    /* client writes data and notify HAL the data is ready. */
+    /**
+     * client writes data and notify HAL the data is ready.
+     */
     DATA_READY = 1 << 0,
-    /* client reads data and notify HAL the data is consumed. */
-    DATA_CONSUMED = 1 << 1
+    /**
+     * client reads data and notify HAL the data is consumed.
+     */
+    DATA_CONSUMED = 1 << 1,
 };
 
 /**
  *  Filter Event for Section Filter.
  */
 struct DemuxFilterSectionEvent {
-    /* Table ID of filtered data */
+    /**
+     * Table ID of filtered data
+     */
     uint16_t tableId;
-    /* Version number of filtered data */
+
+    /**
+     * Version number of filtered data
+     */
     uint16_t version;
-    /* Section number of filtered data */
+
+    /**
+     * Section number of filtered data
+     */
     uint16_t sectionNum;
-    /* Data size in bytes of filtered data */
+
+    /**
+     * Data size in bytes of filtered data
+     */
     uint16_t dataLength;
 };
 
 /**
+ *  Extra Meta Data from AD (Audio Descriptor) according to
+ *  ETSI TS 101 154 V2.1.1.
+ */
+struct AudioExtraMetaData {
+    uint8_t adFade;
+
+    uint8_t adPan;
+
+    uint8_t versionTextTag;
+
+    uint8_t adGainCenter;
+
+    uint8_t adGainFront;
+
+    uint8_t adGainSurround;
+};
+
+/**
  *  Filter Event for Audio or Video Filter.
  */
 struct DemuxFilterMediaEvent {
-    /* Presentation Time Stamp for audio or video frame. It based on 90KHz has
+    DemuxStreamId streamId;
+
+    /**
+     * true if PTS is present in PES header.
+     */
+    bool isPtsPresent;
+
+    /**
+     * Presentation Time Stamp for audio or video frame. It based on 90KHz has
      * the same format as PTS (Presentation Time Stamp).
      */
     uint64_t pts;
-    /* Data size in bytes of audio or video frame */
-    uint16_t dataLength;
-    /* A handle associated to the memory where audio or video data stays. */
-    handle secureMemory;
+
+    /**
+     * Data size in bytes of audio or video frame
+     */
+    uint32_t dataLength;
+
+    /**
+     * A handle associated to the memory where audio or video data stays.
+     */
+    handle avMemory;
+
+    /**
+     * True if the avMemory is in secure area, and isn't mappable.
+     */
+    bool isSecureMemory;
+
+    /**
+     * MPU sequence number of filtered data (only for MMTP)
+     */
+    uint32_t mpuSequenceNumber;
+
+    bool isPesPrivateData;
+
+    safe_union ExtraMetaData {
+        /**
+         * Not additional parameters. it's used for video.
+         */
+        Monostate noinit;
+
+        AudioExtraMetaData audio;
+    } extraMetaData;
 };
 
 /**
@@ -1532,176 +2425,309 @@
  */
 struct DemuxFilterPesEvent {
     DemuxStreamId streamId;
-    /* Data size in bytes of PES data */
+
+    /**
+     * Data size in bytes of PES data
+     */
+    uint16_t dataLength;
+
+    /**
+     * MPU sequence number of filtered data (only for MMTP)
+     */
+    uint32_t mpuSequenceNumber;
+};
+
+/**
+ *  Filter Event for TS Record data.
+ */
+struct DemuxFilterTsRecordEvent {
+    DemuxPid pid;
+
+    /**
+     * Indexes of record output
+     */
+    safe_union IndexMask {
+        bitfield<DemuxTsIndex> tsIndexMask;
+
+        bitfield<DemuxScIndex> scIndexMask;
+
+        bitfield<DemuxScHevcIndex> scHevcIndexMask;
+    } indexMask;
+
+    /**
+     * Byte number from beginning of the filter's output
+     */
+    uint64_t byteNumber;
+};
+
+/**
+ *  Filter Event for MMTP Record data.
+ */
+struct DemuxFilterMmtpRecordEvent {
+    bitfield<DemuxScHevcIndex> scHevcIndexMask;
+
+    /**
+     * Byte number from beginning of the filter's output
+     */
+    uint64_t byteNumber;
+};
+
+/**
+ *  Filter Event for Download data.
+ */
+struct DemuxFilterDownloadEvent {
+    uint32_t itemId;
+
+    /**
+     * MPU sequence number of filtered data (only for MMTP)
+     */
+    uint32_t mpuSequenceNumber;
+
+    uint32_t itemFragmentIndex;
+
+    uint32_t lastItemFragmentIndex;
+
+    /**
+     * Data size in bytes of filtered data
+     */
     uint16_t dataLength;
 };
 
 /**
- *  Filter Event for Record data.
+ *  Filter Event for IP payload data.
  */
-struct DemuxFilterRecordEvent {
-    DemuxTpid tpid;
-    /* Indexes of record output */
-    safe_union IndexMask {
-        DemuxTsIndexMask tsIndexMask;
-        DemuxScIndexMask scIndexMask;
-    } indexMask;
-    /* Packet number from beginning of the filter's output */
-    uint64_t packetNum;
+struct DemuxFilterIpPayloadEvent {
+    /**
+     * Data size in bytes of IP data
+     */
+    uint16_t dataLength;
 };
 
 /**
  * Filter Event.
  */
 struct DemuxFilterEvent {
-    DemuxFilterId filterId;
-    DemuxFilterType filterType;
     safe_union Event {
         DemuxFilterSectionEvent section;
+
         DemuxFilterMediaEvent media;
+
         DemuxFilterPesEvent pes;
-        DemuxFilterRecordEvent ts;
+
+        DemuxFilterTsRecordEvent tsRecord;
+
+        DemuxFilterMmtpRecordEvent mmtpRecord;
+
+        DemuxFilterDownloadEvent download;
+
+        DemuxFilterIpPayloadEvent ipPayload;
     };
-    /* An array of events */
+
+    /**
+     * An array of events
+     */
     vec<Event> events;
 };
 
-/**
- *  A hardware resource ID to be used for audio and video hardware sync.
- */
 typedef uint32_t AvSyncHwId;
 
-/**
- *  A token to be used to link descrambler and key slot. It's opaque to
- *  framework and apps.
- */
 typedef vec<uint8_t> TunerKeyToken;
 
 /**
  * A data format in demux's output or input according to ISO/IEC 13818-1.
  */
 @export
-enum DemuxDataFormat : uint32_t {
-    /* Data is Transport Stream. */
+enum DataFormat : uint32_t {
+    /**
+     * Data is Transport Stream.
+     */
     TS,
-    /* Data is Packetized Elementary Stream. */
+    /**
+     * Data is Packetized Elementary Stream.
+     */
     PES,
-    /* Data is Elementary Stream. */
+    /**
+     * Data is Elementary Stream.
+     */
     ES,
-    /* Data is TLV (type-length-value) Stream for JP SHV */
+    /**
+     * Data is TLV (type-length-value) Stream for JP SHV
+     */
     SHV_TLV,
 };
 
-/**
- * A status of the demux's output.
- */
-typedef DemuxFilterStatus DemuxOutputStatus;
+typedef DemuxFilterStatus RecordStatus;
 
 /**
- *  The Settings for the demux's output.
+ *  The Settings for the record in DVR.
  */
-struct DemuxOutputSettings {
+struct RecordSettings {
     /**
      * Register for interested status events so that the HAL can send these
      * status events back to client.
      */
-    bitfield<DemuxOutputStatus> statusMask;
+    bitfield<RecordStatus> statusMask;
+
     /**
-     * Unconsumed data size in bytes in the output. The HAL uses it to trigger
-     * DemuxOutputStatus::LOW_WATER.
+     * Unconsumed data size in bytes in the record. The HAL uses it to trigger
+     * OutputStatus::LOW_WATER.
      */
     uint32_t lowThreshold;
+
     /**
-     * Unconsumed data size in bytes in the output. The HAL uses it to trigger
-     * DemuxOutputStatus::High_WATER.
+     * Unconsumed data size in bytes in the record. The HAL uses it to trigger
+     * OutputStatus::High_WATER.
      */
     uint32_t highThreshold;
+
     /**
-     * The data format in the output.
+     * The data format in the record.
      */
-    DemuxDataFormat dataFormat;
+    DataFormat dataFormat;
+
     /**
-     * The packet size in bytes in the output.
+     * The packet size in bytes in the record.
      */
     uint8_t packetSize;
 };
 
 /**
- * A status of the demux's input.
+ * A status of the playback in DVR.
  */
 @export
-enum DemuxInputStatus : uint32_t {
+enum PlaybackStatus : uint32_t {
     /**
-     * The space of the demux's input is empty.
+     * The space of the demux's playback is empty.
      */
-    SPACE_EMPTY        = 1 << 0,
+    SPACE_EMPTY = 1 << 0,
     /**
-     * The spece of the demux's input is almost empty.
+     * The spece of the demux's playback is almost empty.
      */
     SPACE_ALMOST_EMPTY = 1 << 1,
     /**
-     * The space of the demux's input is almost full.
+     * The space of the demux's playback is almost full.
      */
-    SPACE_ALMOST_FULL  = 1 << 2,
+    SPACE_ALMOST_FULL = 1 << 2,
     /**
-     * The space of the demux's input is full.
+     * The space of the demux's playback is full.
      */
-    SPACE_FULL         = 1 << 3,
+    SPACE_FULL = 1 << 3,
 };
 
 /**
- *  The Settings for the demux's input.
+ * The Setting for the playback in DVR.
  */
-@export
-struct DemuxInputSettings {
+struct PlaybackSettings {
     /**
      * Register for interested status events so that the HAL can send these
      * status events back to client.
      */
-    bitfield<DemuxInputStatus> statusMask;
+    bitfield<PlaybackStatus> statusMask;
+
     /**
-     * Unused space size in bytes in the input. The HAL uses it to trigger
-     * DemuxInputStatus::SPACE_ALMOST_EMPTY.
+     * Unused space size in bytes in the playback. The HAL uses it to trigger
+     * InputStatus::SPACE_ALMOST_EMPTY.
      */
     uint32_t lowThreshold;
+
     /**
-     * Unused space size in bytes in the input. The HAL uses it to trigger
-     * DemuxInputStatus::SPACE_ALMOST_FULL.
+     * Unused space size in bytes in the playback. The HAL uses it to trigger
+     * InputStatus::SPACE_ALMOST_FULL.
      */
     uint32_t highThreshold;
+
     /**
-     * The data format in the input.
+     * The data format in the playback.
      */
-    DemuxDataFormat dataFormat;
+    DataFormat dataFormat;
+
     /**
-     * The packet size in bytes in the input.
+     * The packet size in bytes in the playback.
      */
     uint8_t packetSize;
 };
 
 /**
+ * The type of DVR.
+ */
+@export
+enum DvrType : uint8_t {
+    RECORD,
+    PLAYBACK,
+};
+
+/**
+ * The Setting for DVR.
+ */
+safe_union DvrSettings {
+    RecordSettings record;
+
+    PlaybackSettings playback;
+};
+
+/**
  *  Capabilities for Demux.
  */
-@export
 struct DemuxCapabilities {
-    /* The number of Demux to be supported. */
+    /**
+     * The number of Demux to be supported.
+     */
     uint32_t numDemux;
-    /* The number of Input to be supported. */
-    uint32_t numInput;
-    /* The number of Output to be supported. */
-    uint32_t numOutput;
-    /* The number of TS Filter to be supported. */
+
+    /**
+     * The number of record to be supported.
+     */
+    uint32_t numRecord;
+
+    /**
+     * The number of playback to be supported.
+     */
+    uint32_t numPlayback;
+
+    /**
+     * The number of TS Filter to be supported.
+     */
     uint32_t numTsFilter;
-    /* The number of Section Filter to be supported. */
+
+    /**
+     * The number of Section Filter to be supported.
+     */
     uint32_t numSectionFilter;
-    /* The number of Audio Filter to be supported. */
+
+    /**
+     * The number of Audio Filter to be supported.
+     */
     uint32_t numAudioFilter;
-    /* The number of Video Filter to be supported. */
+
+    /**
+     * The number of Video Filter to be supported.
+     */
     uint32_t numVideoFilter;
-    /* The number of PES Filter to be supported. */
+
+    /**
+     * The number of PES Filter to be supported.
+     */
     uint32_t numPesFilter;
-    /* The number of PCR Filter to be supported. */
+
+    /**
+     * The number of PCR Filter to be supported.
+     */
     uint32_t numPcrFilter;
-    /* The maximum number of bytes is supported in the mask of Section Filter. */
+
+    /**
+     * The maximum number of bytes is supported in the mask of Section Filter.
+     */
     uint32_t numBytesInSectionFilter;
+
+    bitfield<DemuxFilterMainType> filterCaps;
+
+    /**
+     * The array has same elements as DemuxFilterMainType. linkCaps[i] presents
+     * filter's capability as soource for the ith type in DemuxFilterMainType.
+     * The jth bit of linkCaps[i] is 1 if the output of ith type filter can be
+     * data source for the filter type j.
+     */
+    vec<bitfield<DemuxFilterMainType>> linkCaps;
+
+    bool bTimeFilter;
 };
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 7936185..c666226 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -20,8 +20,11 @@
 #include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/tv/tuner/1.0/IDemux.h>
-#include <android/hardware/tv/tuner/1.0/IDemuxCallback.h>
 #include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/IFilter.h>
+#include <android/hardware/tv/tuner/1.0/IFilterCallback.h>
 #include <android/hardware/tv/tuner/1.0/IFrontend.h>
 #include <android/hardware/tv/tuner/1.0/IFrontendCallback.h>
 #include <android/hardware/tv/tuner/1.0/ITuner.h>
@@ -57,8 +60,9 @@
 using android::hardware::MQDescriptorSync;
 using android::hardware::Return;
 using android::hardware::Void;
-using android::hardware::tv::tuner::V1_0::DemuxDataFormat;
+using android::hardware::tv::tuner::V1_0::DataFormat;
 using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
 using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
@@ -66,10 +70,11 @@
 using android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
 using android::hardware::tv::tuner::V1_0::DemuxFilterType;
-using android::hardware::tv::tuner::V1_0::DemuxInputSettings;
-using android::hardware::tv::tuner::V1_0::DemuxInputStatus;
-using android::hardware::tv::tuner::V1_0::DemuxOutputStatus;
 using android::hardware::tv::tuner::V1_0::DemuxQueueNotifyBits;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
+using android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using android::hardware::tv::tuner::V1_0::DvrSettings;
+using android::hardware::tv::tuner::V1_0::DvrType;
 using android::hardware::tv::tuner::V1_0::FrontendAtscModulation;
 using android::hardware::tv::tuner::V1_0::FrontendAtscSettings;
 using android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
@@ -80,11 +85,17 @@
 using android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
 using android::hardware::tv::tuner::V1_0::FrontendSettings;
 using android::hardware::tv::tuner::V1_0::IDemux;
-using android::hardware::tv::tuner::V1_0::IDemuxCallback;
 using android::hardware::tv::tuner::V1_0::IDescrambler;
+using android::hardware::tv::tuner::V1_0::IDvr;
+using android::hardware::tv::tuner::V1_0::IDvrCallback;
+using android::hardware::tv::tuner::V1_0::IFilter;
+using android::hardware::tv::tuner::V1_0::IFilterCallback;
 using android::hardware::tv::tuner::V1_0::IFrontend;
 using android::hardware::tv::tuner::V1_0::IFrontendCallback;
 using android::hardware::tv::tuner::V1_0::ITuner;
+using android::hardware::tv::tuner::V1_0::PlaybackSettings;
+using android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using android::hardware::tv::tuner::V1_0::RecordStatus;
 using android::hardware::tv::tuner::V1_0::Result;
 
 namespace {
@@ -131,17 +142,28 @@
         0x73, 0x63, 0x65, 0x6e, 0x65,
 };
 
-const uint16_t FMQ_SIZE_4K = 0x1000;
+// const uint16_t FMQ_SIZE_4K = 0x1000;
 const uint32_t FMQ_SIZE_1M = 0x100000;
+const uint32_t FMQ_SIZE_16M = 0x1000000;
 
 struct FilterConf {
     DemuxFilterType type;
     DemuxFilterSettings setting;
 };
 
-struct InputConf {
+enum FilterEventType : uint8_t {
+    UNDEFINED,
+    SECTION,
+    MEDIA,
+    PES,
+    RECORD,
+    MMTPRECORD,
+    DOWNLOAD,
+};
+
+struct PlaybackConf {
     string inputDataFile;
-    DemuxInputSettings setting;
+    PlaybackSettings setting;
 };
 
 class FrontendCallback : public IFrontendCallback {
@@ -154,14 +176,6 @@
         return Void();
     }
 
-    virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override {
-        android::Mutex::Autolock autoLock(mMsgLock);
-        mDiseqcMessageReceived = true;
-        mEventMessage = diseqcMessage;
-        mMsgCondition.signal();
-        return Void();
-    }
-
     virtual Return<void> onScanMessage(FrontendScanMessageType /* type */,
                                        const FrontendScanMessage& /* message */) override {
         android::Mutex::Autolock autoLock(mMsgLock);
@@ -211,14 +225,14 @@
     }
 }
 
-class DemuxCallback : public IDemuxCallback {
+class FilterCallback : public IFilterCallback {
   public:
     virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent) override {
         android::Mutex::Autolock autoLock(mMsgLock);
         // Temprarily we treat the first coming back filter data on the matching pid a success
         // once all of the MQ are cleared, means we got all the expected output
-        mFilterIdToEvent[filterEvent.filterId] = filterEvent;
-        readFilterEventData(filterEvent.filterId);
+        mFilterIdToEvent = filterEvent;
+        readFilterEventData();
         mPidFilterOutputCount++;
         // mFilterIdToMQ.erase(filterEvent.filterId);
 
@@ -227,96 +241,50 @@
         return Void();
     }
 
-    virtual Return<void> onFilterStatus(uint32_t /*filterId*/,
-                                        const DemuxFilterStatus /*status*/) override {
+    virtual Return<void> onFilterStatus(const DemuxFilterStatus /*status*/) override {
         return Void();
     }
 
-    virtual Return<void> onOutputStatus(DemuxOutputStatus /*status*/) override { return Void(); }
+    void setFilterId(uint32_t filterId) { mFilterId = filterId; }
+    void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
 
-    virtual Return<void> onInputStatus(DemuxInputStatus status) override {
-        // android::Mutex::Autolock autoLock(mMsgLock);
-        ALOGW("[vts] input status %d", status);
-        switch (status) {
-            case DemuxInputStatus::SPACE_EMPTY:
-            case DemuxInputStatus::SPACE_ALMOST_EMPTY:
-                ALOGW("[vts] keep inputing %d", status);
-                mKeepWritingInputFMQ = true;
-                break;
-            case DemuxInputStatus::SPACE_ALMOST_FULL:
-            case DemuxInputStatus::SPACE_FULL:
-                ALOGW("[vts] stop inputing %d", status);
-                mKeepWritingInputFMQ = false;
-                break;
-        }
-        return Void();
-    }
-
-    void testOnFilterEvent(uint32_t filterId);
     void testFilterDataOutput();
-    void stopInputThread();
 
-    void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor);
     void startFilterEventThread(DemuxFilterEvent event);
-    static void* __threadLoopInput(void* threadArgs);
     static void* __threadLoopFilter(void* threadArgs);
-    void inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ);
     void filterThreadLoop(DemuxFilterEvent& event);
 
-    void updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor);
-    void updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile);
-    bool readFilterEventData(uint32_t filterId);
+    void updateFilterMQ(MQDesc& filterMQDescriptor);
+    void updateGoldenOutputMap(string goldenOutputFile);
+    bool readFilterEventData();
 
   private:
-    struct InputThreadArgs {
-        DemuxCallback* user;
-        InputConf* inputConf;
-        bool* keepWritingInputFMQ;
-    };
     struct FilterThreadArgs {
-        DemuxCallback* user;
+        FilterCallback* user;
         DemuxFilterEvent event;
     };
     uint16_t mDataLength = 0;
     std::vector<uint8_t> mDataOutputBuffer;
 
-    bool mFilterEventReceived;
-    std::map<uint32_t, string> mFilterIdToGoldenOutput;
+    string mFilterIdToGoldenOutput;
 
-    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
-    std::unique_ptr<FilterMQ> mInputMQ;
-    std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
-    std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
-    EventFlag* mInputMQEventFlag;
+    uint32_t mFilterId;
+    FilterEventType mFilterEventType;
+    std::unique_ptr<FilterMQ> mFilterIdToMQ;
+    EventFlag* mFilterIdToMQEventFlag;
+    DemuxFilterEvent mFilterIdToEvent;
 
     android::Mutex mMsgLock;
     android::Mutex mFilterOutputLock;
-    android::Mutex mInputThreadLock;
     android::Condition mMsgCondition;
     android::Condition mFilterOutputCondition;
 
-    bool mKeepWritingInputFMQ = true;
-    bool mInputThreadRunning;
-    pthread_t mInputThread;
     pthread_t mFilterThread;
 
     int mPidFilterOutputCount = 0;
 };
 
-void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) {
-    mInputMQ = std::make_unique<FilterMQ>(inputMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mInputMQ);
-    struct InputThreadArgs* threadArgs =
-            (struct InputThreadArgs*)malloc(sizeof(struct InputThreadArgs));
-    threadArgs->user = this;
-    threadArgs->inputConf = &inputConf;
-    threadArgs->keepWritingInputFMQ = &mKeepWritingInputFMQ;
-
-    pthread_create(&mInputThread, NULL, __threadLoopInput, (void*)threadArgs);
-    pthread_setname_np(mInputThread, "test_playback_input_loop");
-}
-
-void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) {
+void FilterCallback::startFilterEventThread(DemuxFilterEvent event) {
     struct FilterThreadArgs* threadArgs =
             (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
     threadArgs->user = this;
@@ -326,7 +294,7 @@
     pthread_setname_np(mFilterThread, "test_playback_input_loop");
 }
 
-void DemuxCallback::testFilterDataOutput() {
+void FilterCallback::testFilterDataOutput() {
     android::Mutex::Autolock autoLock(mMsgLock);
     while (mPidFilterOutputCount < 1) {
         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
@@ -338,95 +306,25 @@
     ALOGW("[vts] pass and stop");
 }
 
-void DemuxCallback::stopInputThread() {
-    mInputThreadRunning = false;
-    mKeepWritingInputFMQ = false;
-
-    android::Mutex::Autolock autoLock(mInputThreadLock);
+void FilterCallback::updateFilterMQ(MQDesc& filterMQDescriptor) {
+    mFilterIdToMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mFilterIdToMQ);
+    EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ->getEventFlagWord(),
+                                           &mFilterIdToMQEventFlag) == android::OK);
 }
 
-void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) {
-    mFilterIdToMQ[filterId] =
-            std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mFilterIdToMQ[filterId]);
-    EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(),
-                                           &mFilterIdToMQEventFlag[filterId]) == android::OK);
+void FilterCallback::updateGoldenOutputMap(string goldenOutputFile) {
+    mFilterIdToGoldenOutput = goldenOutputFile;
 }
 
-void DemuxCallback::updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile) {
-    mFilterIdToGoldenOutput[filterId] = goldenOutputFile;
-}
-
-void* DemuxCallback::__threadLoopInput(void* threadArgs) {
-    DemuxCallback* const self =
-            static_cast<DemuxCallback*>(((struct InputThreadArgs*)threadArgs)->user);
-    self->inputThreadLoop(((struct InputThreadArgs*)threadArgs)->inputConf,
-                          ((struct InputThreadArgs*)threadArgs)->keepWritingInputFMQ);
-    return 0;
-}
-
-void DemuxCallback::inputThreadLoop(InputConf* inputConf, bool* keepWritingInputFMQ) {
-    android::Mutex::Autolock autoLock(mInputThreadLock);
-    mInputThreadRunning = true;
-
-    // Create the EventFlag that is used to signal the HAL impl that data have been
-    // written into the Input FMQ
-    EventFlag* inputMQEventFlag;
-    EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &inputMQEventFlag) ==
-                android::OK);
-
-    // open the stream and get its length
-    std::ifstream inputData(inputConf->inputDataFile, std::ifstream::binary);
-    int writeSize = inputConf->setting.packetSize * 6;
-    char* buffer = new char[writeSize];
-    ALOGW("[vts] input thread loop start %s", inputConf->inputDataFile.c_str());
-    if (!inputData.is_open()) {
-        mInputThreadRunning = false;
-        ALOGW("[vts] Error %s", strerror(errno));
-    }
-
-    while (mInputThreadRunning) {
-        // move the stream pointer for packet size * 6 every read until the end
-        while (*keepWritingInputFMQ) {
-            inputData.read(buffer, writeSize);
-            if (!inputData) {
-                int leftSize = inputData.gcount();
-                if (leftSize == 0) {
-                    mInputThreadRunning = false;
-                    break;
-                }
-                inputData.clear();
-                inputData.read(buffer, leftSize);
-                // Write the left over of the input data and quit the thread
-                if (leftSize > 0) {
-                    EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], leftSize));
-                    inputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
-                }
-                mInputThreadRunning = false;
-                break;
-            }
-            // Write input FMQ and notify the Tuner Implementation
-            EXPECT_TRUE(mInputMQ->write((unsigned char*)&buffer[0], writeSize));
-            inputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
-            inputData.seekg(writeSize, inputData.cur);
-            sleep(1);
-        }
-    }
-
-    ALOGW("[vts] Input thread end.");
-
-    delete[] buffer;
-    inputData.close();
-}
-
-void* DemuxCallback::__threadLoopFilter(void* threadArgs) {
-    DemuxCallback* const self =
-            static_cast<DemuxCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
+void* FilterCallback::__threadLoopFilter(void* threadArgs) {
+    FilterCallback* const self =
+            static_cast<FilterCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
     self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
     return 0;
 }
 
-void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
+void FilterCallback::filterThreadLoop(DemuxFilterEvent& /* event */) {
     android::Mutex::Autolock autoLock(mFilterOutputLock);
     // Read from mFilterIdToMQ[event.filterId] per event and filter type
 
@@ -439,30 +337,184 @@
     // end thread
 }
 
-bool DemuxCallback::readFilterEventData(uint32_t filterId) {
+bool FilterCallback::readFilterEventData() {
     bool result = false;
-    DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId];
-    ALOGW("[vts] reading from filter FMQ %d", filterId);
+    DemuxFilterEvent filterEvent = mFilterIdToEvent;
+    ALOGW("[vts] reading from filter FMQ %d", mFilterId);
     // todo separate filter handlers
     for (int i = 0; i < filterEvent.events.size(); i++) {
-        DemuxFilterPesEvent event = filterEvent.events[i].pes();
-        mDataLength = event.dataLength;
+        switch (mFilterEventType) {
+            case FilterEventType::SECTION:
+                mDataLength = filterEvent.events[i].section().dataLength;
+                break;
+            case FilterEventType::PES:
+                mDataLength = filterEvent.events[i].pes().dataLength;
+                break;
+            case FilterEventType::MEDIA:
+                break;
+            case FilterEventType::RECORD:
+                break;
+            case FilterEventType::MMTPRECORD:
+                break;
+            case FilterEventType::DOWNLOAD:
+                break;
+            default:
+                break;
+        }
         // EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not
         // match";
 
         mDataOutputBuffer.resize(mDataLength);
-        result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength);
+        result = mFilterIdToMQ->read(mDataOutputBuffer.data(), mDataLength);
         EXPECT_TRUE(result) << "can't read from Filter MQ";
 
         /*for (int i = 0; i < mDataLength; i++) {
             EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
         }*/
     }
-    mFilterIdToMQEventFlag[filterId]->wake(
-            static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+    mFilterIdToMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
     return result;
 }
 
+class DvrCallback : public IDvrCallback {
+  public:
+    virtual Return<void> onRecordStatus(RecordStatus /*status*/) override { return Void(); }
+
+    virtual Return<void> onPlaybackStatus(PlaybackStatus status) override {
+        // android::Mutex::Autolock autoLock(mMsgLock);
+        ALOGW("[vts] playback status %d", status);
+        switch (status) {
+            case PlaybackStatus::SPACE_EMPTY:
+            case PlaybackStatus::SPACE_ALMOST_EMPTY:
+                ALOGW("[vts] keep playback inputing %d", status);
+                mKeepWritingPlaybackFMQ = true;
+                break;
+            case PlaybackStatus::SPACE_ALMOST_FULL:
+            case PlaybackStatus::SPACE_FULL:
+                ALOGW("[vts] stop playback inputing %d", status);
+                mKeepWritingPlaybackFMQ = false;
+                break;
+        }
+        return Void();
+    }
+
+    void testFilterDataOutput();
+    void stopPlaybackThread();
+
+    void startPlaybackInputThread(PlaybackConf playbackConf, MQDesc& playbackMQDescriptor);
+    static void* __threadLoopPlayback(void* threadArgs);
+    void playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ);
+
+  private:
+    struct PlaybackThreadArgs {
+        DvrCallback* user;
+        PlaybackConf* playbackConf;
+        bool* keepWritingPlaybackFMQ;
+    };
+    uint16_t mDataLength = 0;
+    std::vector<uint8_t> mDataOutputBuffer;
+
+    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
+    std::unique_ptr<FilterMQ> mPlaybackMQ;
+    std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
+    std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
+    EventFlag* mPlaybackMQEventFlag;
+
+    android::Mutex mMsgLock;
+    android::Mutex mPlaybackThreadLock;
+    android::Condition mMsgCondition;
+
+    bool mKeepWritingPlaybackFMQ = true;
+    bool mPlaybackThreadRunning;
+    pthread_t mPlaybackThread;
+
+    int mPidFilterOutputCount = 0;
+};
+
+void DvrCallback::startPlaybackInputThread(PlaybackConf playbackConf,
+                                           MQDesc& playbackMQDescriptor) {
+    mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mPlaybackMQ);
+    struct PlaybackThreadArgs* threadArgs =
+            (struct PlaybackThreadArgs*)malloc(sizeof(struct PlaybackThreadArgs));
+    threadArgs->user = this;
+    threadArgs->playbackConf = &playbackConf;
+    threadArgs->keepWritingPlaybackFMQ = &mKeepWritingPlaybackFMQ;
+
+    pthread_create(&mPlaybackThread, NULL, __threadLoopPlayback, (void*)threadArgs);
+    pthread_setname_np(mPlaybackThread, "test_playback_input_loop");
+}
+
+void DvrCallback::stopPlaybackThread() {
+    mPlaybackThreadRunning = false;
+    mKeepWritingPlaybackFMQ = false;
+
+    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+}
+
+void* DvrCallback::__threadLoopPlayback(void* threadArgs) {
+    DvrCallback* const self =
+            static_cast<DvrCallback*>(((struct PlaybackThreadArgs*)threadArgs)->user);
+    self->playbackThreadLoop(((struct PlaybackThreadArgs*)threadArgs)->playbackConf,
+                             ((struct PlaybackThreadArgs*)threadArgs)->keepWritingPlaybackFMQ);
+    return 0;
+}
+
+void DvrCallback::playbackThreadLoop(PlaybackConf* playbackConf, bool* keepWritingPlaybackFMQ) {
+    android::Mutex::Autolock autoLock(mPlaybackThreadLock);
+    mPlaybackThreadRunning = true;
+
+    // Create the EventFlag that is used to signal the HAL impl that data have been
+    // written into the Playback FMQ
+    EventFlag* playbackMQEventFlag;
+    EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
+                android::OK);
+
+    // open the stream and get its length
+    std::ifstream inputData(playbackConf->inputDataFile, std::ifstream::binary);
+    int writeSize = playbackConf->setting.packetSize * 6;
+    char* buffer = new char[writeSize];
+    ALOGW("[vts] playback thread loop start %s", playbackConf->inputDataFile.c_str());
+    if (!inputData.is_open()) {
+        mPlaybackThreadRunning = false;
+        ALOGW("[vts] Error %s", strerror(errno));
+    }
+
+    while (mPlaybackThreadRunning) {
+        // move the stream pointer for packet size * 6 every read until the end
+        while (*keepWritingPlaybackFMQ) {
+            inputData.read(buffer, writeSize);
+            if (!inputData) {
+                int leftSize = inputData.gcount();
+                if (leftSize == 0) {
+                    mPlaybackThreadRunning = false;
+                    break;
+                }
+                inputData.clear();
+                inputData.read(buffer, leftSize);
+                // Write the left over of the input data and quit the thread
+                if (leftSize > 0) {
+                    EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize));
+                    playbackMQEventFlag->wake(
+                            static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+                }
+                mPlaybackThreadRunning = false;
+                break;
+            }
+            // Write input FMQ and notify the Tuner Implementation
+            EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize));
+            playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+            inputData.seekg(writeSize, inputData.cur);
+            sleep(1);
+        }
+    }
+
+    ALOGW("[vts] Playback thread end.");
+
+    delete[] buffer;
+    inputData.close();
+}
+
 // Test environment for Tuner HIDL HAL.
 class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
   public:
@@ -494,16 +546,21 @@
     sp<FrontendCallback> mFrontendCallback;
     sp<IDescrambler> mDescrambler;
     sp<IDemux> mDemux;
-    sp<DemuxCallback> mDemuxCallback;
+    sp<IDvr> mDvr;
+    sp<IFilter> mFilter;
+    std::map<uint32_t, sp<IFilter>> mFilters;
+    std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks;
+    sp<FilterCallback> mFilterCallback;
+    sp<DvrCallback> mDvrCallback;
     MQDesc mFilterMQDescriptor;
-    MQDesc mInputMQDescriptor;
+    MQDesc mPlaybackMQDescriptor;
     vector<uint32_t> mUsedFilterIds;
 
     uint32_t mDemuxId;
     uint32_t mFilterId;
 
-    pthread_t mInputThread;
-    bool mInputThreadRunning;
+    pthread_t mPlaybackshread;
+    bool mPlaybackThreadRunning;
 
     ::testing::AssertionResult createFrontend(int32_t frontendId);
     ::testing::AssertionResult tuneFrontend(int32_t frontendId);
@@ -512,16 +569,16 @@
     ::testing::AssertionResult createDemux();
     ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId,
                                                        FrontendSettings settings);
-    ::testing::AssertionResult getInputMQDescriptor();
-    ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting);
+    ::testing::AssertionResult getPlaybackMQDescriptor();
+    ::testing::AssertionResult addPlaybackToDemux(PlaybackSettings setting);
     ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
-    ::testing::AssertionResult getFilterMQDescriptor(const uint32_t filterId);
+    ::testing::AssertionResult getFilterMQDescriptor();
     ::testing::AssertionResult closeDemux();
     ::testing::AssertionResult createDescrambler();
     ::testing::AssertionResult closeDescrambler();
 
     ::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
-                                                    InputConf inputConf,
+                                                    PlaybackConf playbackConf,
                                                     vector<string> goldenOutputFiles);
     ::testing::AssertionResult broadcastDataFlowTest(vector<FilterConf> filterConf,
                                                      vector<string> goldenOutputFiles);
@@ -665,39 +722,43 @@
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
-::testing::AssertionResult TunerHidlTest::addInputToDemux(DemuxInputSettings setting) {
+::testing::AssertionResult TunerHidlTest::addPlaybackToDemux(PlaybackSettings setting) {
     Result status;
 
     if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
 
-    // Create demux callback
-    if (!mDemuxCallback) {
-        mDemuxCallback = new DemuxCallback();
-    }
+    // Create dvr callback
+    mDvrCallback = new DvrCallback();
 
     // Add playback input to the local demux
-    status = mDemux->addInput(FMQ_SIZE_1M, mDemuxCallback);
+    mDemux->openDvr(DvrType::PLAYBACK, FMQ_SIZE_1M, mDvrCallback,
+                    [&](Result result, const sp<IDvr>& dvr) {
+                        mDvr = dvr;
+                        status = result;
+                    });
 
     if (status != Result::SUCCESS) {
         return ::testing::AssertionFailure();
     }
 
-    status = mDemux->configureInput(setting);
+    DvrSettings dvrSetting;
+    dvrSetting.playback(setting);
+    status = mDvr->configure(dvrSetting);
 
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
-::testing::AssertionResult TunerHidlTest::getInputMQDescriptor() {
+::testing::AssertionResult TunerHidlTest::getPlaybackMQDescriptor() {
     Result status;
 
-    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+    if ((!mDemux && createDemux() == ::testing::AssertionFailure()) || !mDvr) {
         return ::testing::AssertionFailure();
     }
 
-    mDemux->getInputQueueDesc([&](Result result, const MQDesc& inputMQDesc) {
-        mInputMQDescriptor = inputMQDesc;
+    mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mPlaybackMQDescriptor = dvrMQDesc;
         status = result;
     });
 
@@ -713,13 +774,20 @@
     }
 
     // Create demux callback
-    if (!mDemuxCallback) {
-        mDemuxCallback = new DemuxCallback();
-    }
+    mFilterCallback = new FilterCallback();
 
     // Add filter to the local demux
-    mDemux->addFilter(type, FMQ_SIZE_4K, mDemuxCallback, [&](Result result, uint32_t filterId) {
-        // TODO use a map to save all the filter id and FMQ
+    mDemux->openFilter(type, FMQ_SIZE_16M, mFilterCallback,
+                       [&](Result result, const sp<IFilter>& filter) {
+                           mFilter = filter;
+                           status = result;
+                       });
+
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    mFilter->getId([&](Result result, uint32_t filterId) {
         mFilterId = filterId;
         status = result;
     });
@@ -728,20 +796,64 @@
         return ::testing::AssertionFailure();
     }
 
+    mFilterCallback->setFilterId(mFilterId);
+
+    FilterEventType eventType = FilterEventType::UNDEFINED;
+    switch (type.mainType) {
+        case DemuxFilterMainType::TS:
+            switch (type.subType.tsFilterType()) {
+                case DemuxTsFilterType::UNDEFINED:
+                    break;
+                case DemuxTsFilterType::SECTION:
+                    eventType = FilterEventType::SECTION;
+                    break;
+                case DemuxTsFilterType::PES:
+                    eventType = FilterEventType::PES;
+                    break;
+                case DemuxTsFilterType::TS:
+                    break;
+                case DemuxTsFilterType::AUDIO:
+                case DemuxTsFilterType::VIDEO:
+                    eventType = FilterEventType::MEDIA;
+                    break;
+                case DemuxTsFilterType::PCR:
+                    break;
+                case DemuxTsFilterType::RECORD:
+                    eventType = FilterEventType::RECORD;
+                    break;
+            }
+            break;
+        case DemuxFilterMainType::MMTP:
+            /*mmtpSettings*/
+            break;
+        case DemuxFilterMainType::IP:
+            /*ipSettings*/
+            break;
+        case DemuxFilterMainType::TLV:
+            /*tlvSettings*/
+            break;
+        case DemuxFilterMainType::ALP:
+            /*alpSettings*/
+            break;
+        default:
+            break;
+    }
+    mFilterCallback->setFilterEventType(eventType);
+
     // Configure the filter
-    status = mDemux->configureFilter(mFilterId, setting);
+    status = mFilter->configure(setting);
 
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
-::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(const uint32_t filterId) {
+::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor() {
     Result status;
 
-    if (!mDemux) {
+    if (!mDemux || !mFilter) {
         return ::testing::AssertionFailure();
     }
 
-    mDemux->getFilterQueueDesc(filterId, [&](Result result, const MQDesc& filterMQDesc) {
+    mFilter->getQueueDesc([&](Result result, const MQDesc& filterMQDesc) {
         mFilterMQDescriptor = filterMQDesc;
         status = result;
     });
@@ -750,7 +862,8 @@
 }
 
 ::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(
-        vector<FilterConf> filterConf, InputConf inputConf, vector<string> /*goldenOutputFiles*/) {
+        vector<FilterConf> filterConf, PlaybackConf playbackConf,
+        vector<string> /*goldenOutputFiles*/) {
     Result status;
     int filterIdsSize;
     // Filter Configuration Module
@@ -758,45 +871,58 @@
         if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
                     ::testing::AssertionFailure() ||
             // TODO use a map to save the FMQs/EvenFlags and pass to callback
-            getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) {
+            getFilterMQDescriptor() == ::testing::AssertionFailure()) {
             return ::testing::AssertionFailure();
         }
         filterIdsSize = mUsedFilterIds.size();
         mUsedFilterIds.resize(filterIdsSize + 1);
         mUsedFilterIds[filterIdsSize] = mFilterId;
-        mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor);
-        // mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]);
-        status = mDemux->startFilter(mFilterId);
+        mFilters[mFilterId] = mFilter;
+        mFilterCallbacks[mFilterId] = mFilterCallback;
+        mFilterCallback->updateFilterMQ(mFilterMQDescriptor);
+        // mDemuxCallback->updateGoldenOutputMap(goldenOutputFiles[i]);
+        status = mFilter->start();
         if (status != Result::SUCCESS) {
             return ::testing::AssertionFailure();
         }
     }
 
     // Playback Input Module
-    DemuxInputSettings inputSetting = inputConf.setting;
-    if (addInputToDemux(inputSetting) == ::testing::AssertionFailure() ||
-        getInputMQDescriptor() == ::testing::AssertionFailure()) {
+    PlaybackSettings playbackSetting = playbackConf.setting;
+    if (addPlaybackToDemux(playbackSetting) == ::testing::AssertionFailure() ||
+        getPlaybackMQDescriptor() == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
-    mDemuxCallback->startPlaybackInputThread(inputConf, mInputMQDescriptor);
-    status = mDemux->startInput();
+    for (int i = 0; i <= filterIdsSize; i++) {
+        if (mDvr->attachFilter(mFilters[mUsedFilterIds[i]]) != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+    mDvrCallback->startPlaybackInputThread(playbackConf, mPlaybackMQDescriptor);
+    status = mDvr->start();
     if (status != Result::SUCCESS) {
         return ::testing::AssertionFailure();
     }
 
     // Data Verify Module
-    mDemuxCallback->testFilterDataOutput();
-    mDemuxCallback->stopInputThread();
+    std::map<uint32_t, sp<FilterCallback>>::iterator it;
+    for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
+        it->second->testFilterDataOutput();
+    }
+    mDvrCallback->stopPlaybackThread();
 
     // Clean Up Module
     for (int i = 0; i <= filterIdsSize; i++) {
-        if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) {
+        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
             return ::testing::AssertionFailure();
         }
     }
-    if (mDemux->stopInput() != Result::SUCCESS) {
+    if (mDvr->stop() != Result::SUCCESS) {
         return ::testing::AssertionFailure();
     }
+    mUsedFilterIds.clear();
+    mFilterCallbacks.clear();
+    mFilters.clear();
     return closeDemux();
 }
 
@@ -831,31 +957,39 @@
         if (addFilterToDemux(filterConf[i].type, filterConf[i].setting) ==
                     ::testing::AssertionFailure() ||
             // TODO use a map to save the FMQs/EvenFlags and pass to callback
-            getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure()) {
+            getFilterMQDescriptor() == ::testing::AssertionFailure()) {
             return ::testing::AssertionFailure();
         }
         filterIdsSize = mUsedFilterIds.size();
         mUsedFilterIds.resize(filterIdsSize + 1);
         mUsedFilterIds[filterIdsSize] = mFilterId;
-        mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor);
-        status = mDemux->startFilter(mFilterId);
+        mFilters[mFilterId] = mFilter;
+        mFilterCallbacks[mFilterId] = mFilterCallback;
+        mFilterCallback->updateFilterMQ(mFilterMQDescriptor);
+        status = mFilter->start();
         if (status != Result::SUCCESS) {
             return ::testing::AssertionFailure();
         }
     }
 
     // Data Verify Module
-    mDemuxCallback->testFilterDataOutput();
+    std::map<uint32_t, sp<FilterCallback>>::iterator it;
+    for (it = mFilterCallbacks.begin(); it != mFilterCallbacks.end(); it++) {
+        it->second->testFilterDataOutput();
+    }
 
     // Clean Up Module
     for (int i = 0; i <= filterIdsSize; i++) {
-        if (mDemux->stopFilter(mUsedFilterIds[i]) != Result::SUCCESS) {
+        if (mFilters[mUsedFilterIds[i]]->stop() != Result::SUCCESS) {
             return ::testing::AssertionFailure();
         }
     }
     if (mFrontend->stopTune() != Result::SUCCESS) {
         return ::testing::AssertionFailure();
     }
+    mUsedFilterIds.clear();
+    mFilterCallbacks.clear();
+    mFilters.clear();
     return closeDemux();
 }
 
@@ -992,7 +1126,7 @@
 /*
  * DATA FLOW TESTS
  */
-TEST_F(TunerHidlTest, PlaybackDataFlowWithPesFilterTest) {
+TEST_F(TunerHidlTest, PlaybackDataFlowWithSectionFilterTest) {
     description("Feed ts data from playback and configure pes filter to get output");
 
     // todo modulize the filter conf parser
@@ -1000,32 +1134,39 @@
     filterConf.resize(1);
 
     DemuxFilterSettings filterSetting;
-    DemuxFilterPesDataSettings pesFilterSetting{
+    DemuxTsFilterSettings tsFilterSetting{
             .tpid = 18,
     };
-    filterSetting.pesData(pesFilterSetting);
-    FilterConf pesFilterConf{
-            .type = DemuxFilterType::PES,
+    DemuxFilterSectionSettings sectionFilterSetting;
+    tsFilterSetting.filterSettings.section(sectionFilterSetting);
+    filterSetting.ts(tsFilterSetting);
+
+    DemuxFilterType type{
+            .mainType = DemuxFilterMainType::TS,
+    };
+    type.subType.tsFilterType(DemuxTsFilterType::SECTION);
+    FilterConf sectionFilterConf{
+            .type = type,
             .setting = filterSetting,
     };
-    filterConf[0] = pesFilterConf;
+    filterConf[0] = sectionFilterConf;
 
-    DemuxInputSettings inputSetting{
+    PlaybackSettings playbackSetting{
             .statusMask = 0xf,
             .lowThreshold = 0x1000,
             .highThreshold = 0x07fff,
-            .dataFormat = DemuxDataFormat::TS,
+            .dataFormat = DataFormat::TS,
             .packetSize = 188,
     };
 
-    InputConf inputConf{
+    PlaybackConf playbackConf{
             .inputDataFile = "/vendor/etc/test1.ts",
-            .setting = inputSetting,
+            .setting = playbackSetting,
     };
 
     vector<string> goldenOutputFiles;
 
-    ASSERT_TRUE(playbackDataFlowTest(filterConf, inputConf, goldenOutputFiles));
+    ASSERT_TRUE(playbackDataFlowTest(filterConf, playbackConf, goldenOutputFiles));
 }
 
 TEST_F(TunerHidlTest, BroadcastDataFlowWithPesFilterTest) {
@@ -1036,12 +1177,19 @@
     filterConf.resize(1);
 
     DemuxFilterSettings filterSetting;
-    DemuxFilterPesDataSettings pesFilterSetting{
-            .tpid = 18,
+    DemuxTsFilterSettings tsFilterSetting{
+            .tpid = 119,
     };
-    filterSetting.pesData(pesFilterSetting);
+    DemuxFilterPesDataSettings pesFilterSetting;
+    tsFilterSetting.filterSettings.pesData(pesFilterSetting);
+    filterSetting.ts(tsFilterSetting);
+
+    DemuxFilterType type{
+            .mainType = DemuxFilterMainType::TS,
+    };
+    type.subType.tsFilterType(DemuxTsFilterType::PES);
     FilterConf pesFilterConf{
-            .type = DemuxFilterType::PES,
+            .type = type,
             .setting = filterSetting,
     };
     filterConf[0] = pesFilterConf;
diff --git a/vibrator/staidl/Android.bp b/vibrator/staidl/Android.bp
new file mode 100644
index 0000000..18468ef
--- /dev/null
+++ b/vibrator/staidl/Android.bp
@@ -0,0 +1,14 @@
+aidl_interface {
+    name: "vintf-vibrator",
+    vendor_available: true,
+    srcs: [
+        "android/hardware/vibrator/*.aidl",
+    ],
+    stability: "vintf",
+    backend: {
+        java: {
+            enabled: false,
+        },
+    },
+}
+
diff --git a/vibrator/staidl/android/hardware/vibrator/Effect.aidl b/vibrator/staidl/android/hardware/vibrator/Effect.aidl
new file mode 100644
index 0000000..c60bfe9
--- /dev/null
+++ b/vibrator/staidl/android/hardware/vibrator/Effect.aidl
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+@Backing(type="int")
+enum Effect {
+    /**
+     * A single click effect.
+     *
+     * This effect should produce a sharp, crisp click sensation.
+     */
+    CLICK,
+    /**
+     * A double click effect.
+     *
+     * This effect should produce two sequential sharp, crisp click sensations with a minimal
+     * amount of time between them.
+     */
+    DOUBLE_CLICK,
+    /**
+     * A tick effect.
+     *
+     * This effect should produce a soft, short sensation, like the tick of a clock.
+     */
+    TICK,
+    /**
+     * A thud effect.
+     *
+     * This effect should solid feeling bump, like the depression of a heavy mechanical button.
+     */
+    THUD,
+    /**
+     * A pop effect.
+     *
+     * A short, quick burst effect.
+     */
+    POP,
+    /**
+     * A heavy click effect.
+     *
+     * This should produce a sharp striking sensation, like a click but stronger.
+     */
+    HEAVY_CLICK,
+    /**
+     * Ringtone patterns. They may correspond with the device's ringtone audio, or may just be a
+     * pattern that can be played as a ringtone with any audio, depending on the device.
+     */
+    RINGTONE_1,
+    RINGTONE_2,
+    RINGTONE_3,
+    RINGTONE_4,
+    RINGTONE_5,
+    RINGTONE_6,
+    RINGTONE_7,
+    RINGTONE_8,
+    RINGTONE_9,
+    RINGTONE_10,
+    RINGTONE_11,
+    RINGTONE_12,
+    RINGTONE_13,
+    RINGTONE_14,
+    RINGTONE_15,
+    /**
+     * A soft tick effect meant to be played as a texture.
+     *
+     * A soft, short sensation like the tick of a clock. Unlike regular effects, texture effects
+     * are expected to be played multiple times in quick succession, replicating a specific
+     * texture to the user as a form of haptic feedback.
+     */
+    TEXTURE_TICK,
+}
diff --git a/vibrator/staidl/android/hardware/vibrator/EffectStrength.aidl b/vibrator/staidl/android/hardware/vibrator/EffectStrength.aidl
new file mode 100644
index 0000000..66f70e5
--- /dev/null
+++ b/vibrator/staidl/android/hardware/vibrator/EffectStrength.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+@Backing(type="byte")
+enum EffectStrength {
+    LIGHT,
+    MEDIUM,
+    STRONG,
+}
diff --git a/vibrator/staidl/android/hardware/vibrator/IVibrator.aidl b/vibrator/staidl/android/hardware/vibrator/IVibrator.aidl
new file mode 100644
index 0000000..b2008f4
--- /dev/null
+++ b/vibrator/staidl/android/hardware/vibrator/IVibrator.aidl
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.vibrator;
+
+import android.hardware.vibrator.IVibratorCallback;
+import android.hardware.vibrator.Effect;
+import android.hardware.vibrator.EffectStrength;
+
+@VintfStability
+interface IVibrator {
+    /**
+     * Whether on w/ IVibratorCallback can be used w/ 'on' function
+     */
+    const int CAP_ON_CALLBACK = 1 << 0;
+    /**
+     * Whether on w/ IVibratorCallback can be used w/ 'perform' function
+     */
+    const int CAP_PERFORM_CALLBACK = 1 << 1;
+    /**
+     * Whether setAmplitude is supported.
+     */
+    const int CAP_AMPLITUDE_CONTROL = 1 << 2;
+    /**
+     * Whether setExternalControl is supported.
+     */
+    const int CAP_EXTERNAL_CONTROL = 1 << 3;
+
+    /**
+     * Determine capabilities of the vibrator HAL (CAP_* values)
+     */
+    int getCapabilities();
+
+    /**
+     * Turn off vibrator
+     *
+     * Cancel a previously-started vibration, if any.
+     */
+    void off();
+
+    /**
+     * Turn on vibrator
+     *
+     * This function must only be called after the previous timeout has expired or
+     * was canceled (through off()).
+     * @param timeoutMs number of milliseconds to vibrate.
+     * @param callback A callback used to inform Frameworks of state change, if supported.
+     */
+    void on(in int timeoutMs, in IVibratorCallback callback);
+
+    /**
+     * Fire off a predefined haptic event.
+     *
+     * @param effect The type of haptic event to trigger.
+     * @param strength The intensity of haptic event to trigger.
+     * @param callback A callback used to inform Frameworks of state change, if supported.
+     * @return The length of time the event is expected to take in
+     *     milliseconds. This doesn't need to be perfectly accurate, but should be a reasonable
+     *     approximation.
+     */
+    int perform(in Effect effect, in EffectStrength strength, in IVibratorCallback callback);
+
+    /**
+     * Sets the motor's vibrational amplitude.
+     *
+     * Changes the force being produced by the underlying motor.
+     *
+     * @param amplitude The unitless force setting. Note that this number must
+     *                  be between 1 and 255, inclusive. If the motor does not
+     *                  have exactly 255 steps, it must do it's best to map it
+     *                  onto the number of steps it does have.
+     */
+    void setAmplitude(in int amplitude);
+
+    /**
+     * Enables/disables control override of vibrator to audio.
+     *
+     * When this API is set, the vibrator control should be ceded to audio system
+     * for haptic audio. While this is enabled, issuing of other commands to control
+     * the vibrator is unsupported and the resulting behavior is undefined. Amplitude
+     * control may or may not be supported and is reflected in the return value of
+     * supportsAmplitudeControl() while this is enabled. When this is disabled, the
+     * vibrator should resume to an off state.
+     *
+     * @param enabled Whether external control should be enabled or disabled.
+     */
+    void setExternalControl(in boolean enabled);
+}
diff --git a/vibrator/staidl/android/hardware/vibrator/IVibratorCallback.aidl b/vibrator/staidl/android/hardware/vibrator/IVibratorCallback.aidl
new file mode 100644
index 0000000..43859de
--- /dev/null
+++ b/vibrator/staidl/android/hardware/vibrator/IVibratorCallback.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+package android.hardware.vibrator;
+
+@VintfStability
+interface IVibratorCallback {
+    oneway void onComplete();
+}
diff --git a/vibrator/staidl/default/Android.bp b/vibrator/staidl/default/Android.bp
new file mode 100644
index 0000000..f399887
--- /dev/null
+++ b/vibrator/staidl/default/Android.bp
@@ -0,0 +1,13 @@
+cc_binary {
+    name: "android.hardware.vibrator-service.example",
+    relative_install_path: "hw",
+    init_rc: ["vibrator-default.rc"],
+    vintf_fragments: ["vibrator-default.xml"],
+    vendor: true,
+    shared_libs: [
+        "libbase",
+        "libbinder_ndk",
+        "vintf-vibrator-ndk_platform",
+    ],
+    srcs: ["main.cpp", "Vibrator.cpp"],
+}
diff --git a/vibrator/staidl/default/Vibrator.cpp b/vibrator/staidl/default/Vibrator.cpp
new file mode 100644
index 0000000..cdf8e09
--- /dev/null
+++ b/vibrator/staidl/default/Vibrator.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "Vibrator.h"
+
+#include <android-base/logging.h>
+#include <thread>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+ndk::ScopedAStatus Vibrator::getCapabilities(int32_t* _aidl_return) {
+    LOG(INFO) << "Vibrator reporting capabilities";
+    *_aidl_return = IVibrator::CAP_ON_CALLBACK | IVibrator::CAP_PERFORM_CALLBACK |
+                    IVibrator::CAP_AMPLITUDE_CONTROL | IVibrator::CAP_EXTERNAL_CONTROL;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::off() {
+    LOG(INFO) << "Vibrator off";
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::on(int32_t timeoutMs,
+                                const std::shared_ptr<IVibratorCallback>& callback) {
+    LOG(INFO) << "Vibrator on for timeoutMs: " << timeoutMs;
+    if (callback != nullptr) {
+        std::thread([=] {
+            LOG(INFO) << "Starting on on another thread";
+            usleep(timeoutMs * 1000);
+            LOG(INFO) << "Notifying on complete";
+            callback->onComplete();
+        }).detach();
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::perform(Effect effect, EffectStrength strength,
+                                     const std::shared_ptr<IVibratorCallback>& callback,
+                                     int32_t* _aidl_return) {
+    LOG(INFO) << "Vibrator perform";
+
+    if (effect != Effect::CLICK && effect != Effect::TICK) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+    if (strength != EffectStrength::LIGHT && strength != EffectStrength::MEDIUM &&
+        strength != EffectStrength::STRONG) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION));
+    }
+
+    constexpr size_t kEffectMillis = 100;
+
+    if (callback != nullptr) {
+        std::thread([=] {
+            LOG(INFO) << "Starting perform on another thread";
+            usleep(kEffectMillis * 1000);
+            LOG(INFO) << "Notifying perform complete";
+            callback->onComplete();
+        }).detach();
+    }
+
+    *_aidl_return = kEffectMillis;
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setAmplitude(int32_t amplitude) {
+    LOG(INFO) << "Vibrator set amplitude: " << amplitude;
+    if (amplitude <= 0 || amplitude > 255) {
+        return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT));
+    }
+    return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus Vibrator::setExternalControl(bool enabled) {
+    LOG(INFO) << "Vibrator set external control: " << enabled;
+    return ndk::ScopedAStatus::ok();
+}
+
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/vibrator/staidl/default/Vibrator.h b/vibrator/staidl/default/Vibrator.h
new file mode 100644
index 0000000..77e96e3
--- /dev/null
+++ b/vibrator/staidl/default/Vibrator.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/vibrator/BnVibrator.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace vibrator {
+
+class Vibrator : public BnVibrator {
+    ndk::ScopedAStatus getCapabilities(int32_t* _aidl_return) override;
+    ndk::ScopedAStatus off() override;
+    ndk::ScopedAStatus on(int32_t timeoutMs,
+                          const std::shared_ptr<IVibratorCallback>& callback) override;
+    ndk::ScopedAStatus perform(Effect effect, EffectStrength strength,
+                               const std::shared_ptr<IVibratorCallback>& callback,
+                               int32_t* _aidl_return) override;
+    ndk::ScopedAStatus setAmplitude(int32_t amplitude) override;
+    ndk::ScopedAStatus setExternalControl(bool enabled) override;
+};
+
+}  // namespace vibrator
+}  // namespace hardware
+}  // namespace android
+}  // namespace aidl
diff --git a/vibrator/staidl/default/main.cpp b/vibrator/staidl/default/main.cpp
new file mode 100644
index 0000000..d1619ff
--- /dev/null
+++ b/vibrator/staidl/default/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#include "Vibrator.h"
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+using aidl::android::hardware::vibrator::Vibrator;
+
+int main() {
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+    std::shared_ptr<Vibrator> vib = ndk::SharedRefBase::make<Vibrator>();
+
+    const std::string instance = std::string() + Vibrator::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(vib->asBinder().get(), instance.c_str());
+    CHECK(status == STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return EXIT_FAILURE;  // should not reach
+}
diff --git a/vibrator/staidl/default/vibrator-default.rc b/vibrator/staidl/default/vibrator-default.rc
new file mode 100644
index 0000000..d17f468
--- /dev/null
+++ b/vibrator/staidl/default/vibrator-default.rc
@@ -0,0 +1,4 @@
+service vendor.vibrator-default /vendor/bin/hw/android.hardware.vibrator-service.example
+    class hal
+    user system
+    group system
diff --git a/vibrator/staidl/default/vibrator-default.xml b/vibrator/staidl/default/vibrator-default.xml
new file mode 100644
index 0000000..49b11ec
--- /dev/null
+++ b/vibrator/staidl/default/vibrator-default.xml
@@ -0,0 +1,6 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.vibrator</name>
+        <fqname>IVibrator/default</fqname>
+    </hal>
+</manifest>
diff --git a/vibrator/staidl/vts/Android.bp b/vibrator/staidl/vts/Android.bp
new file mode 100644
index 0000000..20d53c7
--- /dev/null
+++ b/vibrator/staidl/vts/Android.bp
@@ -0,0 +1,17 @@
+cc_test {
+    name: "VtsHalVibratorTargetTest",
+    defaults: [
+        "VtsHalTargetTestDefaults",
+        "use_libaidlvintf_gtest_helper_static",
+    ],
+    srcs: ["VtsHalVibratorTargetTest.cpp"],
+    shared_libs: [
+        "libbinder",
+    ],
+    static_libs: [
+        "vintf-vibrator-cpp",
+    ],
+    test_suites: [
+        "vts-core",
+    ],
+}
diff --git a/vibrator/staidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/staidl/vts/VtsHalVibratorTargetTest.cpp
new file mode 100644
index 0000000..33bcaf5
--- /dev/null
+++ b/vibrator/staidl/vts/VtsHalVibratorTargetTest.cpp
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+#include <aidl/Gtest.h>
+#include <aidl/Vintf.h>
+
+#include <android/hardware/vibrator/BnVibratorCallback.h>
+#include <android/hardware/vibrator/IVibrator.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+
+#include <future>
+
+using android::ProcessState;
+using android::sp;
+using android::String16;
+using android::binder::Status;
+using android::hardware::vibrator::BnVibratorCallback;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+using android::hardware::vibrator::IVibrator;
+
+const std::vector<Effect> kEffects = {
+        Effect::CLICK,       Effect::DOUBLE_CLICK, Effect::TICK,        Effect::THUD,
+        Effect::POP,         Effect::HEAVY_CLICK,  Effect::RINGTONE_1,  Effect::RINGTONE_2,
+        Effect::RINGTONE_3,  Effect::RINGTONE_4,   Effect::RINGTONE_5,  Effect::RINGTONE_6,
+        Effect::RINGTONE_7,  Effect::RINGTONE_8,   Effect::RINGTONE_9,  Effect::RINGTONE_10,
+        Effect::RINGTONE_11, Effect::RINGTONE_12,  Effect::RINGTONE_13, Effect::RINGTONE_14,
+        Effect::RINGTONE_15, Effect::TEXTURE_TICK};
+
+const std::vector<EffectStrength> kEffectStrengths = {EffectStrength::LIGHT, EffectStrength::MEDIUM,
+                                                      EffectStrength::STRONG};
+
+const std::vector<Effect> kInvalidEffects = {
+        static_cast<Effect>(static_cast<int32_t>(*kEffects.begin()) - 1),
+        static_cast<Effect>(static_cast<int32_t>(*kEffects.end()) + 1),
+};
+
+const std::vector<EffectStrength> kInvalidEffectStrengths = {
+        static_cast<EffectStrength>(static_cast<int8_t>(*kEffectStrengths.begin()) - 1),
+        static_cast<EffectStrength>(static_cast<int8_t>(*kEffectStrengths.end()) + 1),
+};
+
+class CompletionCallback : public BnVibratorCallback {
+  public:
+    CompletionCallback(const std::function<void()>& callback) : mCallback(callback) {}
+    Status onComplete() override {
+        mCallback();
+        return Status::ok();
+    }
+
+  private:
+    std::function<void()> mCallback;
+};
+
+class VibratorAidl : public testing::TestWithParam<std::string> {
+  public:
+    virtual void SetUp() override {
+        vibrator = android::waitForDeclaredService<IVibrator>(String16(GetParam().c_str()));
+        ASSERT_NE(vibrator, nullptr);
+        ASSERT_TRUE(vibrator->getCapabilities(&capabilities).isOk());
+    }
+
+    sp<IVibrator> vibrator;
+    int32_t capabilities;
+};
+
+TEST_P(VibratorAidl, OnThenOffBeforeTimeout) {
+    EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
+    sleep(1);
+    EXPECT_TRUE(vibrator->off().isOk());
+}
+
+TEST_P(VibratorAidl, OnWithCallback) {
+    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
+
+    std::promise<void> completionPromise;
+    std::future<void> completionFuture{completionPromise.get_future()};
+    sp<CompletionCallback> callback =
+            new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+    uint32_t durationMs = 250;
+    std::chrono::milliseconds timeout{durationMs * 2};
+    EXPECT_TRUE(vibrator->on(durationMs, callback).isOk());
+    EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+    EXPECT_TRUE(vibrator->off().isOk());
+}
+
+TEST_P(VibratorAidl, OnCallbackNotSupported) {
+    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) {
+        sp<CompletionCallback> callback = new CompletionCallback([] {});
+        EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, vibrator->on(250, callback).exceptionCode());
+    }
+}
+
+TEST_P(VibratorAidl, ValidateEffect) {
+    for (Effect effect : kEffects) {
+        for (EffectStrength strength : kEffectStrengths) {
+            int32_t lengthMs = 0;
+            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
+            EXPECT_TRUE(status.isOk() ||
+                        status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION);
+            if (status.isOk()) {
+                EXPECT_GT(lengthMs, 0);
+            } else {
+                EXPECT_EQ(lengthMs, 0);
+            }
+        }
+    }
+}
+
+TEST_P(VibratorAidl, ValidateEffectWithCallback) {
+    if (!(capabilities & IVibrator::CAP_PERFORM_CALLBACK)) return;
+
+    for (Effect effect : kEffects) {
+        for (EffectStrength strength : kEffectStrengths) {
+            std::promise<void> completionPromise;
+            std::future<void> completionFuture{completionPromise.get_future()};
+            sp<CompletionCallback> callback =
+                    new CompletionCallback([&completionPromise] { completionPromise.set_value(); });
+            int lengthMs;
+            Status status = vibrator->perform(effect, strength, callback, &lengthMs);
+            EXPECT_TRUE(status.isOk() ||
+                        status.exceptionCode() == Status::EX_UNSUPPORTED_OPERATION);
+            if (!status.isOk()) continue;
+
+            std::chrono::milliseconds timeout{lengthMs * 2};
+            EXPECT_EQ(completionFuture.wait_for(timeout), std::future_status::ready);
+        }
+    }
+}
+
+TEST_P(VibratorAidl, ValidateEffectWithCallbackNotSupported) {
+    if (capabilities & IVibrator::CAP_PERFORM_CALLBACK) return;
+
+    for (Effect effect : kEffects) {
+        for (EffectStrength strength : kEffectStrengths) {
+            sp<CompletionCallback> callback = new CompletionCallback([] {});
+            int lengthMs;
+            Status status = vibrator->perform(effect, strength, callback, &lengthMs);
+            EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, status.exceptionCode());
+            EXPECT_EQ(lengthMs, 0);
+        }
+    }
+}
+
+TEST_P(VibratorAidl, InvalidEffectsUnsupported) {
+    for (Effect effect : kInvalidEffects) {
+        for (EffectStrength strength : kInvalidEffectStrengths) {
+            int32_t lengthMs;
+            Status status = vibrator->perform(effect, strength, nullptr /*callback*/, &lengthMs);
+            EXPECT_EQ(status.exceptionCode(), Status::EX_UNSUPPORTED_OPERATION);
+        }
+    }
+}
+
+TEST_P(VibratorAidl, ChangeVibrationAmplitude) {
+    if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
+        EXPECT_TRUE(vibrator->setAmplitude(1).isOk());
+        EXPECT_TRUE(vibrator->on(2000, nullptr /*callback*/).isOk());
+        EXPECT_TRUE(vibrator->setAmplitude(128).isOk());
+        sleep(1);
+        EXPECT_TRUE(vibrator->setAmplitude(255).isOk());
+        sleep(1);
+    }
+}
+
+TEST_P(VibratorAidl, AmplitudeOutsideRangeFails) {
+    if (capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) {
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(-1).exceptionCode());
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(0).exceptionCode());
+        EXPECT_EQ(Status::EX_ILLEGAL_ARGUMENT, vibrator->setAmplitude(256).exceptionCode());
+    }
+}
+
+TEST_P(VibratorAidl, AmplitudeReturnsUnsupportedMatchingCapabilities) {
+    if ((capabilities & IVibrator::CAP_AMPLITUDE_CONTROL) == 0) {
+        EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION, vibrator->setAmplitude(1).exceptionCode());
+    }
+}
+
+TEST_P(VibratorAidl, ChangeVibrationExternalControl) {
+    if (capabilities & IVibrator::CAP_EXTERNAL_CONTROL) {
+        EXPECT_TRUE(vibrator->setExternalControl(true).isOk());
+        sleep(1);
+        EXPECT_TRUE(vibrator->setExternalControl(false).isOk());
+        sleep(1);
+    }
+}
+
+TEST_P(VibratorAidl, ExternalControlUnsupportedMatchingCapabilities) {
+    if ((capabilities & IVibrator::CAP_EXTERNAL_CONTROL) == 0) {
+        EXPECT_EQ(Status::EX_UNSUPPORTED_OPERATION,
+                  vibrator->setExternalControl(true).exceptionCode());
+    }
+}
+
+INSTANTIATE_TEST_SUITE_P(, VibratorAidl,
+                         testing::ValuesIn(android::getAidlHalInstanceNames(IVibrator::descriptor)),
+                         android::PrintInstanceNameToString);
+
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+    ProcessState::self()->setThreadPoolMaxThreadCount(1);
+    ProcessState::self()->startThreadPool();
+    return RUN_ALL_TESTS();
+}
diff --git a/vr/1.0/vts/functional/Android.bp b/vr/1.0/vts/functional/Android.bp
index 958cce7..bd0336c 100644
--- a/vr/1.0/vts/functional/Android.bp
+++ b/vr/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalVrV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.vr@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
index b165613..c08e5ca 100644
--- a/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
+++ b/vr/1.0/vts/functional/VtsHalVrV1_0TargetTest.cpp
@@ -15,11 +15,12 @@
  */
 
 #define LOG_TAG "vr_hidl_hal_test"
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/vr/1.0/IVr.h>
+#include <gtest/gtest.h>
 #include <hardware/vr.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 #include <log/log.h>
 
 using ::android::hardware::vr::V1_0::IVr;
@@ -27,24 +28,11 @@
 using ::android::hardware::Void;
 using ::android::sp;
 
-// Test environment for Vr HIDL HAL.
-class VrHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
- public:
-  // get the test environment singleton
-  static VrHidlEnvironment* Instance() {
-    static VrHidlEnvironment* instance = new VrHidlEnvironment;
-    return instance;
-  }
-
-  virtual void registerTestServices() override { registerTestService<IVr>(); }
-};
-
 // The main test class for VR HIDL HAL.
-class VrHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class VrHidlTest : public ::testing::TestWithParam<std::string> {
  public:
   void SetUp() override {
-    vr = ::testing::VtsHalHidlTargetTestBase::getService<IVr>(
-        VrHidlEnvironment::Instance()->getServiceName<IVr>());
+    vr = IVr::getService(GetParam());
     ASSERT_NE(vr, nullptr);
   }
 
@@ -54,19 +42,19 @@
 };
 
 // Sanity check that Vr::init does not crash.
-TEST_F(VrHidlTest, Init) {
+TEST_P(VrHidlTest, Init) {
   EXPECT_TRUE(vr->init().isOk());
 }
 
 // Sanity check Vr::setVrMode is able to enable and disable VR mode.
-TEST_F(VrHidlTest, SetVrMode) {
+TEST_P(VrHidlTest, SetVrMode) {
   EXPECT_TRUE(vr->init().isOk());
   EXPECT_TRUE(vr->setVrMode(true).isOk());
   EXPECT_TRUE(vr->setVrMode(false).isOk());
 }
 
 // Sanity check that Vr::init and Vr::setVrMode can be used in any order.
-TEST_F(VrHidlTest, ReInit) {
+TEST_P(VrHidlTest, ReInit) {
   EXPECT_TRUE(vr->init().isOk());
   EXPECT_TRUE(vr->setVrMode(true).isOk());
   EXPECT_TRUE(vr->init().isOk());
@@ -75,11 +63,8 @@
   EXPECT_TRUE(vr->setVrMode(false).isOk());
 }
 
-int main(int argc, char **argv) {
-  ::testing::AddGlobalTestEnvironment(VrHidlEnvironment::Instance());
-  ::testing::InitGoogleTest(&argc, argv);
-  VrHidlEnvironment::Instance()->init(&argc, argv);
-  int status = RUN_ALL_TESTS();
-  ALOGI("Test result = %d", status);
-  return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+        PerInstance, VrHidlTest,
+        testing::ValuesIn(android::hardware::getAllHalInstanceNames(IVr::descriptor)),
+        android::hardware::PrintInstanceNameToString);
+