Merge "[vts-core] add VtsHalHealthV1_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/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/current.txt b/current.txt
index 4c5f155..877bcb4 100644
--- a/current.txt
+++ b/current.txt
@@ -587,7 +587,12 @@
 07d0a252b2d8fa35887908a996ba395cf392968395fc30afab791f46e0c22a52 android.hardware.boot@1.1::IBootControl
 74049a402be913963edfdd80828a53736570e9d8124a1bf18166b6ed46a6b0ab android.hardware.boot@1.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/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
index 7dedd7f..6be30d3 100644
--- a/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
+++ b/drm/1.1/vts/functional/drm_hal_clearkey_test.cpp
@@ -24,7 +24,7 @@
 #include <android/hardware/drm/1.0/types.h>
 #include <android/hardware/drm/1.1/types.h>
 #include <android/hidl/allocator/1.0/IAllocator.h>
-#include <android/hidl/manager/1.0/IServiceManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
 #include <gtest/gtest.h>
 #include <hidl/HidlSupport.h>
 #include <hidl/ServiceManagement.h>
@@ -129,9 +129,9 @@
         ALOGD("DrmHalClearkeyTest: Running test %s.%s", test_info->test_case_name(),
                 test_info->name());
 
-        auto manager = android::hardware::defaultServiceManager();
+        auto manager = android::hardware::defaultServiceManager1_2();
         ASSERT_NE(nullptr, manager.get());
-        manager->listByInterface(IDrmFactory::descriptor,
+        manager->listManifestByInterface(IDrmFactory::descriptor,
                 [&](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         sp<IDrmFactory> drmFactory =
@@ -144,7 +144,7 @@
                 }
             );
 
-        manager->listByInterface(ICryptoFactory::descriptor,
+        manager->listManifestByInterface(ICryptoFactory::descriptor,
                 [&](const hidl_vec<hidl_string> &registered) {
                     for (const auto &instance : registered) {
                         sp<ICryptoFactory> cryptoFactory =
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.cpp b/gnss/1.1/vts/functional/gnss_hal_test.cpp
index 381ac1d..f3b376e 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test.cpp
@@ -16,10 +16,16 @@
 
 #define LOG_TAG "GnssHalTest"
 
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <hidl/ServiceManagement.h>
+
 #include <gnss_hal_test.h>
 #include <chrono>
 #include "Utils.h"
 
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
 using ::android::hardware::gnss::common::Utils;
 
 // Implementations for the main test class for GNSS HAL
@@ -149,6 +155,28 @@
     }
 }
 
+bool GnssHalTest::IsGnssHalVersion_1_1() const {
+    using ::android::hidl::manager::V1_2::IServiceManager;
+    sp<IServiceManager> manager = ::android::hardware::defaultServiceManager1_2();
+
+    bool hasGnssHalVersion_1_1 = false;
+    manager->listManifestByInterface(
+            "android.hardware.gnss@1.1::IGnss",
+            [&hasGnssHalVersion_1_1](const hidl_vec<hidl_string>& registered) {
+                ASSERT_EQ(1, registered.size());
+                hasGnssHalVersion_1_1 = true;
+            });
+
+    bool hasGnssHalVersion_2_0 = false;
+    manager->listManifestByInterface(
+            "android.hardware.gnss@2.0::IGnss",
+            [&hasGnssHalVersion_2_0](const hidl_vec<hidl_string>& registered) {
+                hasGnssHalVersion_2_0 = registered.size() != 0;
+            });
+
+    return hasGnssHalVersion_1_1 && !hasGnssHalVersion_2_0;
+}
+
 void GnssHalTest::notify() {
     std::unique_lock<std::mutex> lock(mtx_);
     notify_count_++;
diff --git a/gnss/1.1/vts/functional/gnss_hal_test.h b/gnss/1.1/vts/functional/gnss_hal_test.h
index 64478b5..84a9f84 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test.h
+++ b/gnss/1.1/vts/functional/gnss_hal_test.h
@@ -145,6 +145,12 @@
      */
     void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
 
+    /*
+     * IsGnssHalVersion_1_1:
+     * returns  true if the GNSS HAL version is exactly 1.1.
+     */
+    bool IsGnssHalVersion_1_1() const;
+
     sp<IGnss> gnss_hal_;         // GNSS HAL to call into
     sp<IGnssCallback> gnss_cb_;  // Primary callback interface
 
diff --git a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
index 2d901f3..ee236ba 100644
--- a/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/1.1/vts/functional/gnss_hal_test_cases.cpp
@@ -24,6 +24,9 @@
 
 using android::hardware::hidl_vec;
 
+using IGnssMeasurement_1_0 = android::hardware::gnss::V1_0::IGnssMeasurement;
+using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
+
 using android::hardware::gnss::V1_0::GnssConstellationType;
 using android::hardware::gnss::V1_0::GnssLocation;
 using android::hardware::gnss::V1_0::IGnssDebug;
@@ -43,11 +46,15 @@
  * Gets the GnssMeasurementExtension and verify that it returns an actual extension.
  */
 TEST_F(GnssHalTest, TestGnssMeasurementCallback) {
-    auto gnssMeasurement = gnss_hal_->getExtensionGnssMeasurement_1_1();
-    ASSERT_TRUE(gnssMeasurement.isOk());
+    auto gnssMeasurement_1_1 = gnss_hal_->getExtensionGnssMeasurement_1_1();
+    ASSERT_TRUE(gnssMeasurement_1_1.isOk());
+    auto gnssMeasurement_1_0 = gnss_hal_->getExtensionGnssMeasurement();
+    ASSERT_TRUE(gnssMeasurement_1_0.isOk());
     if (last_capabilities_ & IGnssCallback::Capabilities::MEASUREMENTS) {
-        sp<IGnssMeasurement> iGnssMeas = gnssMeasurement;
-        EXPECT_NE(iGnssMeas, nullptr);
+        sp<IGnssMeasurement_1_1> iGnssMeas_1_1 = gnssMeasurement_1_1;
+        sp<IGnssMeasurement_1_0> iGnssMeas_1_0 = gnssMeasurement_1_0;
+        // At least one interface must be non-null.
+        ASSERT_TRUE(iGnssMeas_1_1 != nullptr || iGnssMeas_1_0 != nullptr);
     }
 }
 
@@ -59,6 +66,11 @@
  * each received location.
  */
 TEST_F(GnssHalTest, GetLocationLowPower) {
+    if (!IsGnssHalVersion_1_1()) {
+        ALOGI("Test GetLocationLowPower skipped. GNSS HAL version is greater than 1.1.");
+        return;
+    }
+
     const int kMinIntervalMsec = 5000;
     const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
     const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
@@ -202,6 +214,11 @@
  * formerly strongest satellite
  */
 TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+    if (!IsGnssHalVersion_1_1()) {
+        ALOGI("Test BlacklistIndividualSatellites skipped. GNSS HAL version is greater than 1.1.");
+        return;
+    }
+
     const int kLocationsToAwait = 3;
     const int kRetriesToUnBlacklist = 10;
 
@@ -323,6 +340,11 @@
  * 4a & b) Clean up by turning off location, and send in empty blacklist.
  */
 TEST_F(GnssHalTest, BlacklistConstellation) {
+    if (!IsGnssHalVersion_1_1()) {
+        ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 1.1.");
+        return;
+    }
+
     const int kLocationsToAwait = 3;
 
     StartAndCheckLocations(kLocationsToAwait);
diff --git a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
index a8e40ba..ae36c50 100644
--- a/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
+++ b/gnss/2.0/vts/functional/VtsHalGnssV2_0TargetTest.cpp
@@ -23,7 +23,6 @@
     ::testing::AddGlobalTestEnvironment(GnssHidlEnvironment::Instance());
     ::testing::InitGoogleTest(&argc, argv);
     GnssHidlEnvironment::Instance()->init(&argc, argv);
-    // TODO (b/122463165): Expand coverage to include 1.1 and 1.0 VTS tests.
     int status = RUN_ALL_TESTS();
     ALOGI("Test result = %d", status);
     return status;
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index a9f858c..14ae43c 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -152,7 +152,7 @@
       name_cbq_("name"),
       capabilities_cbq_("capabilities"),
       location_cbq_("location"),
-      sv_info_cbq_("sv_info") {}
+      sv_info_list_cbq_("sv_info") {}
 
 Return<void> GnssHalTest::GnssCallback::gnssSetSystemInfoCb(
         const IGnssCallback_1_0::GnssSystemInfo& info) {
@@ -204,7 +204,7 @@
 Return<void> GnssHalTest::GnssCallback::gnssSvStatusCb_2_0(
         const hidl_vec<IGnssCallback_2_0::GnssSvInfo>& svInfoList) {
     ALOGI("gnssSvStatusCb_2_0. Size = %d", (int)svInfoList.size());
-    sv_info_cbq_.store(svInfoList);
+    sv_info_list_cbq_.store(svInfoList);
     return Void();
 }
 
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index 05e37d3..90a7866 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -23,6 +23,7 @@
 
 #include <condition_variable>
 #include <deque>
+#include <list>
 #include <mutex>
 
 using android::hardware::hidl_vec;
@@ -85,6 +86,14 @@
          */
         bool retrieve(T& event, int timeout_seconds);
 
+        /*
+         * Removes parameter count number of callack events at the front of the queue, stores
+         * them in event_list parameter and returns the number of events retrieved. Waits up to
+         * timeout_seconds to retrieve each event. If timeout occurs, it returns the number of
+         * items retrieved which will be less than count.
+         */
+        int retrieve(list<T>& event_list, int count, int timeout_seconds);
+
         /* Returns the number of events pending to be retrieved from the callback event queue. */
         int size() const;
 
@@ -117,7 +126,7 @@
         CallbackQueue<android::hardware::hidl_string> name_cbq_;
         CallbackQueue<uint32_t> capabilities_cbq_;
         CallbackQueue<GnssLocation_2_0> location_cbq_;
-        CallbackQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_cbq_;
+        CallbackQueue<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_list_cbq_;
 
         GnssCallback();
         virtual ~GnssCallback() = default;
@@ -265,6 +274,19 @@
 }
 
 template <class T>
+int GnssHalTest::CallbackQueue<T>::retrieve(list<T>& event_list, int count, int timeout_seconds) {
+    for (int i = 0; i < count; ++i) {
+        T event;
+        if (!retrieve(event, timeout_seconds)) {
+            return i;
+        }
+        event_list.push_back(event);
+    }
+
+    return count;
+}
+
+template <class T>
 int GnssHalTest::CallbackQueue<T>::size() const {
     std::unique_lock<std::recursive_mutex> lock(mtx_);
     return events_.size();
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 155afd6..39736cc 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -23,7 +23,10 @@
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
 
+using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
+using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
 using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
+using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
 using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil;
 using IGnssMeasurement_2_0 = android::hardware::gnss::V2_0::IGnssMeasurement;
 using IGnssMeasurement_1_1 = android::hardware::gnss::V1_1::IGnssMeasurement;
@@ -33,15 +36,12 @@
 using IAGnss_2_0 = android::hardware::gnss::V2_0::IAGnss;
 using IAGnss_1_0 = android::hardware::gnss::V1_0::IAGnss;
 using IAGnssCallback_2_0 = android::hardware::gnss::V2_0::IAGnssCallback;
-using IGnssBatching_V1_0 = android::hardware::gnss::V1_0::IGnssBatching;
-using IGnssBatching_V2_0 = android::hardware::gnss::V2_0::IGnssBatching;
 
 using android::hardware::gnss::common::Utils;
 using android::hardware::gnss::measurement_corrections::V1_0::IMeasurementCorrections;
 using android::hardware::gnss::measurement_corrections::V1_0::MeasurementCorrections;
 using android::hardware::gnss::V1_0::IGnssNi;
 using android::hardware::gnss::V2_0::ElapsedRealtimeFlags;
-using android::hardware::gnss::V2_0::GnssConstellationType;
 using android::hardware::gnss::V2_0::IGnssCallback;
 using android::hardware::gnss::visibility_control::V1_0::IGnssVisibilityControl;
 
@@ -209,9 +209,9 @@
 
         // Verify ConstellationType is valid.
         ASSERT_TRUE(static_cast<uint8_t>(measurement.constellation) >=
-                            static_cast<uint8_t>(GnssConstellationType::UNKNOWN) &&
+                            static_cast<uint8_t>(GnssConstellationType_2_0::UNKNOWN) &&
                     static_cast<uint8_t>(measurement.constellation) <=
-                            static_cast<uint8_t>(GnssConstellationType::IRNSS));
+                            static_cast<uint8_t>(GnssConstellationType_2_0::IRNSS));
 
         // Verify State is valid.
         ASSERT_TRUE(
@@ -414,3 +414,423 @@
     auto gnssBatching_2_0 = gnss_hal_->getExtensionGnssBatching_2_0();
     ASSERT_TRUE(gnssBatching_2_0.isOk());
 }
+
+/*
+ * GetLocationLowPower:
+ * Turns on location, waits for at least 5 locations allowing max of LOCATION_TIMEOUT_SUBSEQUENT_SEC
+ * between one location and the next. Also ensure that MIN_INTERVAL_MSEC is respected by waiting
+ * NO_LOCATION_PERIOD_SEC and verfiy that no location is received. Also perform validity checks on
+ * each received location.
+ */
+TEST_F(GnssHalTest, GetLocationLowPower) {
+    if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::LOW_POWER_MODE)) {
+        ALOGI("Test GetLocationLowPower skipped. LOW_POWER_MODE capability not supported.");
+        return;
+    }
+
+    const int kMinIntervalMsec = 5000;
+    const int kLocationTimeoutSubsequentSec = (kMinIntervalMsec / 1000) * 2;
+    const int kNoLocationPeriodSec = (kMinIntervalMsec / 1000) / 2;
+    const int kLocationsToCheck = 5;
+    const bool kLowPowerMode = true;
+
+    // Warmup period - VTS doesn't have AGPS access via GnssLocationProvider
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToCheck);
+    StopAndClearLocations();
+    gnss_cb_->location_cbq_.reset();
+
+    // Start of Low Power Mode test
+    SetPositionMode(kMinIntervalMsec, kLowPowerMode);
+
+    // Don't expect true - as without AGPS access
+    if (!StartAndCheckFirstLocation()) {
+        ALOGW("GetLocationLowPower test - no first low power location received.");
+    }
+
+    for (int i = 1; i < kLocationsToCheck; i++) {
+        // Verify that kMinIntervalMsec is respected by waiting kNoLocationPeriodSec and
+        // ensure that no location is received yet
+
+        gnss_cb_->location_cbq_.retrieve(gnss_cb_->last_location_, kNoLocationPeriodSec);
+        const int locationCalledCount = gnss_cb_->location_cbq_.calledCount();
+
+        // Tolerate (ignore) one extra location right after the first one
+        // to handle startup edge case scheduling limitations in some implementations
+        if ((i == 1) && (locationCalledCount == 2)) {
+            CheckLocation(gnss_cb_->last_location_, true);
+            continue;  // restart the quiet wait period after this too-fast location
+        }
+        EXPECT_LE(locationCalledCount, i);
+        if (locationCalledCount != i) {
+            ALOGW("GetLocationLowPower test - not enough locations received. %d vs. %d expected ",
+                  locationCalledCount, i);
+        }
+
+        if (!gnss_cb_->location_cbq_.retrieve(
+                    gnss_cb_->last_location_,
+                    kLocationTimeoutSubsequentSec - kNoLocationPeriodSec)) {
+            ALOGW("GetLocationLowPower test - timeout awaiting location %d", i);
+        } else {
+            CheckLocation(gnss_cb_->last_location_, true);
+        }
+    }
+
+    StopAndClearLocations();
+}
+
+/*
+ * MapConstellationType:
+ * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
+ * GnssConstellationType_1_0 type constellation. For constellations that do not have
+ * an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN
+ */
+GnssConstellationType_1_0 MapConstellationType(GnssConstellationType_2_0 constellation) {
+    switch (constellation) {
+        case GnssConstellationType_2_0::GPS:
+            return GnssConstellationType_1_0::GPS;
+        case GnssConstellationType_2_0::SBAS:
+            return GnssConstellationType_1_0::SBAS;
+        case GnssConstellationType_2_0::GLONASS:
+            return GnssConstellationType_1_0::GLONASS;
+        case GnssConstellationType_2_0::QZSS:
+            return GnssConstellationType_1_0::QZSS;
+        case GnssConstellationType_2_0::BEIDOU:
+            return GnssConstellationType_1_0::BEIDOU;
+        case GnssConstellationType_2_0::GALILEO:
+            return GnssConstellationType_1_0::GALILEO;
+        default:
+            return GnssConstellationType_1_0::UNKNOWN;
+    }
+}
+
+/*
+ * FindStrongFrequentNonGpsSource:
+ *
+ * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
+ *
+ * returns the strongest source,
+ *         or a source with constellation == UNKNOWN if none are found sufficient times
+ */
+IGnssConfiguration_1_1::BlacklistedSource FindStrongFrequentNonGpsSource(
+        const list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>>& sv_info_lists,
+        const int min_observations) {
+    struct ComparableBlacklistedSource {
+        IGnssConfiguration_1_1::BlacklistedSource id;
+
+        ComparableBlacklistedSource() {
+            id.constellation = GnssConstellationType_1_0::UNKNOWN;
+            id.svid = 0;
+        }
+
+        bool operator<(const ComparableBlacklistedSource& compare) const {
+            return ((id.svid < compare.id.svid) || ((id.svid == compare.id.svid) &&
+                                                    (id.constellation < compare.id.constellation)));
+        }
+    };
+
+    struct SignalCounts {
+        int observations;
+        float max_cn0_dbhz;
+    };
+
+    std::map<ComparableBlacklistedSource, SignalCounts> mapSignals;
+
+    for (const auto& sv_info_list : sv_info_lists) {
+        for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+            if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+                (sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
+                (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
+                ComparableBlacklistedSource source;
+                source.id.svid = sv_info.v1_0.svid;
+                source.id.constellation = MapConstellationType(sv_info.constellation);
+
+                const auto& itSignal = mapSignals.find(source);
+                if (itSignal == mapSignals.end()) {
+                    SignalCounts counts;
+                    counts.observations = 1;
+                    counts.max_cn0_dbhz = sv_info.v1_0.cN0Dbhz;
+                    mapSignals.insert(
+                            std::pair<ComparableBlacklistedSource, SignalCounts>(source, counts));
+                } else {
+                    itSignal->second.observations++;
+                    if (itSignal->second.max_cn0_dbhz < sv_info.v1_0.cN0Dbhz) {
+                        itSignal->second.max_cn0_dbhz = sv_info.v1_0.cN0Dbhz;
+                    }
+                }
+            }
+        }
+    }
+
+    float max_cn0_dbhz_with_sufficient_count = 0.;
+    int total_observation_count = 0;
+    int blacklisted_source_count_observation = 0;
+
+    ComparableBlacklistedSource source_to_blacklist;  // initializes to zero = UNKNOWN constellation
+    for (auto const& pairSignal : mapSignals) {
+        total_observation_count += pairSignal.second.observations;
+        if ((pairSignal.second.observations >= min_observations) &&
+            (pairSignal.second.max_cn0_dbhz > max_cn0_dbhz_with_sufficient_count)) {
+            source_to_blacklist = pairSignal.first;
+            blacklisted_source_count_observation = pairSignal.second.observations;
+            max_cn0_dbhz_with_sufficient_count = pairSignal.second.max_cn0_dbhz;
+        }
+    }
+    ALOGD("Among %d observations, chose svid %d, constellation %d, "
+          "with %d observations at %.1f max CNo",
+          total_observation_count, source_to_blacklist.id.svid,
+          (int)source_to_blacklist.id.constellation, blacklisted_source_count_observation,
+          max_cn0_dbhz_with_sufficient_count);
+
+    return source_to_blacklist.id;
+}
+
+/*
+ * BlacklistIndividualSatellites:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for common satellites (strongest and one other.)
+ * 2a & b) Turns off location, and blacklists common satellites.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use those satellites.
+ * 4a & b) Turns off location, and send in empty blacklist.
+ * 5a) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does re-use at least the previously strongest satellite
+ * 5b) Retry a few times, in case GNSS search strategy takes a while to reacquire even the
+ * formerly strongest satellite
+ */
+TEST_F(GnssHalTest, BlacklistIndividualSatellites) {
+    if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
+        ALOGI("Test BlacklistIndividualSatellites skipped. SATELLITE_BLACKLIST capability"
+              " not supported.");
+        return;
+    }
+
+    const int kLocationsToAwait = 3;
+    const int kRetriesToUnBlacklist = 10;
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+    int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+    /*
+     * Identify strongest SV seen at least kLocationsToAwait -1 times
+     * Why -1?  To avoid test flakiness in case of (plausible) slight flakiness in strongest signal
+     * observability (one epoch RF null)
+     */
+
+    const int kGnssSvStatusTimeout = 2;
+    list<hidl_vec<IGnssCallback_2_0::GnssSvInfo>> sv_info_lists;
+    int count = gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, sv_info_list_cbq_size,
+                                                     kGnssSvStatusTimeout);
+    ASSERT_EQ(count, sv_info_list_cbq_size);
+
+    IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist =
+            FindStrongFrequentNonGpsSource(sv_info_lists, kLocationsToAwait - 1);
+
+    if (source_to_blacklist.constellation == GnssConstellationType_1_0::UNKNOWN) {
+        // Cannot find a non-GPS satellite. Let the test pass.
+        return;
+    }
+
+    // Stop locations, blacklist the common SV
+    StopAndClearLocations();
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration_1_1> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration_1_1::BlacklistedSource> sources;
+    sources.resize(1);
+    sources[0] = source_to_blacklist;
+
+    auto result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // retry and ensure satellite not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // early exit if test is being run with insufficient signal
+    location_called_count = gnss_cb_->location_cbq_.calledCount();
+    if (location_called_count == 0) {
+        ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+    }
+    ASSERT_TRUE(location_called_count > 0);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+        for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+            auto constellation = MapConstellationType(sv_info.constellation);
+            EXPECT_FALSE((sv_info.v1_0.svid == source_to_blacklist.svid) &&
+                         (constellation == source_to_blacklist.constellation) &&
+                         (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clear blacklist and restart - this time updating the blacklist while location is still on
+    sources.resize(0);
+
+    result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    bool strongest_sv_is_reobserved = false;
+    // do several loops awaiting a few locations, allowing non-immediate reacquisition strategies
+    int unblacklist_loops_remaining = kRetriesToUnBlacklist;
+    while (!strongest_sv_is_reobserved && (unblacklist_loops_remaining-- > 0)) {
+        StopAndClearLocations();
+        gnss_cb_->sv_info_list_cbq_.reset();
+
+        gnss_cb_->location_cbq_.reset();
+        StartAndCheckLocations(kLocationsToAwait);
+
+        // early exit loop if test is being run with insufficient signal
+        location_called_count = gnss_cb_->location_cbq_.calledCount();
+        if (location_called_count == 0) {
+            ALOGE("0 Gnss locations received - ensure sufficient signal and retry");
+        }
+        ASSERT_TRUE(location_called_count > 0);
+
+        // Tolerate 1 less sv status to handle edge cases in reporting.
+        sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+        EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+        ALOGD("Clear blacklist, observed %d GnssSvStatus, while awaiting %d Locations"
+              ", tries remaining %d",
+              sv_info_list_cbq_size, kLocationsToAwait, unblacklist_loops_remaining);
+
+        for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+            hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+            gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+            for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+                auto constellation = MapConstellationType(sv_info.constellation);
+                if ((sv_info.v1_0.svid == source_to_blacklist.svid) &&
+                    (constellation == source_to_blacklist.constellation) &&
+                    (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
+                    strongest_sv_is_reobserved = true;
+                    break;
+                }
+            }
+            if (strongest_sv_is_reobserved) break;
+        }
+    }
+    EXPECT_TRUE(strongest_sv_is_reobserved);
+    StopAndClearLocations();
+}
+
+/*
+ * BlacklistConstellation:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Turns off location, and blacklist first non-GPS constellations.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blacklist.
+ */
+TEST_F(GnssHalTest, BlacklistConstellation) {
+    if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
+        ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
+        return;
+    }
+
+    const int kLocationsToAwait = 3;
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+    const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+    // Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0
+    // as blacklisting of this constellation is not supported in gnss@2.0.
+    const int kGnssSvStatusTimeout = 2;
+    GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN;
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+        for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+            if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
+                (sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) &&
+                (sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
+                (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
+                // found a non-GPS V1_0 constellation
+                constellation_to_blacklist = MapConstellationType(sv_info.constellation);
+                break;
+            }
+        }
+        if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) {
+            break;
+        }
+    }
+
+    if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) {
+        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+        // Proceed functionally to blacklist something.
+        constellation_to_blacklist = GnssConstellationType_1_0::GLONASS;
+    }
+    IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist;
+    source_to_blacklist.constellation = constellation_to_blacklist;
+    source_to_blacklist.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration_1_1> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration_1_1::BlacklistedSource> sources;
+    sources.resize(1);
+    sources[0] = source_to_blacklist;
+
+    auto result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // retry and ensure constellation not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size,
+          kLocationsToAwait);
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+        for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+            auto constellation = MapConstellationType(sv_info.constellation);
+            EXPECT_FALSE((constellation == source_to_blacklist.constellation) &&
+                         (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clean up
+    StopAndClearLocations();
+    sources.resize(0);
+    result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
\ No newline at end of file
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/keymaster/4.0/vts/OWNERS b/keymaster/4.0/vts/OWNERS
index 376c12b..abfb2e0 100644
--- a/keymaster/4.0/vts/OWNERS
+++ b/keymaster/4.0/vts/OWNERS
@@ -1,3 +1,4 @@
+jbires@google.com
 jdanis@google.com
 swillden@google.com
 yim@google.com
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/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/radio/1.2/vts/functional/radio_hidl_hal_test.cpp b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
index 835d9b8..21caddb 100644
--- a/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
+++ b/radio/1.2/vts/functional/radio_hidl_hal_test.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-#include <android/hardware/radio/1.1/IRadio.h>
 #include <radio_hidl_hal_utils_v1_2.h>
 
 void RadioHidlTest_v1_2::SetUp() {
@@ -154,25 +153,7 @@
 }
 
 void RadioHidlTest_v1_2::stopNetworkScan() {
-    sp<::android::hardware::radio::V1_1::IRadio> radio_v1_1;
-
-    radio_v1_1 = ::testing::VtsHalHidlTargetTestBase::getService<
-            ::android::hardware::radio::V1_1::IRadio>(
-            RadioHidlEnvironment::Instance()
-                    ->getServiceName<::android::hardware::radio::V1_1::IRadio>(
-                            hidl_string(RADIO_SERVICE_NAME)));
-    if (radio_v1_1 == NULL) {
-        sleep(60);
-        radio_v1_1 = ::testing::VtsHalHidlTargetTestBase::getService<
-                ::android::hardware::radio::V1_1::IRadio>(
-                RadioHidlEnvironment::Instance()
-                        ->getServiceName<::android::hardware::radio::V1_1::IRadio>(
-                                hidl_string(RADIO_SERVICE_NAME)));
-    }
-    ASSERT_NE(nullptr, radio_v1_1.get());
-
     serial = GetRandomSerialNumber();
-
-    radio_v1_1->stopNetworkScan(serial);
+    radio_v1_2->stopNetworkScan(serial);
     EXPECT_EQ(std::cv_status::no_timeout, wait());
 }
diff --git a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
index d3012bb..a4953d7 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -169,6 +169,11 @@
 
 /*
  * Test IRadio.startNetworkScan() for the response returned.
+ *
+ * REQUEST_NOT_SUPPORTED is temporarily returned because of vendors failed to fully implement
+ * startNetworkScan in HAL @1.4 (see b/137298570 and b/135595082). Starting from @1.5, however,
+ * REQUEST_NOT_SUPPORTED will be disallowed for all tests. Modems have "GSM" rat scan need to
+ * support scanning requests combined with some parameters.
  */
 TEST_F(RadioHidlTest_v1_4, startNetworkScan) {
     serial = GetRandomSerialNumber();
@@ -196,10 +201,17 @@
     if (cardStatus.base.base.cardState == CardState::ABSENT) {
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::SIM_ABSENT}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do not support the
-        // required manual GSM search functionality. This is tracked in b/112206766.
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
-                                     {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED}));
+      // OPERATION_NOT_ALLOWED should not be allowed; however, some vendors do
+      // not support the required manual GSM search functionality. This is
+      // tracked in b/112206766. REQUEST_NOT_SUPPORTED is temporarily added back
+      // because of vendors failed to implement startNetworkScan in HAL 1.4 (see
+      // b/137298570 and b/135595082). Starting from 1.5, however,
+      // REQUEST_NOT_SUPPORTED will be disallowed. Modems have "GSM" rat scan
+      // need to support scanning requests combined with some parameters.
+      ASSERT_TRUE(
+          CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                           {RadioError::NONE, RadioError::OPERATION_NOT_ALLOWED,
+                            RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -225,8 +237,9 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(CheckAnyOfErrors(
+          radioRsp_v1_4->rspInfo.error,
+          {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -261,8 +274,9 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(CheckAnyOfErrors(
+          radioRsp_v1_4->rspInfo.error,
+          {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -296,8 +310,9 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(CheckAnyOfErrors(
+          radioRsp_v1_4->rspInfo.error,
+          {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -331,8 +346,9 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(CheckAnyOfErrors(
+          radioRsp_v1_4->rspInfo.error,
+          {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -366,8 +382,9 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(CheckAnyOfErrors(
+          radioRsp_v1_4->rspInfo.error,
+          {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -401,8 +418,9 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(CheckAnyOfErrors(
+          radioRsp_v1_4->rspInfo.error,
+          {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -436,8 +454,9 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::SIM_ABSENT, RadioError::INVALID_ARGUMENTS}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(
-                CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error, {RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(CheckAnyOfErrors(
+          radioRsp_v1_4->rspInfo.error,
+          {RadioError::INVALID_ARGUMENTS, RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -473,8 +492,10 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::NONE, RadioError::SIM_ABSENT}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
-                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(
+          CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                           {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+                            RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
@@ -512,8 +533,10 @@
         ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
                                      {RadioError::NONE, RadioError::SIM_ABSENT}));
     } else if (cardStatus.base.base.cardState == CardState::PRESENT) {
-        ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
-                                     {RadioError::NONE, RadioError::INVALID_ARGUMENTS}));
+      ASSERT_TRUE(
+          CheckAnyOfErrors(radioRsp_v1_4->rspInfo.error,
+                           {RadioError::NONE, RadioError::INVALID_ARGUMENTS,
+                            RadioError::REQUEST_NOT_SUPPORTED}));
     }
 }
 
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/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp
index d4c5f32..7bb992b 100644
--- a/sensors/1.0/vts/functional/Android.bp
+++ b/sensors/1.0/vts/functional/Android.bp
@@ -16,6 +16,7 @@
 
 cc_test {
     name: "VtsHalSensorsV1_0TargetTest",
+    cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "SensorsHidlEnvironmentV1_0.cpp",
@@ -23,7 +24,10 @@
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
         "VtsHalSensorsTargetTestUtils",
     ],
diff --git a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
index 47308e1..5453ef6 100644
--- a/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
+++ b/sensors/1.0/vts/functional/VtsHalSensorsV1_0TargetTest.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "sensors_hidl_hal_test"
-
 #include "SensorsHidlEnvironmentV1_0.h"
 #include "sensors-vts-utils/SensorsHidlTestBase.h"
 
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp
index 8e8413c..4765fa2 100644
--- a/sensors/2.0/vts/functional/Android.bp
+++ b/sensors/2.0/vts/functional/Android.bp
@@ -16,6 +16,7 @@
 
 cc_test {
     name: "VtsHalSensorsV2_0TargetTest",
+    cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
         "SensorsHidlEnvironmentV2_0.cpp",
@@ -23,7 +24,10 @@
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
         "android.hardware.sensors@2.0",
         "libfmq",
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
index 0525bdc..03fcc17 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.cpp
@@ -38,6 +38,13 @@
 
 constexpr size_t SensorsHidlEnvironmentV2_0::MAX_RECEIVE_BUFFER_EVENT_COUNT;
 
+void SensorsHalDeathRecipient::serviceDied(
+        uint64_t /* cookie */,
+        const ::android::wp<::android::hidl::base::V1_0::IBase>& /* service */) {
+    ALOGE("Sensors HAL died (likely crashed) during test");
+    FAIL() << "Sensors HAL died during test";
+}
+
 struct SensorsCallback : ISensorsCallback {
     Return<void> onDynamicSensorsConnected(const hidl_vec<SensorInfo>& /* sensorInfos */) {
         return Return<void>();
@@ -56,6 +63,7 @@
         if (mSensors == nullptr) {
             break;
         }
+        mSensors->linkToDeath(mDeathRecipient, 0 /* cookie */);
 
         // Initialize FMQs
         mEventQueue = std::make_unique<EventMessageQueue>(MAX_RECEIVE_BUFFER_EVENT_COUNT,
diff --git a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
index 5e54530..b0dbd90 100644
--- a/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
+++ b/sensors/2.0/vts/functional/SensorsHidlEnvironmentV2_0.h
@@ -32,6 +32,13 @@
 using ::android::hardware::MessageQueue;
 
 class SensorsHidlTest;
+
+class SensorsHalDeathRecipient : public ::android::hardware::hidl_death_recipient {
+    virtual void serviceDied(
+            uint64_t cookie,
+            const ::android::wp<::android::hidl::base::V1_0::IBase>& service) override;
+};
+
 class SensorsHidlEnvironmentV2_0 : public SensorsHidlEnvironmentBase {
    public:
     using Event = ::android::hardware::sensors::V1_0::Event;
@@ -84,6 +91,11 @@
     sp<android::hardware::sensors::V2_0::ISensors> mSensors;
 
     /**
+     * Monitors the HAL for crashes, triggering test failure if seen
+     */
+    sp<SensorsHalDeathRecipient> mDeathRecipient = new SensorsHalDeathRecipient();
+
+    /**
      * Type used to simplify the creation of the Event FMQ
      */
     typedef MessageQueue<Event, ::android::hardware::kSynchronizedReadWrite> EventMessageQueue;
diff --git a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
index 62c5334..8364ba9 100644
--- a/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
+++ b/sensors/2.0/vts/functional/VtsHalSensorsV2_0TargetTest.cpp
@@ -14,8 +14,6 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "sensors_hidl_hal_test"
-
 #include "SensorsHidlEnvironmentV2_0.h"
 #include "sensors-vts-utils/SensorsHidlTestBase.h"
 #include "sensors-vts-utils/SensorsTestSharedMemory.h"
@@ -40,6 +38,10 @@
 using ::android::hardware::sensors::V1_0::SensorStatus;
 using ::android::hardware::sensors::V1_0::SharedMemType;
 using ::android::hardware::sensors::V1_0::Vec3;
+using std::chrono::duration_cast;
+using std::chrono::microseconds;
+using std::chrono::milliseconds;
+using std::chrono::nanoseconds;
 
 constexpr size_t kEventSize = static_cast<size_t>(SensorsEventFormatOffset::TOTAL_LENGTH);
 
@@ -69,9 +71,9 @@
     }
 
     void waitForFlushEvents(const std::vector<SensorInfo>& sensorsToWaitFor,
-                            int32_t numCallsToFlush, int64_t timeoutMs) {
+                            int32_t numCallsToFlush, milliseconds timeout) {
         std::unique_lock<std::recursive_mutex> lock(mFlushMutex);
-        mFlushCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
+        mFlushCV.wait_for(lock, timeout,
                           [&] { return flushesReceived(sensorsToWaitFor, numCallsToFlush); });
     }
 
@@ -80,10 +82,9 @@
         return mEventMap[sensorHandle];
     }
 
-    void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, int32_t timeoutMs) {
+    void waitForEvents(const std::vector<SensorInfo>& sensorsToWaitFor, milliseconds timeout) {
         std::unique_lock<std::recursive_mutex> lock(mEventMutex);
-        mEventCV.wait_for(lock, std::chrono::milliseconds(timeoutMs),
-                          [&] { return eventsReceived(sensorsToWaitFor); });
+        mEventCV.wait_for(lock, timeout, [&] { return eventsReceived(sensorsToWaitFor); });
     }
 
    protected:
@@ -117,7 +118,13 @@
 // The main test class for SENSORS HIDL HAL.
 
 class SensorsHidlTest : public SensorsHidlTestBase {
-   protected:
+  public:
+    virtual void SetUp() override {
+        // Ensure that we have a valid environment before performing tests
+        ASSERT_NE(getSensors(), nullptr);
+    }
+
+  protected:
     SensorInfo defaultSensorByType(SensorType type) override;
     std::vector<SensorInfo> getSensorsList();
     // implementation wrapper
@@ -169,19 +176,21 @@
     // Helper functions
     void activateAllSensors(bool enable);
     std::vector<SensorInfo> getNonOneShotSensors();
+    std::vector<SensorInfo> getNonOneShotAndNonSpecialSensors();
     std::vector<SensorInfo> getOneShotSensors();
     std::vector<SensorInfo> getInjectEventSensors();
     int32_t getInvalidSensorHandle();
     bool getDirectChannelSensor(SensorInfo* sensor, SharedMemType* memType, RateLevel* rate);
     void verifyDirectChannel(SharedMemType memType);
-    void verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
-                                     std::shared_ptr<SensorsTestSharedMemory> mem,
-                                     int32_t* directChannelHandle);
+    void verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
+                                     int32_t* directChannelHandle, bool supportsSharedMemType,
+                                     bool supportsAnyDirectChannel);
     void verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
-                         int32_t directChannelHandle);
-    void verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
-                                       int32_t directChannelHandle);
+                         int32_t directChannelHandle, bool directChannelSupported);
+    void verifyUnregisterDirectChannel(int32_t directChannelHandle, bool directChannelSupported);
     void checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle, RateLevel rateLevel);
+    void queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+                                   bool* supportsAnyDirectChannel);
 };
 
 Return<Result> SensorsHidlTest::activate(int32_t sensorHandle, bool enabled) {
@@ -250,6 +259,18 @@
     return sensors;
 }
 
+std::vector<SensorInfo> SensorsHidlTest::getNonOneShotAndNonSpecialSensors() {
+    std::vector<SensorInfo> sensors;
+    for (const SensorInfo& info : getSensorsList()) {
+        SensorFlagBits reportMode = extractReportMode(info.flags);
+        if (reportMode != SensorFlagBits::ONE_SHOT_MODE &&
+            reportMode != SensorFlagBits::SPECIAL_REPORTING_MODE) {
+            sensors.push_back(info);
+        }
+    }
+    return sensors;
+}
+
 std::vector<SensorInfo> SensorsHidlTest::getOneShotSensors() {
     std::vector<SensorInfo> sensors;
     for (const SensorInfo& info : getSensorsList()) {
@@ -368,7 +389,7 @@
     }
 
     // Wait for events to be written back to the Event FMQ
-    callback.waitForEvents(sensors, 1000 /* timeoutMs */);
+    callback.waitForEvents(sensors, milliseconds(1000) /* timeout */);
 
     for (const auto& s : sensors) {
         auto events = callback.getEvents(s.sensorHandle);
@@ -614,6 +635,9 @@
     std::unique_ptr<SensorsHidlEnvironmentTest> newEnv =
         std::make_unique<SensorsHidlEnvironmentTest>();
     newEnv->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if setting up the new environment failed
+    }
 
     activateAllSensors(true);
     // Verify that the old environment does not receive any events
@@ -626,8 +650,11 @@
     newEnv->HidlTearDown();
 
     // Restore the test environment for future tests
-    SensorsHidlEnvironmentV2_0::Instance()->HidlTearDown();
-    SensorsHidlEnvironmentV2_0::Instance()->HidlSetUp();
+    getEnvironment()->HidlTearDown();
+    getEnvironment()->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
 
     // Ensure that the original environment is receiving events
     activateAllSensors(true);
@@ -646,8 +673,11 @@
     // Clear the active sensor handles so they are not disabled during TearDown
     auto handles = mSensorHandles;
     mSensorHandles.clear();
-    getEnvironment()->TearDown();
-    getEnvironment()->SetUp();
+    getEnvironment()->HidlTearDown();
+    getEnvironment()->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
 
     // Verify no events are received until sensors are re-activated
     ASSERT_EQ(collectEvents(kCollectionTimeoutUs, kNumEvents, getEnvironment()).size(), 0);
@@ -686,7 +716,7 @@
     }
 
     // Wait up to one second for the flush events
-    callback.waitForFlushEvents(sensors, flushCalls, 1000 /* timeoutMs */);
+    callback.waitForFlushEvents(sensors, flushCalls, milliseconds(1000) /* timeout */);
 
     // Deactivate all sensors after waiting for flush events so pending flush events are not
     // abandoned by the HAL.
@@ -761,7 +791,12 @@
     activateAllSensors(false /* enable */);
     for (const SensorInfo& sensor : getSensorsList()) {
         // Call batch on inactive sensor
-        ASSERT_EQ(batch(sensor.sensorHandle, sensor.minDelay, 0 /* maxReportLatencyNs */),
+        // One shot sensors have minDelay set to -1 which is an invalid
+        // parameter. Use 0 instead to avoid errors.
+        int64_t samplingPeriodNs = extractReportMode(sensor.flags) == SensorFlagBits::ONE_SHOT_MODE
+                                           ? 0
+                                           : sensor.minDelay;
+        ASSERT_EQ(batch(sensor.sensorHandle, samplingPeriodNs, 0 /* maxReportLatencyNs */),
                   Result::OK);
 
         // Activate the sensor
@@ -807,17 +842,19 @@
 }
 
 TEST_F(SensorsHidlTest, NoStaleEvents) {
-    constexpr int64_t kFiveHundredMilliseconds = 500 * 1000;
-    constexpr int64_t kOneSecond = 1000 * 1000;
+    constexpr milliseconds kFiveHundredMs(500);
+    constexpr milliseconds kOneSecond(1000);
 
     // Register the callback to receive sensor events
     EventCallback callback;
     getEnvironment()->registerCallback(&callback);
 
-    const std::vector<SensorInfo> sensors = getSensorsList();
-    int32_t maxMinDelay = 0;
-    for (const SensorInfo& sensor : getSensorsList()) {
-        maxMinDelay = std::max(maxMinDelay, sensor.minDelay);
+    // This test is not valid for one-shot or special-report-mode sensors
+    const std::vector<SensorInfo> sensors = getNonOneShotAndNonSpecialSensors();
+    milliseconds maxMinDelay(0);
+    for (const SensorInfo& sensor : sensors) {
+        milliseconds minDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+        maxMinDelay = milliseconds(std::max(maxMinDelay.count(), minDelay.count()));
     }
 
     // Activate the sensors so that they start generating events
@@ -826,33 +863,46 @@
     // According to the CDD, the first sample must be generated within 400ms + 2 * sample_time
     // and the maximum reporting latency is 100ms + 2 * sample_time. Wait a sufficient amount
     // of time to guarantee that a sample has arrived.
-    callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
+    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
     activateAllSensors(false);
 
     // Save the last received event for each sensor
     std::map<int32_t, int64_t> lastEventTimestampMap;
     for (const SensorInfo& sensor : sensors) {
-        ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
-        lastEventTimestampMap[sensor.sensorHandle] =
-            callback.getEvents(sensor.sensorHandle).back().timestamp;
+        // Some on-change sensors may not report an event without stimulus
+        if (extractReportMode(sensor.flags) != SensorFlagBits::ON_CHANGE_MODE) {
+            ASSERT_GE(callback.getEvents(sensor.sensorHandle).size(), 1);
+        }
+        if (callback.getEvents(sensor.sensorHandle).size() >= 1) {
+            lastEventTimestampMap[sensor.sensorHandle] =
+                    callback.getEvents(sensor.sensorHandle).back().timestamp;
+        }
     }
 
     // Allow some time to pass, reset the callback, then reactivate the sensors
-    usleep(kOneSecond + (5 * maxMinDelay));
+    usleep(duration_cast<microseconds>(kOneSecond + (5 * maxMinDelay)).count());
     callback.reset();
     activateAllSensors(true);
-    callback.waitForEvents(sensors, kFiveHundredMilliseconds + (5 * maxMinDelay));
+    callback.waitForEvents(sensors, kFiveHundredMs + (5 * maxMinDelay));
     activateAllSensors(false);
 
     for (const SensorInfo& sensor : sensors) {
+        // Skip sensors that did not previously report an event
+        if (lastEventTimestampMap.find(sensor.sensorHandle) == lastEventTimestampMap.end()) {
+            continue;
+        }
+        // Skip on-change sensors that do not consistently report an initial event
+        if (callback.getEvents(sensor.sensorHandle).size() < 1) {
+            continue;
+        }
         // Ensure that the first event received is not stale by ensuring that its timestamp is
         // sufficiently different from the previous event
         const Event newEvent = callback.getEvents(sensor.sensorHandle).front();
-        int64_t delta = newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle];
-        ASSERT_GE(delta, kFiveHundredMilliseconds + (3 * sensor.minDelay));
+        milliseconds delta = duration_cast<milliseconds>(
+                nanoseconds(newEvent.timestamp - lastEventTimestampMap[sensor.sensorHandle]));
+        milliseconds sensorMinDelay = duration_cast<milliseconds>(microseconds(sensor.minDelay));
+        ASSERT_GE(delta, kFiveHundredMs + (3 * sensorMinDelay));
     }
-
-    getEnvironment()->unregisterCallback();
 }
 
 void SensorsHidlTest::checkRateLevel(const SensorInfo& sensor, int32_t directChannelHandle,
@@ -861,21 +911,43 @@
                        [&](Result result, int32_t reportToken) {
                            if (isDirectReportRateSupported(sensor, rateLevel)) {
                                ASSERT_EQ(result, Result::OK);
-                               ASSERT_GT(reportToken, 0);
+                               if (rateLevel != RateLevel::STOP) {
+                                   ASSERT_GT(reportToken, 0);
+                               }
                            } else {
                                ASSERT_EQ(result, Result::BAD_VALUE);
                            }
                        });
 }
 
-void SensorsHidlTest::verifyRegisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
-                                                  std::shared_ptr<SensorsTestSharedMemory> mem,
-                                                  int32_t* directChannelHandle) {
+void SensorsHidlTest::queryDirectChannelSupport(SharedMemType memType, bool* supportsSharedMemType,
+                                                bool* supportsAnyDirectChannel) {
+    *supportsSharedMemType = false;
+    *supportsAnyDirectChannel = false;
+    for (const SensorInfo& curSensor : getSensorsList()) {
+        if (isDirectChannelTypeSupported(curSensor, memType)) {
+            *supportsSharedMemType = true;
+        }
+        if (isDirectChannelTypeSupported(curSensor, SharedMemType::ASHMEM) ||
+            isDirectChannelTypeSupported(curSensor, SharedMemType::GRALLOC)) {
+            *supportsAnyDirectChannel = true;
+        }
+
+        if (*supportsSharedMemType && *supportsAnyDirectChannel) {
+            break;
+        }
+    }
+}
+
+void SensorsHidlTest::verifyRegisterDirectChannel(std::shared_ptr<SensorsTestSharedMemory> mem,
+                                                  int32_t* directChannelHandle,
+                                                  bool supportsSharedMemType,
+                                                  bool supportsAnyDirectChannel) {
     char* buffer = mem->getBuffer();
     memset(buffer, 0xff, mem->getSize());
 
     registerDirectChannel(mem->getSharedMemInfo(), [&](Result result, int32_t channelHandle) {
-        if (isDirectChannelTypeSupported(sensor, memType)) {
+        if (supportsSharedMemType) {
             ASSERT_EQ(result, Result::OK);
             ASSERT_GT(channelHandle, 0);
 
@@ -884,7 +956,9 @@
                 ASSERT_EQ(buffer[i], 0x00);
             }
         } else {
-            ASSERT_EQ(result, Result::INVALID_OPERATION);
+            Result expectedResult =
+                    supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
+            ASSERT_EQ(result, expectedResult);
             ASSERT_EQ(channelHandle, -1);
         }
         *directChannelHandle = channelHandle;
@@ -892,7 +966,7 @@
 }
 
 void SensorsHidlTest::verifyConfigure(const SensorInfo& sensor, SharedMemType memType,
-                                      int32_t directChannelHandle) {
+                                      int32_t directChannelHandle, bool supportsAnyDirectChannel) {
     if (isDirectChannelTypeSupported(sensor, memType)) {
         // Verify that each rate level is properly supported
         checkRateLevel(sensor, directChannelHandle, RateLevel::NORMAL);
@@ -908,22 +982,22 @@
             -1 /* sensorHandle */, directChannelHandle, RateLevel::STOP,
             [](Result result, int32_t /* reportToken */) { ASSERT_EQ(result, Result::OK); });
     } else {
-        // Direct channel is not supported for this SharedMemType
+        // directChannelHandle will be -1 here, HAL should either reject it as a bad value if there
+        // is some level of direct channel report, otherwise return INVALID_OPERATION if direct
+        // channel is not supported at all
+        Result expectedResult =
+                supportsAnyDirectChannel ? Result::BAD_VALUE : Result::INVALID_OPERATION;
         configDirectReport(sensor.sensorHandle, directChannelHandle, RateLevel::NORMAL,
-                           [](Result result, int32_t /* reportToken */) {
-                               ASSERT_EQ(result, Result::INVALID_OPERATION);
+                           [expectedResult](Result result, int32_t /* reportToken */) {
+                               ASSERT_EQ(result, expectedResult);
                            });
     }
 }
 
-void SensorsHidlTest::verifyUnregisterDirectChannel(const SensorInfo& sensor, SharedMemType memType,
-                                                    int32_t directChannelHandle) {
-    Result result = unregisterDirectChannel(directChannelHandle);
-    if (isDirectChannelTypeSupported(sensor, memType)) {
-        ASSERT_EQ(result, Result::OK);
-    } else {
-        ASSERT_EQ(result, Result::INVALID_OPERATION);
-    }
+void SensorsHidlTest::verifyUnregisterDirectChannel(int32_t directChannelHandle,
+                                                    bool supportsAnyDirectChannel) {
+    Result expectedResult = supportsAnyDirectChannel ? Result::OK : Result::INVALID_OPERATION;
+    ASSERT_EQ(unregisterDirectChannel(directChannelHandle), expectedResult);
 }
 
 void SensorsHidlTest::verifyDirectChannel(SharedMemType memType) {
@@ -934,11 +1008,16 @@
         SensorsTestSharedMemory::create(memType, kMemSize));
     ASSERT_NE(mem, nullptr);
 
+    bool supportsSharedMemType;
+    bool supportsAnyDirectChannel;
+    queryDirectChannelSupport(memType, &supportsSharedMemType, &supportsAnyDirectChannel);
+
     for (const SensorInfo& sensor : getSensorsList()) {
         int32_t directChannelHandle = 0;
-        verifyRegisterDirectChannel(sensor, memType, mem, &directChannelHandle);
-        verifyConfigure(sensor, memType, directChannelHandle);
-        verifyUnregisterDirectChannel(sensor, memType, directChannelHandle);
+        verifyRegisterDirectChannel(mem, &directChannelHandle, supportsSharedMemType,
+                                    supportsAnyDirectChannel);
+        verifyConfigure(sensor, memType, directChannelHandle, supportsAnyDirectChannel);
+        verifyUnregisterDirectChannel(directChannelHandle, supportsAnyDirectChannel);
     }
 }
 
@@ -1030,8 +1109,11 @@
     // Clear the active direct connections so they are not stopped during TearDown
     auto handles = mDirectChannelHandles;
     mDirectChannelHandles.clear();
-    getEnvironment()->TearDown();
-    getEnvironment()->SetUp();
+    getEnvironment()->HidlTearDown();
+    getEnvironment()->HidlSetUp();
+    if (HasFatalFailure()) {
+        return;  // Exit early if resetting the environment failed
+    }
 
     // Attempt to configure the direct channel and expect it to fail
     configDirectReport(
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp
index 95df425..02dc608 100644
--- a/sensors/common/vts/utils/Android.bp
+++ b/sensors/common/vts/utils/Android.bp
@@ -16,6 +16,7 @@
 
 cc_library_static {
     name: "VtsHalSensorsTargetTestUtils",
+    cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""],
     srcs: [
         "GrallocWrapper.cpp",
         "SensorsHidlEnvironmentBase.cpp",
@@ -30,7 +31,10 @@
     ],
     static_libs: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.allocator@3.0",
         "android.hardware.graphics.mapper@2.0",
+        "android.hardware.graphics.mapper@2.1",
+        "android.hardware.graphics.mapper@3.0",
         "android.hardware.sensors@1.0",
         "VtsHalHidlTargetTestBase",
     ],
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp
index 7bed16d..1cad913 100644
--- a/sensors/common/vts/utils/GrallocWrapper.cpp
+++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -14,211 +14,264 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "GrallocWrapper"
-
 #include "GrallocWrapper.h"
 
+#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
+#include <android/hardware/graphics/allocator/3.0/IAllocator.h>
+#include <android/hardware/graphics/mapper/2.0/IMapper.h>
+#include <android/hardware/graphics/mapper/2.1/IMapper.h>
+#include <android/hardware/graphics/mapper/3.0/IMapper.h>
+
 #include <utils/Log.h>
 
+#include <cinttypes>
+#include <type_traits>
+
+using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator;
+using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator;
+using IMapper2 = ::android::hardware::graphics::mapper::V2_0::IMapper;
+using IMapper2_1 = ::android::hardware::graphics::mapper::V2_1::IMapper;
+using IMapper3 = ::android::hardware::graphics::mapper::V3_0::IMapper;
+
+using Error2 = ::android::hardware::graphics::mapper::V2_0::Error;
+using Error3 = ::android::hardware::graphics::mapper::V3_0::Error;
+
+using ::android::hardware::graphics::common::V1_0::BufferUsage;
+using ::android::hardware::graphics::common::V1_0::PixelFormat;
+
+// This is a typedef to the same underlying type across v2.0 and v3.0
+using ::android::hardware::graphics::mapper::V2_0::BufferDescriptor;
+
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
 namespace android {
 
-GrallocWrapper::GrallocWrapper() {
-    init();
+// Since we use the same APIs across allocator/mapper HALs but they have major
+// version differences (meaning they are not related through inheritance), we
+// create a common interface abstraction for the IAllocator + IMapper combination
+// (major versions need to match in the current HALs, e.g. IAllocator 3.0 needs to
+// be paired with IMapper 3.0, so these are tied together)
+class IGrallocHalWrapper {
+  public:
+    virtual ~IGrallocHalWrapper() = default;
+
+    // IAllocator
+    virtual std::string dumpDebugInfo() = 0;
+    virtual native_handle_t* allocate(uint32_t size) = 0;
+    virtual void freeBuffer(native_handle_t* bufferHandle) = 0;
+
+    // IMapper
+    virtual void* lock(native_handle_t* bufferHandle) = 0;
+    virtual void unlock(native_handle_t* bufferHandle) = 0;
+};
+
+namespace {
+
+bool failed(Error2 error) {
+    return (error != Error2::NONE);
+}
+bool failed(Error3 error) {
+    return (error != Error3::NONE);
 }
 
-void GrallocWrapper::init() {
-    mAllocator = allocator2::IAllocator::getService();
-    if (mAllocator == nullptr) {
-        ALOGE("Failed to get allocator service");
-    }
-
-    mMapper = mapper2::IMapper::getService();
-    if (mMapper == nullptr) {
-        ALOGE("Failed to get mapper service");
-    }
-    if (mMapper->isRemote()) {
-        ALOGE("Mapper is not in passthrough mode");
-    }
-}
-
-GrallocWrapper::~GrallocWrapper() {
-    for (auto bufferHandle : mClonedBuffers) {
-        auto buffer = const_cast<native_handle_t*>(bufferHandle);
-        native_handle_close(buffer);
-        native_handle_delete(buffer);
-    }
-    mClonedBuffers.clear();
-
-    for (auto bufferHandle : mImportedBuffers) {
-        auto buffer = const_cast<native_handle_t*>(bufferHandle);
-        if (mMapper->freeBuffer(buffer) != mapper2::Error::NONE) {
-            ALOGE("Failed to free buffer %p", buffer);
+// Since all the type and function names are the same for the things we use across the major HAL
+// versions, we use template magic to avoid repeating ourselves.
+template <typename AllocatorT, typename MapperT>
+class GrallocHalWrapper : public IGrallocHalWrapper {
+  public:
+    GrallocHalWrapper(const sp<AllocatorT>& allocator, const sp<MapperT>& mapper)
+        : mAllocator(allocator), mMapper(mapper) {
+        if (mapper->isRemote()) {
+            ALOGE("Mapper is in passthrough mode");
         }
     }
-    mImportedBuffers.clear();
-}
 
-sp<allocator2::IAllocator> GrallocWrapper::getAllocator() const {
-    return mAllocator;
-}
+    virtual std::string dumpDebugInfo() override;
+    virtual native_handle_t* allocate(uint32_t size) override;
+    virtual void freeBuffer(native_handle_t* bufferHandle) override;
 
-std::string GrallocWrapper::dumpDebugInfo() {
+    virtual void* lock(native_handle_t* bufferHandle) override;
+    virtual void unlock(native_handle_t* bufferHandle) override;
+
+  private:
+    static constexpr uint64_t kBufferUsage =
+            static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN);
+    sp<AllocatorT> mAllocator;
+    sp<MapperT> mMapper;
+
+    BufferDescriptor getDescriptor(uint32_t size);
+    native_handle_t* importBuffer(const hidl_handle& rawHandle);
+};
+
+template <typename AllocatorT, typename MapperT>
+std::string GrallocHalWrapper<AllocatorT, MapperT>::dumpDebugInfo() {
     std::string debugInfo;
-    mAllocator->dumpDebugInfo([&](const auto& tmpDebugInfo) { debugInfo = tmpDebugInfo.c_str(); });
-
+    mAllocator->dumpDebugInfo([&](const hidl_string& tmpDebugInfo) { debugInfo = tmpDebugInfo; });
     return debugInfo;
 }
 
-const native_handle_t* GrallocWrapper::cloneBuffer(const hardware::hidl_handle& rawHandle) {
-    const native_handle_t* bufferHandle = native_handle_clone(rawHandle.getNativeHandle());
+template <typename AllocatorT, typename MapperT>
+native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) {
+    constexpr uint32_t kBufferCount = 1;
+    BufferDescriptor descriptor = getDescriptor(size);
+    native_handle_t* bufferHandle = nullptr;
 
-    if (bufferHandle) {
-        mClonedBuffers.insert(bufferHandle);
-    }
+    auto callback = [&](auto error, uint32_t /*stride*/, const hidl_vec<hidl_handle>& buffers) {
+        if (failed(error)) {
+            ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error));
+        } else if (buffers.size() != kBufferCount) {
+            ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", buffers.size(),
+                  kBufferCount);
+        } else {
+            bufferHandle = importBuffer(buffers[0]);
+        }
+    };
+
+    mAllocator->allocate(descriptor, kBufferCount, callback);
     return bufferHandle;
 }
 
-std::vector<const native_handle_t*> GrallocWrapper::allocate(
-    const mapper2::BufferDescriptor& descriptor, uint32_t count, bool import, uint32_t* outStride) {
-    std::vector<const native_handle_t*> bufferHandles;
-    bufferHandles.reserve(count);
-    mAllocator->allocate(descriptor, count,
-                         [&](const auto& tmpError, const auto& tmpStride, const auto& tmpBuffers) {
-                             if (mapper2::Error::NONE != tmpError) {
-                                 ALOGE("Failed to allocate buffers");
-                             }
-                             if (count != tmpBuffers.size()) {
-                                 ALOGE("Invalid buffer array");
-                             }
-
-                             for (uint32_t i = 0; i < count; i++) {
-                                 if (import) {
-                                     bufferHandles.push_back(importBuffer(tmpBuffers[i]));
-                                 } else {
-                                     bufferHandles.push_back(cloneBuffer(tmpBuffers[i]));
-                                 }
-                             }
-
-                             if (outStride) {
-                                 *outStride = tmpStride;
-                             }
-                         });
-
-    return bufferHandles;
+template <typename AllocatorT, typename MapperT>
+void GrallocHalWrapper<AllocatorT, MapperT>::freeBuffer(native_handle_t* bufferHandle) {
+    auto error = mMapper->freeBuffer(bufferHandle);
+    if (!error.isOk() || failed(error)) {
+        ALOGE("Failed to free buffer %p", bufferHandle);
+    }
 }
 
-const native_handle_t* GrallocWrapper::allocate(
-    const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo, bool import,
-    uint32_t* outStride) {
-    mapper2::BufferDescriptor descriptor = createDescriptor(descriptorInfo);
-    auto buffers = allocate(descriptor, 1, import, outStride);
-    return buffers[0];
-}
+template <typename AllocatorT, typename MapperT>
+BufferDescriptor GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) {
+    typename MapperT::BufferDescriptorInfo descriptorInfo = {
+            .width = size,
+            .height = 1,
+            .layerCount = 1,
+            .usage = kBufferUsage,
+            .format = static_cast<decltype(descriptorInfo.format)>(PixelFormat::BLOB),
+    };
 
-sp<mapper2::IMapper> GrallocWrapper::getMapper() const {
-    return mMapper;
-}
-
-mapper2::BufferDescriptor GrallocWrapper::createDescriptor(
-    const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo) {
-    mapper2::BufferDescriptor descriptor;
-    mMapper->createDescriptor(descriptorInfo, [&](const auto& tmpError, const auto& tmpDescriptor) {
-        if (tmpError != mapper2::Error::NONE) {
-            ALOGE("Failed to create descriptor");
+    BufferDescriptor descriptor;
+    auto callback = [&](auto error, const BufferDescriptor& tmpDescriptor) {
+        if (failed(error)) {
+            ALOGE("Failed to create descriptor: %" PRId32, static_cast<int32_t>(error));
+        } else {
+            descriptor = tmpDescriptor;
         }
-        descriptor = tmpDescriptor;
-    });
+    };
 
+    mMapper->createDescriptor(descriptorInfo, callback);
     return descriptor;
 }
 
-const native_handle_t* GrallocWrapper::importBuffer(const hardware::hidl_handle& rawHandle) {
-    const native_handle_t* bufferHandle = nullptr;
-    mMapper->importBuffer(rawHandle, [&](const auto& tmpError, const auto& tmpBuffer) {
-        if (tmpError != mapper2::Error::NONE) {
-            ALOGE("Failed to import buffer %p", rawHandle.getNativeHandle());
-        }
-        bufferHandle = static_cast<const native_handle_t*>(tmpBuffer);
-    });
+template <typename AllocatorT, typename MapperT>
+native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::importBuffer(
+        const hidl_handle& rawHandle) {
+    native_handle_t* bufferHandle = nullptr;
 
-    if (bufferHandle) {
-        mImportedBuffers.insert(bufferHandle);
-    }
+    mMapper->importBuffer(rawHandle, [&](auto error, void* tmpBuffer) {
+        if (failed(error)) {
+            ALOGE("Failed to import buffer %p: %" PRId32, rawHandle.getNativeHandle(),
+                  static_cast<int32_t>(error));
+        } else {
+            bufferHandle = static_cast<native_handle_t*>(tmpBuffer);
+        }
+    });
 
     return bufferHandle;
 }
 
-void GrallocWrapper::freeBuffer(const native_handle_t* bufferHandle) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    if (mImportedBuffers.erase(bufferHandle)) {
-        mapper2::Error error = mMapper->freeBuffer(buffer);
-        if (error != mapper2::Error::NONE) {
-            ALOGE("Failed to free %p", buffer);
-        }
-    } else {
-        mClonedBuffers.erase(bufferHandle);
-        native_handle_close(buffer);
-        native_handle_delete(buffer);
-    }
-}
-
-void* GrallocWrapper::lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-                           const mapper2::IMapper::Rect& accessRegion, int acquireFence) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    NATIVE_HANDLE_DECLARE_STORAGE(acquireFenceStorage, 1, 0);
-    hardware::hidl_handle acquireFenceHandle;
-    if (acquireFence >= 0) {
-        auto h = native_handle_init(acquireFenceStorage, 1, 0);
-        h->data[0] = acquireFence;
-        acquireFenceHandle = h;
-    }
+template <typename AllocatorT, typename MapperT>
+void* GrallocHalWrapper<AllocatorT, MapperT>::lock(native_handle_t* bufferHandle) {
+    // Per the HAL, all-zeros Rect means the entire buffer
+    typename MapperT::Rect accessRegion = {};
+    hidl_handle acquireFenceHandle;  // No fence needed, already safe to lock
 
     void* data = nullptr;
-    mMapper->lock(buffer, cpuUsage, accessRegion, acquireFenceHandle,
-                  [&](const auto& tmpError, const auto& tmpData) {
-                      if (tmpError != mapper2::Error::NONE) {
-                          ALOGE("Failed to lock buffer %p", buffer);
+    mMapper->lock(bufferHandle, kBufferUsage, accessRegion, acquireFenceHandle,
+                  [&](auto error, void* tmpData, ...) {  // V3_0 passes extra args we don't use
+                      if (failed(error)) {
+                          ALOGE("Failed to lock buffer %p: %" PRId32, bufferHandle,
+                                static_cast<int32_t>(error));
+                      } else {
+                          data = tmpData;
                       }
-                      data = tmpData;
                   });
 
-    if (acquireFence >= 0) {
-        close(acquireFence);
-    }
-
     return data;
 }
 
-int GrallocWrapper::unlock(const native_handle_t* bufferHandle) {
-    auto buffer = const_cast<native_handle_t*>(bufferHandle);
-
-    int releaseFence = -1;
-    mMapper->unlock(buffer, [&](const auto& tmpError, const auto& tmpReleaseFence) {
-        if (tmpError != mapper2::Error::NONE) {
-            ALOGE("Failed to unlock buffer %p", buffer);
-        }
-
-        auto fenceHandle = tmpReleaseFence.getNativeHandle();
-        if (fenceHandle) {
-            if (fenceHandle->numInts != 0) {
-                ALOGE("Invalid fence handle %p", fenceHandle);
-            }
-            if (fenceHandle->numFds == 1) {
-                releaseFence = dup(fenceHandle->data[0]);
-                if (releaseFence < 0) {
-                    ALOGE("Failed to dup fence fd");
-                }
-            } else {
-                if (fenceHandle->numFds != 0) {
-                    ALOGE("Invalid fence handle %p", fenceHandle);
-                }
-            }
+template <typename AllocatorT, typename MapperT>
+void GrallocHalWrapper<AllocatorT, MapperT>::unlock(native_handle_t* bufferHandle) {
+    mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) {
+        if (failed(error)) {
+            ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle,
+                  static_cast<int32_t>(error));
         }
     });
+}
 
-    return releaseFence;
+}  // anonymous namespace
+
+GrallocWrapper::GrallocWrapper() {
+    sp<IAllocator3> allocator3 = IAllocator3::getService();
+    sp<IMapper3> mapper3 = IMapper3::getService();
+
+    if (allocator3 != nullptr && mapper3 != nullptr) {
+        mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
+                new GrallocHalWrapper<IAllocator3, IMapper3>(allocator3, mapper3));
+    } else {
+        ALOGD("Graphics HALs 3.0 not found (allocator %d mapper %d), falling back to 2.x",
+              (allocator3 != nullptr), (mapper3 != nullptr));
+
+        sp<IAllocator2> allocator2 = IAllocator2::getService();
+        sp<IMapper2> mapper2 = IMapper2_1::getService();
+        if (mapper2 == nullptr) {
+            mapper2 = IMapper2::getService();
+        }
+
+        if (allocator2 != nullptr && mapper2 != nullptr) {
+            mGrallocHal = std::unique_ptr<IGrallocHalWrapper>(
+                    new GrallocHalWrapper<IAllocator2, IMapper2>(allocator2, mapper2));
+        } else {
+            ALOGE("Couldn't open 2.x/3.0 graphics HALs (2.x allocator %d mapper %d)",
+                  (allocator2 != nullptr), (mapper2 != nullptr));
+        }
+    }
+}
+
+GrallocWrapper::~GrallocWrapper() {
+    for (auto bufferHandle : mAllocatedBuffers) {
+        mGrallocHal->unlock(bufferHandle);
+        mGrallocHal->freeBuffer(bufferHandle);
+    }
+    mAllocatedBuffers.clear();
+}
+
+std::string GrallocWrapper::dumpDebugInfo() {
+    return mGrallocHal->dumpDebugInfo();
+}
+
+std::pair<native_handle_t*, void*> GrallocWrapper::allocate(uint32_t size) {
+    native_handle_t* bufferHandle = mGrallocHal->allocate(size);
+    void* buffer = nullptr;
+    if (bufferHandle) {
+        buffer = mGrallocHal->lock(bufferHandle);
+        if (buffer) {
+            mAllocatedBuffers.insert(bufferHandle);
+        } else {
+            mGrallocHal->freeBuffer(bufferHandle);
+            bufferHandle = nullptr;
+        }
+    }
+    return std::make_pair<>(bufferHandle, buffer);
+}
+
+void GrallocWrapper::freeBuffer(native_handle_t* bufferHandle) {
+    if (mAllocatedBuffers.erase(bufferHandle)) {
+        mGrallocHal->unlock(bufferHandle);
+        mGrallocHal->freeBuffer(bufferHandle);
+    }
 }
 
 }  // namespace android
diff --git a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
index affdf8b..fa0e2e9 100644
--- a/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
+++ b/sensors/common/vts/utils/SensorsHidlEnvironmentBase.cpp
@@ -29,7 +29,9 @@
 
 void SensorsHidlEnvironmentBase::HidlTearDown() {
     mStopThread = true;
-    mPollThread.detach();
+    if (mPollThread.joinable()) {
+        mPollThread.detach();
+    }
 }
 
 void SensorsHidlEnvironmentBase::catEvents(std::vector<Event>* output) {
diff --git a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
index 819e297..3b068bd 100644
--- a/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
+++ b/sensors/common/vts/utils/SensorsTestSharedMemory.cpp
@@ -119,32 +119,13 @@
         }
         case SharedMemType::GRALLOC: {
             mGrallocWrapper = std::make_unique<::android::GrallocWrapper>();
-            if (mGrallocWrapper->getAllocator() == nullptr ||
-                mGrallocWrapper->getMapper() == nullptr) {
+            if (!mGrallocWrapper->isInitialized()) {
                 break;
             }
-            using android::hardware::graphics::common::V1_0::BufferUsage;
-            using android::hardware::graphics::common::V1_0::PixelFormat;
-            mapper2::IMapper::BufferDescriptorInfo buf_desc_info = {
-                .width = static_cast<uint32_t>(size),
-                .height = 1,
-                .layerCount = 1,
-                .usage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA |
-                                               BufferUsage::CPU_READ_OFTEN),
-                .format = PixelFormat::BLOB};
 
-            handle = const_cast<native_handle_t*>(mGrallocWrapper->allocate(buf_desc_info));
-            if (handle != nullptr) {
-                mapper2::IMapper::Rect region{0, 0, static_cast<int32_t>(buf_desc_info.width),
-                                              static_cast<int32_t>(buf_desc_info.height)};
-                buffer = static_cast<char*>(
-                    mGrallocWrapper->lock(handle, buf_desc_info.usage, region, /*fence=*/-1));
-                if (buffer != nullptr) {
-                    break;
-                }
-                mGrallocWrapper->freeBuffer(handle);
-                handle = nullptr;
-            }
+            std::pair<native_handle_t*, void*> buf = mGrallocWrapper->allocate(size);
+            handle = buf.first;
+            buffer = static_cast<char*>(buf.second);
             break;
         }
         default:
@@ -175,9 +156,7 @@
         }
         case SharedMemType::GRALLOC: {
             if (mSize != 0) {
-                mGrallocWrapper->unlock(mNativeHandle);
                 mGrallocWrapper->freeBuffer(mNativeHandle);
-
                 mNativeHandle = nullptr;
                 mSize = 0;
             }
diff --git a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
index 3bd73c3..41e6334 100644
--- a/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
+++ b/sensors/common/vts/utils/include/sensors-vts-utils/GrallocWrapper.h
@@ -14,66 +14,47 @@
  * limitations under the License.
  */
 
-#ifndef GRALLO_WRAPPER_H_
-#define GRALLO_WRAPPER_H_
+#pragma once
 
+#include <utils/NativeHandle.h>
+
+#include <memory>
+#include <string>
 #include <unordered_set>
-
-#include <android/hardware/graphics/allocator/2.0/IAllocator.h>
-#include <android/hardware/graphics/mapper/2.0/IMapper.h>
-
-namespace allocator2 = ::android::hardware::graphics::allocator::V2_0;
-namespace mapper2 = ::android::hardware::graphics::mapper::V2_0;
+#include <utility>
 
 namespace android {
 
-// Modified from hardware/interfaces/graphics/mapper/2.0/vts/functional/
+class IGrallocHalWrapper;
+
+// Reference: hardware/interfaces/graphics/mapper/2.0/vts/functional/
 class GrallocWrapper {
    public:
     GrallocWrapper();
     ~GrallocWrapper();
 
-    sp<allocator2::IAllocator> getAllocator() const;
-    sp<mapper2::IMapper> getMapper() const;
+    // After constructing this object, this function must be called to check the result. If it
+    // returns false, other methods are not safe to call.
+    bool isInitialized() const { return (mGrallocHal != nullptr); };
 
     std::string dumpDebugInfo();
 
-    // When import is false, this simply calls IAllocator::allocate. When import
-    // is true, the returned buffers are also imported into the mapper.
-    //
-    // Either case, the returned buffers must be freed with freeBuffer.
-    std::vector<const native_handle_t*> allocate(const mapper2::BufferDescriptor& descriptor,
-                                                 uint32_t count, bool import = true,
-                                                 uint32_t* outStride = nullptr);
-    const native_handle_t* allocate(const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo,
-                                    bool import = true, uint32_t* outStride = nullptr);
+    // Allocates a gralloc buffer suitable for direct channel sensors usage with the given size.
+    // The buffer should be freed using freeBuffer when it's not needed anymore; otherwise it'll
+    // be freed when this object is destroyed.
+    // Returns a handle to the buffer, and a CPU-accessible pointer for reading. On failure, both
+    // will be set to nullptr.
+    std::pair<native_handle_t*, void*> allocate(uint32_t size);
 
-    mapper2::BufferDescriptor createDescriptor(
-        const mapper2::IMapper::BufferDescriptorInfo& descriptorInfo);
+    // Releases a gralloc buffer previously returned by allocate()
+    void freeBuffer(native_handle_t* bufferHandle);
 
-    const native_handle_t* importBuffer(const hardware::hidl_handle& rawHandle);
-    void freeBuffer(const native_handle_t* bufferHandle);
-
-    // We use fd instead of hardware::hidl_handle in these functions to pass fences
-    // in and out of the mapper.  The ownership of the fd is always transferred
-    // with each of these functions.
-    void* lock(const native_handle_t* bufferHandle, uint64_t cpuUsage,
-               const mapper2::IMapper::Rect& accessRegion, int acquireFence);
-
-    int unlock(const native_handle_t* bufferHandle);
-
-   private:
-    void init();
-    const native_handle_t* cloneBuffer(const hardware::hidl_handle& rawHandle);
-
-    sp<allocator2::IAllocator> mAllocator;
-    sp<mapper2::IMapper> mMapper;
+  private:
+    std::unique_ptr<IGrallocHalWrapper> mGrallocHal;
 
     // Keep track of all cloned and imported handles.  When a test fails with
     // ASSERT_*, the destructor will free the handles for the test.
-    std::unordered_set<const native_handle_t*> mClonedBuffers;
-    std::unordered_set<const native_handle_t*> mImportedBuffers;
+    std::unordered_set<native_handle_t*> mAllocatedBuffers;
 };
 
 }  // namespace android
-#endif  // GRALLO_WRAPPER_H_
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/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
index 26a58b2..ffd4d97 100644
--- a/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
+++ b/wifi/hostapd/1.1/vts/functional/hostapd_hidl_test.cpp
@@ -56,6 +56,9 @@
    protected:
     std::string getPrimaryWlanIfaceName() {
         std::array<char, PROPERTY_VALUE_MAX> buffer;
+        auto res = property_get("ro.vendor.wifi.sap.interface",
+                                buffer.data(), nullptr);
+        if (res > 0) return buffer.data();
         property_get("wifi.interface", buffer.data(), "wlan0");
         return buffer.data();
     }
diff --git a/wifi/offload/1.0/vts/functional/Android.bp b/wifi/offload/1.0/vts/functional/Android.bp
index de15aa7..965c946 100644
--- a/wifi/offload/1.0/vts/functional/Android.bp
+++ b/wifi/offload/1.0/vts/functional/Android.bp
@@ -19,5 +19,5 @@
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: ["VtsHalWifiOffloadV1_0TargetTest.cpp"],
     static_libs: ["android.hardware.wifi.offload@1.0"],
-    test_suites: ["general-tests"],
+    test_suites: ["general-tests", "vts-core"],
 }
diff --git a/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp b/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
index dbe4e74..83d834c 100644
--- a/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
+++ b/wifi/offload/1.0/vts/functional/VtsHalWifiOffloadV1_0TargetTest.cpp
@@ -20,10 +20,11 @@
 #include <android/hardware/wifi/offload/1.0/IOffload.h>
 #include <android/hardware/wifi/offload/1.0/IOffloadCallback.h>
 #include <android/hardware/wifi/offload/1.0/types.h>
+#include <gtest/gtest.h>
+#include <hidl/GtestPrinter.h>
+#include <hidl/ServiceManagement.h>
 
 #include <VtsHalHidlTargetCallbackBase.h>
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 
 #include <vector>
 
@@ -69,33 +70,11 @@
     OffloadStatus error_code_;
 };
 
-// Test environment for Weaver HIDL HAL.
-class WifiOffloadHidlEnvironment
-    : public ::testing::VtsHalHidlTargetTestEnvBase {
-   public:
-    // get the test environment singleton
-    static WifiOffloadHidlEnvironment* Instance() {
-        static WifiOffloadHidlEnvironment* instance =
-            new WifiOffloadHidlEnvironment;
-        return instance;
-    }
-
-    virtual void registerTestServices() override {
-        registerTestService<IOffload>();
-    }
-
-   private:
-    WifiOffloadHidlEnvironment() {}
-};
-
 // The main test class for WifiOffload HIDL HAL.
-class WifiOffloadHidlTest : public ::testing::VtsHalHidlTargetTestBase {
+class WifiOffloadHidlTest : public ::testing::TestWithParam<std::string> {
    public:
     virtual void SetUp() override {
-        wifi_offload_ =
-            ::testing::VtsHalHidlTargetTestBase::getService<IOffload>(
-                WifiOffloadHidlEnvironment::Instance()
-                    ->getServiceName<IOffload>());
+        wifi_offload_ = IOffload::getService(GetParam());
         ASSERT_NE(wifi_offload_, nullptr);
 
         wifi_offload_cb_ = new OffloadCallback();
@@ -136,7 +115,7 @@
 /*
  * Verify that setEventCallback method returns without errors
  */
-TEST_F(WifiOffloadHidlTest, setEventCallback) {
+TEST_P(WifiOffloadHidlTest, setEventCallback) {
     auto returnObject = wifi_offload_->setEventCallback(wifi_offload_cb_);
     ASSERT_EQ(true, returnObject.isOk());
 }
@@ -144,7 +123,7 @@
 /*
  * Verify that subscribeScanResults method returns without errors
  */
-TEST_F(WifiOffloadHidlTest, subscribeScanResults) {
+TEST_P(WifiOffloadHidlTest, subscribeScanResults) {
     const auto& result = HIDL_INVOKE(wifi_offload_, subscribeScanResults, 0);
     ASSERT_EQ(OffloadStatusCode::OK, result.code);
 }
@@ -152,7 +131,7 @@
 /*
  * Verify that unsubscribeScanResults method returns without errors
  */
-TEST_F(WifiOffloadHidlTest, unsubscribeScanResults) {
+TEST_P(WifiOffloadHidlTest, unsubscribeScanResults) {
     auto returnObject = wifi_offload_->unsubscribeScanResults();
     ASSERT_EQ(true, returnObject.isOk());
 }
@@ -160,7 +139,7 @@
 /*
  * Verify that configureScans method returns without errors
  */
-TEST_F(WifiOffloadHidlTest, configureScans) {
+TEST_P(WifiOffloadHidlTest, configureScans) {
     ScanParam* pScanParam = new ScanParam();
     std::vector<uint32_t> frequencyList = {kFrequency1, kFrequency2};
     pScanParam->disconnectedModeScanIntervalMs =
@@ -192,7 +171,7 @@
 /*
  * Verify that getScanStats returns without any errors
  */
-TEST_F(WifiOffloadHidlTest, getScanStats) {
+TEST_P(WifiOffloadHidlTest, getScanStats) {
     const auto& result = HIDL_INVOKE(wifi_offload_, getScanStats);
     OffloadStatus status = result.first;
     ASSERT_EQ(OffloadStatusCode::OK, status.code);
@@ -201,7 +180,7 @@
 /*
  * Verify that onScanResult callback is invoked
  */
-TEST_F(WifiOffloadHidlTest, getScanResults) {
+TEST_P(WifiOffloadHidlTest, getScanResults) {
     wifi_offload_->setEventCallback(wifi_offload_cb_);
     std::vector<ScanResult> scan_results;
     std::vector<uint8_t> ssid(kSsid1, kSsid1 + sizeof(kSsid1));
@@ -223,7 +202,7 @@
 /*
  * Verify that onError callback is invoked
  */
-TEST_F(WifiOffloadHidlTest, getError) {
+TEST_P(WifiOffloadHidlTest, getError) {
     wifi_offload_->setEventCallback(wifi_offload_cb_);
     OffloadStatus status = {OffloadStatusCode::ERROR, ""};
     wifi_offload_cb_->onError(status);
@@ -231,12 +210,8 @@
     ASSERT_EQ(true, res.no_timeout);
 }
 
-int main(int argc, char** argv) {
-    ::testing::AddGlobalTestEnvironment(WifiOffloadHidlEnvironment::Instance());
-    ::testing::InitGoogleTest(&argc, argv);
-    WifiOffloadHidlEnvironment::Instance()->init(&argc, argv);
-    int status = RUN_ALL_TESTS();
-    LOG(INFO) << "Test result = " << status;
-
-    return status;
-}
+INSTANTIATE_TEST_SUITE_P(
+    PerInstance, WifiOffloadHidlTest,
+    testing::ValuesIn(
+        android::hardware::getAllHalInstanceNames(IOffload::descriptor)),
+    android::hardware::PrintInstanceNameToString);
\ No newline at end of file
diff --git a/wifi/offload/1.0/vts/functional/hidl_call_util.h b/wifi/offload/1.0/vts/functional/hidl_call_util.h
index f3ca517..99868e8 100644
--- a/wifi/offload/1.0/vts/functional/hidl_call_util.h
+++ b/wifi/offload/1.0/vts/functional/hidl_call_util.h
@@ -21,8 +21,6 @@
 #include <type_traits>
 #include <utility>
 
-#include <VtsHalHidlTargetTestBase.h>
-
 namespace {
 namespace detail {
 template <typename>