Merge "Use libcrypto_static instead of libcrypto"
diff --git a/current.txt b/current.txt
index 72ba9af..3fabd7c 100644
--- a/current.txt
+++ b/current.txt
@@ -575,6 +575,6 @@
 b69a7615c508acf5c5201efd1bfa3262167874fc3594e2db5a3ff93addd8ac75 android.hardware.keymaster@4.0::IKeymasterDevice
 eb2fa0c883c2185d514be0b84c179b283753ef0c1b77b45b4f359bd23bba8b75 android.hardware.neuralnetworks@1.0::IPreparedModel
 fb382e986c10b8fbb797a8546e8f9ea6d1107bfe6f3fb7e57f6bbbf1f807a906 android.hardware.neuralnetworks@1.2::IDevice
-6c5081dd131eeb7eb02efece2187cd4d7d554197800bb520c92ff874cc238fa6 android.hardware.neuralnetworks@1.2::IPreparedModel
+40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
diff --git a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
index 062f2e5..0af9745 100644
--- a/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
+++ b/graphics/composer/2.1/utils/hwc2on1adapter/Android.bp
@@ -55,6 +55,7 @@
         "-Wno-shorten-64-to-32",
         "-Wno-sign-compare",
         "-Wno-missing-prototypes",
+        "-Wno-format-pedantic",
     ],
 
     srcs: [
diff --git a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
index d9beb4f..db7e67d 100644
--- a/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
+++ b/graphics/mapper/2.0/utils/passthrough/include/mapper-passthrough/2.0/Gralloc1Hal.h
@@ -282,14 +282,16 @@
         }
 
         if (flex.planes[0].component != FLEX_COMPONENT_Y ||
-            flex.planes[1].component != FLEX_COMPONENT_Cb ||
-            flex.planes[2].component != FLEX_COMPONENT_Cr) {
+           ((flex.planes[1].component != FLEX_COMPONENT_Cb || flex.planes[2].component != FLEX_COMPONENT_Cr) &&
+           (flex.planes[2].component != FLEX_COMPONENT_Cb || flex.planes[1].component != FLEX_COMPONENT_Cr))) {
             return false;
         }
 
         const auto& y = flex.planes[0];
-        const auto& cb = flex.planes[1];
-        const auto& cr = flex.planes[2];
+        const auto& cb = (flex.planes[1].component == FLEX_COMPONENT_Cb)?
+                          flex.planes[1] : flex.planes[2];
+        const auto& cr = (flex.planes[2].component == FLEX_COMPONENT_Cr)?
+                          flex.planes[2] : flex.planes[1];
 
         if (cb.h_increment != cr.h_increment || cb.v_increment != cr.v_increment) {
             return false;
diff --git a/neuralnetworks/1.0/vts/functional/Android.bp b/neuralnetworks/1.0/vts/functional/Android.bp
index 0af7f79..3e9d5f7 100644
--- a/neuralnetworks/1.0/vts/functional/Android.bp
+++ b/neuralnetworks/1.0/vts/functional/Android.bp
@@ -40,10 +40,11 @@
     ],
 }
 
-cc_defaults {
-    name: "VtsHalNeuralNetworksV1_0TargetTestDefaults",
+cc_test {
+    name: "VtsHalNeuralnetworksV1_0TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
+        "BasicTests.cpp",
         "TestAssertions.cpp",
         "ValidateModel.cpp",
         "ValidateRequest.cpp",
@@ -64,33 +65,11 @@
         "libneuralnetworks_utils",
         "VtsHalNeuralNetworksV1_0_utils",
     ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+    ],
     header_libs: [
         "libneuralnetworks_headers",
     ],
     test_suites: ["general-tests"],
 }
-
-cc_test {
-    name: "VtsHalNeuralnetworksV1_0TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-    ],
-    whole_static_libs: [
-        "neuralnetworks_generated_V1_0_example",
-    ],
-}
-
-cc_test {
-    name: "PresubmitHalNeuralnetworksV1_0TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_0TargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-    ],
-    whole_static_libs: [
-        "neuralnetworks_generated_V1_0_example",
-    ],
-    cflags: [
-        "-DPRESUBMIT_NOT_VTS",
-    ],
-}
diff --git a/neuralnetworks/1.0/vts/functional/BasicTests.cpp b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
index 551ea67..cc44c9e 100644
--- a/neuralnetworks/1.0/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.0/vts/functional/BasicTests.cpp
@@ -21,17 +21,17 @@
 namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
 // create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+TEST_P(NeuralnetworksHidlTest, CreateDevice) {}
 
 // status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
+TEST_P(NeuralnetworksHidlTest, StatusTest) {
     Return<DeviceStatus> status = kDevice->getStatus();
     ASSERT_TRUE(status.isOk());
     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
 }
 
 // initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) {
     Return<void> ret =
             kDevice->getCapabilities([](ErrorStatus status, const Capabilities& capabilities) {
                 EXPECT_EQ(ErrorStatus::NONE, status);
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
index 1948c05..595ad85 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.cpp
@@ -148,6 +148,20 @@
     checkResults(testModel, outputs);
 }
 
+void GeneratedTestBase::SetUp() {
+    testing::TestWithParam<GeneratedTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
+}
+
+std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
+    const auto& [namedDevice, namedModel] = info.param;
+    return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
+}
+
 // Tag for the generated tests
 class GeneratedTest : public GeneratedTestBase {};
 
diff --git a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
index 10e46b7..f230a02 100644
--- a/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.0/vts/functional/GeneratedTestHarness.h
@@ -18,29 +18,38 @@
 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_GENERATED_TEST_HARNESS_H
 
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
+#include <functional>
 #include "TestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
 namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-class GeneratedTestBase
-    : public NeuralnetworksHidlTest,
-      public testing::WithParamInterface<test_helper::TestModelManager::TestParam> {
+using NamedModel = Named<const test_helper::TestModel*>;
+using GeneratedTestParam = std::tuple<NamedDevice, NamedModel>;
+
+class GeneratedTestBase : public testing::TestWithParam<GeneratedTestParam> {
   protected:
-    const test_helper::TestModel& kTestModel = *GetParam().second;
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
+    const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
 };
 
-#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                        \
-    INSTANTIATE_TEST_SUITE_P(                                                                \
-            TestGenerated, TestSuite,                                                        \
-            testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \
-            [](const auto& info) { return info.param.first; })
+using FilterFn = std::function<bool(const test_helper::TestModel&)>;
+std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
+
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
+    INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite,                                    \
+                             testing::Combine(testing::ValuesIn(getNamedDevices()),       \
+                                              testing::ValuesIn(getNamedModels(filter))), \
+                             printGeneratedTest)
 
 // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
 // TODO: Clean up the hierarchy for ValidationTest.
 class ValidationTest : public GeneratedTestBase {};
 
-Model createModel(const ::test_helper::TestModel& testModel);
+Model createModel(const test_helper::TestModel& testModel);
 
 }  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
 
diff --git a/neuralnetworks/1.0/vts/functional/Utils.cpp b/neuralnetworks/1.0/vts/functional/Utils.cpp
index 307003c..5b630fd 100644
--- a/neuralnetworks/1.0/vts/functional/Utils.cpp
+++ b/neuralnetworks/1.0/vts/functional/Utils.cpp
@@ -117,6 +117,13 @@
     return outputBuffers;
 }
 
+std::string gtestCompliantName(std::string name) {
+    // gtest test names must only contain alphanumeric characters
+    std::replace_if(
+            name.begin(), name.end(), [](char c) { return !std::isalnum(c); }, '_');
+    return name;
+}
+
 }  // namespace android::hardware::neuralnetworks
 
 namespace android::hardware::neuralnetworks::V1_0 {
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
index 20b4565..cb22250 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.cpp
@@ -18,11 +18,13 @@
 
 #include "VtsHalNeuralnetworks.h"
 #include "1.0/Callbacks.h"
-#include "1.0/Utils.h"
 #include "GeneratedTestHarness.h"
 #include "TestHarness.h"
 
 #include <android-base/logging.h>
+#include <hidl/ServiceManagement.h>
+#include <string>
+#include <utility>
 
 namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
@@ -76,34 +78,39 @@
     ASSERT_NE(nullptr, preparedModel->get());
 }
 
-// A class for test environment setup
-NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
-    // This has to return a "new" object because it is freed inside
-    // testing::AddGlobalTestEnvironment when the gtest is being torn down
-    static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
-    return instance;
-}
-
-void NeuralnetworksHidlEnvironment::registerTestServices() {
-    registerTestService<IDevice>();
-}
-
-// The main test class for NEURALNETWORK HIDL HAL.
 void NeuralnetworksHidlTest::SetUp() {
-    testing::VtsHalHidlTargetTestBase::SetUp();
-
-#ifdef PRESUBMIT_NOT_VTS
-    const std::string name =
-            NeuralnetworksHidlEnvironment::getInstance()->getServiceName<IDevice>();
-    const std::string sampleDriver = "sample-";
-    if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) {
-        GTEST_SKIP();
-    }
-#endif  // PRESUBMIT_NOT_VTS
-
-    ASSERT_NE(nullptr, kDevice.get());
+    testing::TestWithParam<NeuralnetworksHidlTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
 }
 
+static NamedDevice makeNamedDevice(const std::string& name) {
+    return {name, IDevice::getService(name)};
+}
+
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+    // Retrieves the name of all service instances that implement IDevice,
+    // including any Lazy HAL instances.
+    const std::vector<std::string> names = hardware::getAllHalInstanceNames(IDevice::descriptor);
+
+    // Get a handle to each device and pair it with its name.
+    std::vector<NamedDevice> namedDevices;
+    namedDevices.reserve(names.size());
+    std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
+    return namedDevices;
+}
+
+const std::vector<NamedDevice>& getNamedDevices() {
+    const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
+    return devices;
+}
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info) {
+    return gtestCompliantName(getName(info.param));
+}
+
+INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
+
 // Forward declaration from ValidateModel.cpp
 void validateModel(const sp<IDevice>& device, const Model& model);
 // Forward declaration from ValidateRequest.cpp
@@ -130,14 +137,3 @@
 INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
 
 }  // namespace android::hardware::neuralnetworks::V1_0::vts::functional
-
-using android::hardware::neuralnetworks::V1_0::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
-    testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
-    testing::InitGoogleTest(&argc, argv);
-    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    return status;
-}
diff --git a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
index 48dc237..17f4613 100644
--- a/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.0/vts/functional/VtsHalNeuralnetworks.h
@@ -17,40 +17,34 @@
 #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H
 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_0_VTS_HAL_NEURALNETWORKS_H
 
+#include "1.0/Utils.h"
+
 #include <android/hardware/neuralnetworks/1.0/IDevice.h>
 #include <android/hardware/neuralnetworks/1.0/types.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <android-base/macros.h>
 #include <gtest/gtest.h>
 
+#include <vector>
+
 namespace android::hardware::neuralnetworks::V1_0::vts::functional {
 
-// A class for test environment setup
-class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
-    NeuralnetworksHidlEnvironment() = default;
+using NamedDevice = Named<sp<IDevice>>;
+using NeuralnetworksHidlTestParam = NamedDevice;
 
-  public:
-    static NeuralnetworksHidlEnvironment* getInstance();
-    void registerTestServices() override;
-};
-
-// The main test class for NEURALNETWORKS HIDL HAL.
-class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
-
-  public:
-    NeuralnetworksHidlTest() = default;
-    void SetUp() override;
-
+class NeuralnetworksHidlTest : public testing::TestWithParam<NeuralnetworksHidlTestParam> {
   protected:
-    const sp<IDevice> kDevice = testing::VtsHalHidlTargetTestBase::getService<IDevice>(
-            NeuralnetworksHidlEnvironment::getInstance());
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(GetParam());
 };
 
+const std::vector<NamedDevice>& getNamedDevices();
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info);
+
+#define INSTANTIATE_DEVICE_TEST(TestSuite)                                                 \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \
+                             printNeuralnetworksHidlTest)
+
 // Create an IPreparedModel object. If the model cannot be prepared,
 // "preparedModel" will be nullptr instead.
 void createPreparedModel(const sp<IDevice>& device, const Model& model,
diff --git a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
index 1ce751c..6d4534c 100644
--- a/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
+++ b/neuralnetworks/1.0/vts/functional/include/1.0/Utils.h
@@ -21,13 +21,15 @@
 #include <android/hardware/neuralnetworks/1.0/types.h>
 #include <algorithm>
 #include <iosfwd>
+#include <string>
+#include <utility>
 #include <vector>
 #include "TestHarness.h"
 
 namespace android::hardware::neuralnetworks {
 
 // Create HIDL Request from the TestModel struct.
-V1_0::Request createRequest(const ::test_helper::TestModel& testModel);
+V1_0::Request createRequest(const test_helper::TestModel& testModel);
 
 // After execution, copy out output results from the output memory pool.
 std::vector<::test_helper::TestBuffer> getOutputBuffers(const V1_0::Request& request);
@@ -51,6 +53,21 @@
     return index;
 }
 
+template <typename Type>
+using Named = std::pair<std::string, Type>;
+
+template <typename Type>
+const std::string& getName(const Named<Type>& namedData) {
+    return namedData.first;
+}
+
+template <typename Type>
+const Type& getData(const Named<Type>& namedData) {
+    return namedData.second;
+}
+
+std::string gtestCompliantName(std::string name);
+
 }  // namespace android::hardware::neuralnetworks
 
 namespace android::hardware::neuralnetworks::V1_0 {
diff --git a/neuralnetworks/1.1/vts/functional/Android.bp b/neuralnetworks/1.1/vts/functional/Android.bp
index c197e6d..4e85355 100644
--- a/neuralnetworks/1.1/vts/functional/Android.bp
+++ b/neuralnetworks/1.1/vts/functional/Android.bp
@@ -14,10 +14,11 @@
 // limitations under the License.
 //
 
-cc_defaults {
-    name: "VtsHalNeuralNetworksV1_1TargetTestDefaults",
+cc_test {
+    name: "VtsHalNeuralnetworksV1_1TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
+        "BasicTests.cpp",
         "TestAssertions.cpp",
         "ValidateModel.cpp",
         "ValidateRequest.cpp",
@@ -39,35 +40,12 @@
         "libneuralnetworks_utils",
         "VtsHalNeuralNetworksV1_0_utils",
     ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
+    ],
     header_libs: [
         "libneuralnetworks_headers",
     ],
     test_suites: ["general-tests"],
 }
-
-cc_test {
-    name: "VtsHalNeuralnetworksV1_1TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-    ],
-    whole_static_libs: [
-        "neuralnetworks_generated_V1_0_example",
-        "neuralnetworks_generated_V1_1_example",
-    ],
-}
-
-cc_test {
-    name: "PresubmitHalNeuralnetworksV1_1TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_1TargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-    ],
-    whole_static_libs: [
-        "neuralnetworks_generated_V1_0_example",
-        "neuralnetworks_generated_V1_1_example",
-    ],
-    cflags: [
-        "-DPRESUBMIT_NOT_VTS",
-    ],
-}
diff --git a/neuralnetworks/1.1/vts/functional/BasicTests.cpp b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
index 2791e80..44836f0 100644
--- a/neuralnetworks/1.1/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.1/vts/functional/BasicTests.cpp
@@ -24,17 +24,17 @@
 using V1_0::ErrorStatus;
 
 // create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+TEST_P(NeuralnetworksHidlTest, CreateDevice) {}
 
 // status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
+TEST_P(NeuralnetworksHidlTest, StatusTest) {
     Return<DeviceStatus> status = kDevice->getStatus();
     ASSERT_TRUE(status.isOk());
     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
 }
 
 // initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) {
     Return<void> ret =
             kDevice->getCapabilities_1_1([](ErrorStatus status, const Capabilities& capabilities) {
                 EXPECT_EQ(ErrorStatus::NONE, status);
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
index fddfc2b..7a929d6 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.cpp
@@ -156,6 +156,20 @@
     checkResults(testModel, outputs);
 }
 
+void GeneratedTestBase::SetUp() {
+    testing::TestWithParam<GeneratedTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
+}
+
+std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
+    const auto& [namedDevice, namedModel] = info.param;
+    return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
+}
+
 // Tag for the generated tests
 class GeneratedTest : public GeneratedTestBase {};
 
diff --git a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
index 273d1ec..cf449ea 100644
--- a/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.1/vts/functional/GeneratedTestHarness.h
@@ -18,29 +18,38 @@
 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_GENERATED_TEST_HARNESS_H
 
 #include <android/hardware/neuralnetworks/1.1/IDevice.h>
+#include "1.0/Utils.h"
 #include "TestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
 namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
-class GeneratedTestBase
-    : public NeuralnetworksHidlTest,
-      public testing::WithParamInterface<test_helper::TestModelManager::TestParam> {
+using NamedModel = Named<const test_helper::TestModel*>;
+using GeneratedTestParam = std::tuple<NamedDevice, NamedModel>;
+
+class GeneratedTestBase : public testing::TestWithParam<GeneratedTestParam> {
   protected:
-    const test_helper::TestModel& kTestModel = *GetParam().second;
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
+    const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
 };
 
-#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                        \
-    INSTANTIATE_TEST_SUITE_P(                                                                \
-            TestGenerated, TestSuite,                                                        \
-            testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \
-            [](const auto& info) { return info.param.first; })
+using FilterFn = std::function<bool(const test_helper::TestModel&)>;
+std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
+
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
+    INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite,                                    \
+                             testing::Combine(testing::ValuesIn(getNamedDevices()),       \
+                                              testing::ValuesIn(getNamedModels(filter))), \
+                             printGeneratedTest)
 
 // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
 // TODO: Clean up the hierarchy for ValidationTest.
 class ValidationTest : public GeneratedTestBase {};
 
-Model createModel(const ::test_helper::TestModel& testModel);
+Model createModel(const test_helper::TestModel& testModel);
 
 }  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
 
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
index d53d43e..d56d40b 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.cpp
@@ -17,13 +17,15 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include "VtsHalNeuralnetworks.h"
+#include <android-base/logging.h>
+#include <hidl/ServiceManagement.h>
+#include <string>
+#include <utility>
 #include "1.0/Callbacks.h"
 #include "1.0/Utils.h"
 #include "GeneratedTestHarness.h"
 #include "TestHarness.h"
 
-#include <android-base/logging.h>
-
 namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
 using V1_0::ErrorStatus;
@@ -79,34 +81,39 @@
     ASSERT_NE(nullptr, preparedModel->get());
 }
 
-// A class for test environment setup
-NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
-    // This has to return a "new" object because it is freed inside
-    // testing::AddGlobalTestEnvironment when the gtest is being torn down
-    static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
-    return instance;
-}
-
-void NeuralnetworksHidlEnvironment::registerTestServices() {
-    registerTestService<IDevice>();
-}
-
-// The main test class for NEURALNETWORK HIDL HAL.
 void NeuralnetworksHidlTest::SetUp() {
-    testing::VtsHalHidlTargetTestBase::SetUp();
-
-#ifdef PRESUBMIT_NOT_VTS
-    const std::string name =
-            NeuralnetworksHidlEnvironment::getInstance()->getServiceName<IDevice>();
-    const std::string sampleDriver = "sample-";
-    if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) {
-        GTEST_SKIP();
-    }
-#endif  // PRESUBMIT_NOT_VTS
-
-    ASSERT_NE(nullptr, kDevice.get());
+    testing::TestWithParam<NeuralnetworksHidlTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
 }
 
+static NamedDevice makeNamedDevice(const std::string& name) {
+    return {name, IDevice::getService(name)};
+}
+
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+    // Retrieves the name of all service instances that implement IDevice,
+    // including any Lazy HAL instances.
+    const std::vector<std::string> names = hardware::getAllHalInstanceNames(IDevice::descriptor);
+
+    // Get a handle to each device and pair it with its name.
+    std::vector<NamedDevice> namedDevices;
+    namedDevices.reserve(names.size());
+    std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
+    return namedDevices;
+}
+
+const std::vector<NamedDevice>& getNamedDevices() {
+    const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
+    return devices;
+}
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info) {
+    return gtestCompliantName(getName(info.param));
+}
+
+INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
+
 // Forward declaration from ValidateModel.cpp
 void validateModel(const sp<IDevice>& device, const Model& model);
 // Forward declaration from ValidateRequest.cpp
@@ -133,14 +140,3 @@
 INSTANTIATE_GENERATED_TEST(ValidationTest, [](const test_helper::TestModel&) { return true; });
 
 }  // namespace android::hardware::neuralnetworks::V1_1::vts::functional
-
-using android::hardware::neuralnetworks::V1_1::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
-    testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
-    testing::InitGoogleTest(&argc, argv);
-    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    return status;
-}
diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
index 9d6194a..e879d84 100644
--- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h
@@ -17,41 +17,33 @@
 #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H
 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_1_VTS_HAL_NEURALNETWORKS_H
 
-#include <android/hardware/neuralnetworks/1.0/types.h>
+#include <android/hardware/neuralnetworks/1.0/IPreparedModel.h>
 #include <android/hardware/neuralnetworks/1.1/IDevice.h>
 #include <android/hardware/neuralnetworks/1.1/types.h>
-
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-
-#include <android-base/macros.h>
 #include <gtest/gtest.h>
+#include <vector>
+#include "1.0/Utils.h"
 
 namespace android::hardware::neuralnetworks::V1_1::vts::functional {
 
-// A class for test environment setup
-class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
-    NeuralnetworksHidlEnvironment() = default;
+using NamedDevice = Named<sp<IDevice>>;
+using NeuralnetworksHidlTestParam = NamedDevice;
 
-  public:
-    static NeuralnetworksHidlEnvironment* getInstance();
-    void registerTestServices() override;
-};
-
-// The main test class for NEURALNETWORKS HIDL HAL.
-class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
-
-  public:
-    NeuralnetworksHidlTest() = default;
-    void SetUp() override;
-
+class NeuralnetworksHidlTest : public testing::TestWithParam<NeuralnetworksHidlTestParam> {
   protected:
-    const sp<IDevice> kDevice = testing::VtsHalHidlTargetTestBase::getService<IDevice>(
-            NeuralnetworksHidlEnvironment::getInstance());
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(GetParam());
 };
 
+const std::vector<NamedDevice>& getNamedDevices();
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info);
+
+#define INSTANTIATE_DEVICE_TEST(TestSuite)                                                 \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \
+                             printNeuralnetworksHidlTest)
+
 // Create an IPreparedModel object. If the model cannot be prepared,
 // "preparedModel" will be nullptr instead.
 void createPreparedModel(const sp<IDevice>& device, const Model& model,
diff --git a/neuralnetworks/1.2/IPreparedModel.hal b/neuralnetworks/1.2/IPreparedModel.hal
index f3508fe..1445f18 100644
--- a/neuralnetworks/1.2/IPreparedModel.hal
+++ b/neuralnetworks/1.2/IPreparedModel.hal
@@ -157,22 +157,44 @@
      * unless the device itself is in a bad state.
      *
      * @param callback A callback object used to retrieve memory resources
-     *                 corresponding to a unique identifiers ("slots").
-     * @param requestChannel Used by the client to send a serialized Request to
-     *                       the Burst for execution. The client must not change
-     *                       the content of any data object referenced by the
-     *                       Request (described by the {@link @1.0::DataLocation}
-     *                       of an {@link OperandInformation}) until a result
-     *                       has been received from resultChannel. Execution
-     *                       must not change the content of any of the data
-     *                       objects corresponding to Request inputs. requestChannel
+     *                 corresponding to unique identifiers ("slots").
+     * @param requestChannel FMQ used by the client to send a serialized Request
+     *                       to the Burst for execution. The client must not
+     *                       change the content of any data object referenced by
+     *                       the Request (described by the
+     *                       {@link @1.0::DataLocation} of an
+     *                       {@link OperandInformation}) until a result has been
+     *                       received from resultChannel. Execution must not
+     *                       change the content of any of the data objects
+     *                       corresponding to Request inputs. requestChannel
      *                       must not be used to pass a second Request object
-     *                       until a result has been received from resultChannel.
-     * @param resultChannel Used by the service to return the results of an
-     *                      execution to the client: the status of the execution
-     *                      and OutputShape of all output tensors. resultChannel
-     *                      must be used to return the results if a Request was
-     *                      sent through the requestChannel.
+     *                       until a result has been received from
+     *                       resultChannel. The client must send the request
+     *                       messages to the consumer atomically by using
+     *                       MessageQueue::writeBlocking if the queue is
+     *                       blocking, or by using MessageQueue::write if the
+     *                       queue is non-blocking. When the service receives a
+     *                       packet, it must dequeue the entire packet from the
+     *                       requestChannel. The client must not send a request
+     *                       packet that exceeds the length of the FMQ.
+     * @param resultChannel FMQ used by the service to return the results of an
+     *                      execution to the client: the status of the
+     *                      execution, OutputShape of all output tensors, and
+     *                      timing information. resultChannel must be used to
+     *                      return the results if a Request was sent through the
+     *                      requestChannel. The service must send the result
+     *                      messages to the consumer atomically by using
+     *                      MessageQueue::writeBlocking if the queue is
+     *                      blocking, or by using MessageQueue::write if the
+     *                      queue is non-blocking. When the client receives a
+     *                      packet, it must dequeue the entire packet from the
+     *                      resultChannel. If the packet's length exceeds the
+     *                      size of the FMQ, the service must not send this
+     *                      result packet; instead, the service must send a
+     *                      packet consisting of the error code
+     *                      ErrorStatus::GENERAL_FAILURE, no information for the
+     *                      outputShapes, and an indication that timing
+     *                      information is unavailable.
      * @return status Error status of configuring the execution burst, must be:
      *                - NONE if the burst is successfully configured
      *                - DEVICE_UNAVAILABLE if driver is offline or busy
diff --git a/neuralnetworks/1.2/vts/functional/Android.bp b/neuralnetworks/1.2/vts/functional/Android.bp
index 40ca809..3ba8879 100644
--- a/neuralnetworks/1.2/vts/functional/Android.bp
+++ b/neuralnetworks/1.2/vts/functional/Android.bp
@@ -14,16 +14,19 @@
 // limitations under the License.
 //
 
-cc_defaults {
-    name: "VtsHalNeuralNetworksV1_2TargetTestDefaults",
+cc_test {
+    name: "VtsHalNeuralnetworksV1_2TargetTest",
     defaults: ["VtsHalTargetTestDefaults"],
     srcs: [
+        "BasicTests.cpp",
+        "Callbacks.cpp",
+        "CompilationCachingTests.cpp",
+        "GeneratedTestHarness.cpp",
         "TestAssertions.cpp",
         "ValidateModel.cpp",
         "ValidateRequest.cpp",
+        "ValidateBurst.cpp",
         "VtsHalNeuralnetworks.cpp",
-        "Callbacks.cpp",
-        "GeneratedTestHarness.cpp",
     ],
     local_include_dirs: ["include"],
     shared_libs: [
@@ -42,41 +45,13 @@
         "libneuralnetworks_utils",
         "VtsHalNeuralNetworksV1_0_utils",
     ],
+    whole_static_libs: [
+        "neuralnetworks_generated_V1_0_example",
+        "neuralnetworks_generated_V1_1_example",
+        "neuralnetworks_generated_V1_2_example",
+    ],
     header_libs: [
         "libneuralnetworks_headers",
     ],
     test_suites: ["general-tests"],
 }
-
-cc_test {
-    name: "VtsHalNeuralnetworksV1_2TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-        "CompilationCachingTests.cpp",
-        "ValidateBurst.cpp",
-    ],
-    whole_static_libs: [
-        "neuralnetworks_generated_V1_0_example",
-        "neuralnetworks_generated_V1_1_example",
-        "neuralnetworks_generated_V1_2_example",
-    ],
-}
-
-cc_test {
-    name: "PresubmitHalNeuralnetworksV1_2TargetTest",
-    defaults: ["VtsHalNeuralNetworksV1_2TargetTestDefaults"],
-    srcs: [
-        "BasicTests.cpp",
-        "CompilationCachingTests.cpp",
-        "ValidateBurst.cpp",
-    ],
-    whole_static_libs: [
-        "neuralnetworks_generated_V1_0_example",
-        "neuralnetworks_generated_V1_1_example",
-        "neuralnetworks_generated_V1_2_example",
-    ],
-    cflags: [
-        "-DPRESUBMIT_NOT_VTS",
-    ],
-}
diff --git a/neuralnetworks/1.2/vts/functional/BasicTests.cpp b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
index 8f95b96..8e82c53 100644
--- a/neuralnetworks/1.2/vts/functional/BasicTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/BasicTests.cpp
@@ -25,17 +25,17 @@
 using V1_0::PerformanceInfo;
 
 // create device test
-TEST_F(NeuralnetworksHidlTest, CreateDevice) {}
+TEST_P(NeuralnetworksHidlTest, CreateDevice) {}
 
 // status test
-TEST_F(NeuralnetworksHidlTest, StatusTest) {
+TEST_P(NeuralnetworksHidlTest, StatusTest) {
     Return<DeviceStatus> status = kDevice->getStatus();
     ASSERT_TRUE(status.isOk());
     EXPECT_EQ(DeviceStatus::AVAILABLE, static_cast<DeviceStatus>(status));
 }
 
 // initialization
-TEST_F(NeuralnetworksHidlTest, GetCapabilitiesTest) {
+TEST_P(NeuralnetworksHidlTest, GetCapabilitiesTest) {
     using OperandPerformance = Capabilities::OperandPerformance;
     Return<void> ret = kDevice->getCapabilities_1_2([](ErrorStatus status,
                                                        const Capabilities& capabilities) {
@@ -60,7 +60,7 @@
 }
 
 // device version test
-TEST_F(NeuralnetworksHidlTest, GetDeviceVersionStringTest) {
+TEST_P(NeuralnetworksHidlTest, GetDeviceVersionStringTest) {
     Return<void> ret =
             kDevice->getVersionString([](ErrorStatus status, const hidl_string& version) {
                 EXPECT_EQ(ErrorStatus::NONE, status);
@@ -70,7 +70,7 @@
 }
 
 // device type test
-TEST_F(NeuralnetworksHidlTest, GetDeviceTypeTest) {
+TEST_P(NeuralnetworksHidlTest, GetDeviceTypeTest) {
     Return<void> ret = kDevice->getType([](ErrorStatus status, DeviceType type) {
         EXPECT_EQ(ErrorStatus::NONE, status);
         EXPECT_TRUE(type == DeviceType::OTHER || type == DeviceType::CPU ||
@@ -80,7 +80,7 @@
 }
 
 // device supported extensions test
-TEST_F(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) {
+TEST_P(NeuralnetworksHidlTest, GetDeviceSupportedExtensionsTest) {
     Return<void> ret = kDevice->getSupportedExtensions(
             [](ErrorStatus status, const hidl_vec<Extension>& extensions) {
                 EXPECT_EQ(ErrorStatus::NONE, status);
@@ -101,7 +101,7 @@
 }
 
 // getNumberOfCacheFilesNeeded test
-TEST_F(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) {
+TEST_P(NeuralnetworksHidlTest, getNumberOfCacheFilesNeeded) {
     Return<void> ret = kDevice->getNumberOfCacheFilesNeeded(
             [](ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) {
                 EXPECT_EQ(ErrorStatus::NONE, status);
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index bb46e06..2130a76 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -17,6 +17,7 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include <android-base/logging.h>
+#include <fcntl.h>
 #include <ftw.h>
 #include <gtest/gtest.h>
 #include <hidlmemory/mapping.h>
@@ -37,11 +38,11 @@
 // Forward declaration of the mobilenet generated test models in
 // frameworks/ml/nn/runtime/test/generated/.
 namespace generated_tests::mobilenet_224_gender_basic_fixed {
-const ::test_helper::TestModel& get_test_model();
+const test_helper::TestModel& get_test_model();
 }  // namespace generated_tests::mobilenet_224_gender_basic_fixed
 
 namespace generated_tests::mobilenet_quantized {
-const ::test_helper::TestModel& get_test_model();
+const test_helper::TestModel& get_test_model();
 }  // namespace generated_tests::mobilenet_quantized
 
 namespace android::hardware::neuralnetworks::V1_2::vts::functional {
@@ -53,13 +54,13 @@
 
 namespace float32_model {
 
-constexpr auto get_test_model = ::generated_tests::mobilenet_224_gender_basic_fixed::get_test_model;
+constexpr auto get_test_model = generated_tests::mobilenet_224_gender_basic_fixed::get_test_model;
 
 }  // namespace float32_model
 
 namespace quant8_model {
 
-constexpr auto get_test_model = ::generated_tests::mobilenet_quantized::get_test_model;
+constexpr auto get_test_model = generated_tests::mobilenet_quantized::get_test_model;
 
 }  // namespace quant8_model
 
@@ -217,12 +218,13 @@
 }  // namespace
 
 // Tag for the compilation caching tests.
-class CompilationCachingTestBase : public NeuralnetworksHidlTest {
+class CompilationCachingTestBase : public testing::Test {
   protected:
-    CompilationCachingTestBase(OperandType type) : kOperandType(type) {}
+    CompilationCachingTestBase(sp<IDevice> device, OperandType type)
+        : kDevice(std::move(device)), kOperandType(type) {}
 
     void SetUp() override {
-        NeuralnetworksHidlTest::SetUp();
+        testing::Test::SetUp();
         ASSERT_NE(kDevice.get(), nullptr);
 
         // Create cache directory. The cache directory and a temporary cache file is always created
@@ -274,7 +276,7 @@
             };
             nftw(mCacheDir.c_str(), callback, 128, FTW_DEPTH | FTW_MOUNT | FTW_PHYS);
         }
-        NeuralnetworksHidlTest::TearDown();
+        testing::Test::TearDown();
     }
 
     // Model and examples creators. According to kOperandType, the following methods will return
@@ -398,16 +400,21 @@
     uint32_t mNumDataCache;
     uint32_t mIsCachingSupported;
 
+    const sp<IDevice> kDevice;
     // The primary data type of the testModel.
     const OperandType kOperandType;
 };
 
+using CompilationCachingTestParam = std::tuple<NamedDevice, OperandType>;
+
 // A parameterized fixture of CompilationCachingTestBase. Every test will run twice, with the first
 // pass running with float32 models and the second pass running with quant8 models.
 class CompilationCachingTest : public CompilationCachingTestBase,
-                               public testing::WithParamInterface<OperandType> {
+                               public testing::WithParamInterface<CompilationCachingTestParam> {
   protected:
-    CompilationCachingTest() : CompilationCachingTestBase(GetParam()) {}
+    CompilationCachingTest()
+        : CompilationCachingTestBase(getData(std::get<NamedDevice>(GetParam())),
+                                     std::get<OperandType>(GetParam())) {}
 };
 
 TEST_P(CompilationCachingTest, CacheSavingAndRetrieval) {
@@ -1192,16 +1199,30 @@
     }
 }
 
+static const auto kNamedDeviceChoices = testing::ValuesIn(getNamedDevices());
 static const auto kOperandTypeChoices =
         testing::Values(OperandType::TENSOR_FLOAT32, OperandType::TENSOR_QUANT8_ASYMM);
 
-INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest, kOperandTypeChoices);
+std::string printCompilationCachingTest(
+        const testing::TestParamInfo<CompilationCachingTestParam>& info) {
+    const auto& [namedDevice, operandType] = info.param;
+    const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8");
+    return gtestCompliantName(getName(namedDevice) + "_" + type);
+}
+
+INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingTest,
+                        testing::Combine(kNamedDeviceChoices, kOperandTypeChoices),
+                        printCompilationCachingTest);
+
+using CompilationCachingSecurityTestParam = std::tuple<NamedDevice, OperandType, uint32_t>;
 
 class CompilationCachingSecurityTest
     : public CompilationCachingTestBase,
-      public testing::WithParamInterface<std::tuple<OperandType, uint32_t>> {
+      public testing::WithParamInterface<CompilationCachingSecurityTestParam> {
   protected:
-    CompilationCachingSecurityTest() : CompilationCachingTestBase(std::get<0>(GetParam())) {}
+    CompilationCachingSecurityTest()
+        : CompilationCachingTestBase(getData(std::get<NamedDevice>(GetParam())),
+                                     std::get<OperandType>(GetParam())) {}
 
     void SetUp() {
         CompilationCachingTestBase::SetUp();
@@ -1291,7 +1312,7 @@
         }
     }
 
-    const uint32_t kSeed = std::get<1>(GetParam());
+    const uint32_t kSeed = std::get<uint32_t>(GetParam());
     std::mt19937 generator;
 };
 
@@ -1338,7 +1359,16 @@
     });
 }
 
+std::string printCompilationCachingSecurityTest(
+        const testing::TestParamInfo<CompilationCachingSecurityTestParam>& info) {
+    const auto& [namedDevice, operandType, seed] = info.param;
+    const std::string type = (operandType == OperandType::TENSOR_FLOAT32 ? "float32" : "quant8");
+    return gtestCompliantName(getName(namedDevice) + "_" + type + "_" + std::to_string(seed));
+}
+
 INSTANTIATE_TEST_CASE_P(TestCompilationCaching, CompilationCachingSecurityTest,
-                        testing::Combine(kOperandTypeChoices, testing::Range(0U, 10U)));
+                        testing::Combine(kNamedDeviceChoices, kOperandTypeChoices,
+                                         testing::Range(0U, 10U)),
+                        printCompilationCachingSecurityTest);
 
 }  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
index a2d3792..2beec98 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.cpp
@@ -190,7 +190,7 @@
 }
 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, /*blocking=*/true);
 }
 enum class Executor { ASYNC, SYNC, BURST };
 
@@ -371,6 +371,20 @@
     EvaluatePreparedModel(preparedModel, testModel, testDynamicOutputShape);
 }
 
+void GeneratedTestBase::SetUp() {
+    testing::TestWithParam<GeneratedTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
+}
+
+std::vector<NamedModel> getNamedModels(const FilterFn& filter) {
+    return TestModelManager::get().getTestModels(filter);
+}
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info) {
+    const auto& [namedDevice, namedModel] = info.param;
+    return gtestCompliantName(getName(namedDevice) + "_" + getName(namedModel));
+}
+
 // Tag for the generated tests
 class GeneratedTest : public GeneratedTestBase {};
 
diff --git a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
index 0b8b917..dfc980c 100644
--- a/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
+++ b/neuralnetworks/1.2/vts/functional/GeneratedTestHarness.h
@@ -22,34 +22,43 @@
 #include <android/hardware/neuralnetworks/1.2/types.h>
 #include <functional>
 #include <vector>
+#include "1.0/Utils.h"
 #include "TestHarness.h"
 #include "VtsHalNeuralnetworks.h"
 
 namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-class GeneratedTestBase
-    : public NeuralnetworksHidlTest,
-      public testing::WithParamInterface<test_helper::TestModelManager::TestParam> {
+using NamedModel = Named<const test_helper::TestModel*>;
+using GeneratedTestParam = std::tuple<NamedDevice, NamedModel>;
+
+class GeneratedTestBase : public testing::TestWithParam<GeneratedTestParam> {
   protected:
-    const test_helper::TestModel& kTestModel = *GetParam().second;
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(std::get<NamedDevice>(GetParam()));
+    const test_helper::TestModel& kTestModel = *getData(std::get<NamedModel>(GetParam()));
 };
 
-#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                        \
-    INSTANTIATE_TEST_SUITE_P(                                                                \
-            TestGenerated, TestSuite,                                                        \
-            testing::ValuesIn(::test_helper::TestModelManager::get().getTestModels(filter)), \
-            [](const auto& info) { return info.param.first; })
+using FilterFn = std::function<bool(const test_helper::TestModel&)>;
+std::vector<NamedModel> getNamedModels(const FilterFn& filter);
+
+std::string printGeneratedTest(const testing::TestParamInfo<GeneratedTestParam>& info);
+
+#define INSTANTIATE_GENERATED_TEST(TestSuite, filter)                                     \
+    INSTANTIATE_TEST_SUITE_P(TestGenerated, TestSuite,                                    \
+                             testing::Combine(testing::ValuesIn(getNamedDevices()),       \
+                                              testing::ValuesIn(getNamedModels(filter))), \
+                             printGeneratedTest)
 
 // Tag for the validation tests, instantiated in VtsHalNeuralnetworks.cpp.
 // TODO: Clean up the hierarchy for ValidationTest.
 class ValidationTest : public GeneratedTestBase {};
 
-Model createModel(const ::test_helper::TestModel& testModel);
+Model createModel(const test_helper::TestModel& testModel);
 
 void PrepareModel(const sp<IDevice>& device, const Model& model, sp<IPreparedModel>* preparedModel);
 
 void EvaluatePreparedModel(const sp<IPreparedModel>& preparedModel,
-                           const ::test_helper::TestModel& testModel, bool testDynamicOutputShape);
+                           const test_helper::TestModel& testModel, bool testDynamicOutputShape);
 
 }  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
 
diff --git a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
index c02d020..1d4493d 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateBurst.cpp
@@ -262,7 +262,7 @@
     }));
 
     // serialize the request
-    const auto serialized = ::android::nn::serialize(request, MeasureTiming::YES, slots);
+    const auto serialized = android::nn::serialize(request, MeasureTiming::YES, slots);
 
     // validations
     removeDatumTest(sender.get(), receiver.get(), serialized);
@@ -299,7 +299,7 @@
     // 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
     const std::vector<FmqResultDatum> serialized =
-            ::android::nn::serialize(statusRegular, outputShapesRegular, timingRegular);
+            android::nn::serialize(statusRegular, outputShapesRegular, timingRegular);
     if (statusRegular != ErrorStatus::NONE ||
         serialized.size() <= kExecutionBurstChannelSmallLength) {
         return;
diff --git a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
index 5c52de5..f25ee62 100644
--- a/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
+++ b/neuralnetworks/1.2/vts/functional/ValidateRequest.cpp
@@ -94,7 +94,7 @@
 
         // create burst
         std::shared_ptr<::android::nn::ExecutionBurstController> burst =
-                ::android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
+                android::nn::ExecutionBurstController::create(preparedModel, /*blocking=*/true);
         ASSERT_NE(nullptr, burst.get());
 
         // create memory keys
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
index aa4f1f2..4fbd0e2 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.cpp
@@ -17,13 +17,15 @@
 #define LOG_TAG "neuralnetworks_hidl_hal_test"
 
 #include "VtsHalNeuralnetworks.h"
+#include <android-base/logging.h>
+#include <hidl/ServiceManagement.h>
+#include <string>
+#include <utility>
 #include "1.0/Callbacks.h"
 #include "1.0/Utils.h"
 #include "GeneratedTestHarness.h"
 #include "TestHarness.h"
 
-#include <android-base/logging.h>
-
 namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
 using implementation::PreparedModelCallback;
@@ -82,34 +84,39 @@
     ASSERT_NE(nullptr, preparedModel->get());
 }
 
-// A class for test environment setup
-NeuralnetworksHidlEnvironment* NeuralnetworksHidlEnvironment::getInstance() {
-    // This has to return a "new" object because it is freed inside
-    // testing::AddGlobalTestEnvironment when the gtest is being torn down
-    static NeuralnetworksHidlEnvironment* instance = new NeuralnetworksHidlEnvironment();
-    return instance;
-}
-
-void NeuralnetworksHidlEnvironment::registerTestServices() {
-    registerTestService<IDevice>();
-}
-
-// The main test class for NEURALNETWORK HIDL HAL.
 void NeuralnetworksHidlTest::SetUp() {
-    testing::VtsHalHidlTargetTestBase::SetUp();
-
-#ifdef PRESUBMIT_NOT_VTS
-    const std::string name =
-            NeuralnetworksHidlEnvironment::getInstance()->getServiceName<IDevice>();
-    const std::string sampleDriver = "sample-";
-    if (kDevice == nullptr && name.substr(0, sampleDriver.size()) == sampleDriver) {
-        GTEST_SKIP();
-    }
-#endif  // PRESUBMIT_NOT_VTS
-
-    ASSERT_NE(nullptr, kDevice.get());
+    testing::TestWithParam<NeuralnetworksHidlTestParam>::SetUp();
+    ASSERT_NE(kDevice, nullptr);
 }
 
+static NamedDevice makeNamedDevice(const std::string& name) {
+    return {name, IDevice::getService(name)};
+}
+
+static std::vector<NamedDevice> getNamedDevicesImpl() {
+    // Retrieves the name of all service instances that implement IDevice,
+    // including any Lazy HAL instances.
+    const std::vector<std::string> names = hardware::getAllHalInstanceNames(IDevice::descriptor);
+
+    // Get a handle to each device and pair it with its name.
+    std::vector<NamedDevice> namedDevices;
+    namedDevices.reserve(names.size());
+    std::transform(names.begin(), names.end(), std::back_inserter(namedDevices), makeNamedDevice);
+    return namedDevices;
+}
+
+const std::vector<NamedDevice>& getNamedDevices() {
+    const static std::vector<NamedDevice> devices = getNamedDevicesImpl();
+    return devices;
+}
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info) {
+    return gtestCompliantName(getName(info.param));
+}
+
+INSTANTIATE_DEVICE_TEST(NeuralnetworksHidlTest);
+
 // Forward declaration from ValidateModel.cpp
 void validateModel(const sp<IDevice>& device, const Model& model);
 // Forward declaration from ValidateRequest.cpp
@@ -162,14 +169,3 @@
 }
 
 }  // namespace android::hardware::neuralnetworks::V1_2::vts::functional
-
-using android::hardware::neuralnetworks::V1_2::vts::functional::NeuralnetworksHidlEnvironment;
-
-int main(int argc, char** argv) {
-    testing::AddGlobalTestEnvironment(NeuralnetworksHidlEnvironment::getInstance());
-    testing::InitGoogleTest(&argc, argv);
-    NeuralnetworksHidlEnvironment::getInstance()->init(&argc, argv);
-
-    int status = RUN_ALL_TESTS();
-    return status;
-}
diff --git a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
index 9981696..d01336e 100644
--- a/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
+++ b/neuralnetworks/1.2/vts/functional/VtsHalNeuralnetworks.h
@@ -17,42 +17,33 @@
 #ifndef ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H
 #define ANDROID_HARDWARE_NEURALNETWORKS_V1_2_VTS_HAL_NEURALNETWORKS_H
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
-#include <android-base/macros.h>
-#include <android/hardware/neuralnetworks/1.0/types.h>
-#include <android/hardware/neuralnetworks/1.1/types.h>
 #include <android/hardware/neuralnetworks/1.2/IDevice.h>
+#include <android/hardware/neuralnetworks/1.2/IPreparedModel.h>
 #include <android/hardware/neuralnetworks/1.2/types.h>
 #include <gtest/gtest.h>
-
+#include "1.0/Utils.h"
 #include "1.2/Callbacks.h"
 
 namespace android::hardware::neuralnetworks::V1_2::vts::functional {
 
-// A class for test environment setup
-class NeuralnetworksHidlEnvironment : public testing::VtsHalHidlTargetTestEnvBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlEnvironment);
-    NeuralnetworksHidlEnvironment() = default;
+using NamedDevice = Named<sp<IDevice>>;
+using NeuralnetworksHidlTestParam = NamedDevice;
 
-  public:
-    static NeuralnetworksHidlEnvironment* getInstance();
-    void registerTestServices() override;
-};
-
-// The main test class for NEURALNETWORKS HIDL HAL.
-class NeuralnetworksHidlTest : public testing::VtsHalHidlTargetTestBase {
-    DISALLOW_COPY_AND_ASSIGN(NeuralnetworksHidlTest);
-
-  public:
-    NeuralnetworksHidlTest() = default;
-    void SetUp() override;
-
+class NeuralnetworksHidlTest : public testing::TestWithParam<NeuralnetworksHidlTestParam> {
   protected:
-    const sp<IDevice> kDevice = testing::VtsHalHidlTargetTestBase::getService<IDevice>(
-            NeuralnetworksHidlEnvironment::getInstance());
+    void SetUp() override;
+    const sp<IDevice> kDevice = getData(GetParam());
 };
 
+const std::vector<NamedDevice>& getNamedDevices();
+
+std::string printNeuralnetworksHidlTest(
+        const testing::TestParamInfo<NeuralnetworksHidlTestParam>& info);
+
+#define INSTANTIATE_DEVICE_TEST(TestSuite)                                                 \
+    INSTANTIATE_TEST_SUITE_P(PerInstance, TestSuite, testing::ValuesIn(getNamedDevices()), \
+                             printNeuralnetworksHidlTest)
+
 // Create an IPreparedModel object. If the model cannot be prepared,
 // "preparedModel" will be nullptr instead.
 void createPreparedModel(const sp<IDevice>& device, const Model& model,
diff --git a/neuralnetworks/TEST_MAPPING b/neuralnetworks/TEST_MAPPING
index 50b6c19..421922a 100644
--- a/neuralnetworks/TEST_MAPPING
+++ b/neuralnetworks/TEST_MAPPING
@@ -1,26 +1,35 @@
 {
   "presubmit": [
     {
-      "name": "PresubmitHalNeuralnetworksV1_0TargetTest",
+      "name": "VtsHalNeuralnetworksV1_0TargetTest",
       "options": [
         {
-          "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.0::IDevice/sample-all"
+          // Just use sample-all driver for presubmit tests for faster results.
+          // The other sample drivers (fast-float, quant, etc.) are subsets of
+          // sample-all.
+          "native-test-flag": "--gtest_filter=*sample_all*"
         }
       ]
     },
     {
-      "name": "PresubmitHalNeuralnetworksV1_1TargetTest",
+      "name": "VtsHalNeuralnetworksV1_1TargetTest",
       "options": [
         {
-          "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.1::IDevice/sample-all"
+          // Just use sample-all driver for presubmit tests for faster results.
+          // The other sample drivers (fast-float, quant, etc.) are subsets of
+          // sample-all.
+          "native-test-flag": "--gtest_filter=*sample_all*"
         }
       ]
     },
     {
-      "name": "PresubmitHalNeuralnetworksV1_2TargetTest",
+      "name": "VtsHalNeuralnetworksV1_2TargetTest",
       "options": [
         {
-          "native-test-flag": "--hal_service_instance=android.hardware.neuralnetworks@1.2::IDevice/sample-all"
+          // Just use sample-all driver for presubmit tests for faster results.
+          // The other sample drivers (fast-float, quant, etc.) are subsets of
+          // sample-all.
+          "native-test-flag": "--gtest_filter=*sample_all*"
         }
       ]
     }
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 26f2c90..b2d19a2 100644
--- a/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.4/vts/functional/radio_hidl_hal_api.cpp
@@ -381,7 +381,7 @@
             .interval = 60,
             .specifiers = {specifier},
             .maxSearchTime = 600,
-            .incrementalResults = false,
+            .incrementalResults = true,
             .incrementalResultsPeriodicity = 0};
 
     Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
@@ -416,7 +416,7 @@
             .interval = 60,
             .specifiers = {specifier},
             .maxSearchTime = 600,
-            .incrementalResults = false,
+            .incrementalResults = true,
             .incrementalResultsPeriodicity = 11};
 
     Return<void> res = radio_v1_4->startNetworkScan_1_4(serial, request);
diff --git a/tests/baz/1.0/IBaz.hal b/tests/baz/1.0/IBaz.hal
index 91ed1f2..7855446 100644
--- a/tests/baz/1.0/IBaz.hal
+++ b/tests/baz/1.0/IBaz.hal
@@ -29,6 +29,11 @@
         VALL = V0 | V1 | V2 | V3,
     };
 
+    struct BitFieldTester {
+      bitfield<BitField> scalar;
+      vec<bitfield<BitField>> vector;
+     };
+
     enum SomeOtherEnum : uint8_t {
         bar = 66
     };
@@ -108,6 +113,7 @@
 
     haveSomeStrings(string[3] array) generates (string[2] result);
     haveAStringVec(vec<string> vector) generates (vec<string> result);
+    repeatBitfieldVec(vec<bitfield<BitField>> vector) generates (vec<bitfield<BitField>> result);
 
     returnABunchOfStrings() generates (string a, string b, string c);
 
diff --git a/tests/baz/1.0/default/Baz.cpp b/tests/baz/1.0/default/Baz.cpp
index e118122..2ce096c 100644
--- a/tests/baz/1.0/default/Baz.cpp
+++ b/tests/baz/1.0/default/Baz.cpp
@@ -364,6 +364,12 @@
     return Void();
 }
 
+Return<void> Baz::repeatBitfieldVec(const hidl_vec<uint8_t>& vector,
+                                    repeatBitfieldVec_cb _hidl_cb) {
+    _hidl_cb(vector);
+    return Void();
+}
+
 Return<void> Baz::returnABunchOfStrings(returnABunchOfStrings_cb _hidl_cb) {
     hidl_string eins; eins = "Eins";
     hidl_string zwei; zwei = "Zwei";
diff --git a/tests/baz/1.0/default/Baz.h b/tests/baz/1.0/default/Baz.h
index c264f47..1e24d52 100644
--- a/tests/baz/1.0/default/Baz.h
+++ b/tests/baz/1.0/default/Baz.h
@@ -86,6 +86,8 @@
                                  haveSomeStrings_cb _hidl_cb) override;
     Return<void> haveAStringVec(const hidl_vec<hidl_string>& vector,
                                 haveAStringVec_cb _hidl_cb) override;
+    Return<void> repeatBitfieldVec(const hidl_vec<uint8_t>& vector,
+                                   repeatBitfieldVec_cb _hidl_cb) override;
     Return<void> returnABunchOfStrings(returnABunchOfStrings_cb _hidl_cb) override;
     Return<uint8_t> returnABitField() override;
     Return<uint32_t> size(uint32_t size) override;
diff --git a/tv/tuner/1.0/Android.bp b/tv/tuner/1.0/Android.bp
index 986518b..09265f7 100644
--- a/tv/tuner/1.0/Android.bp
+++ b/tv/tuner/1.0/Android.bp
@@ -13,6 +13,7 @@
         "IDescrambler.hal",
         "IFrontend.hal",
         "IFrontendCallback.hal",
+        "ILnb.hal",
         "ITuner.hal",
     ],
     interfaces: [
diff --git a/tv/tuner/1.0/IDemux.hal b/tv/tuner/1.0/IDemux.hal
index 2d7b275..e03095b 100644
--- a/tv/tuner/1.0/IDemux.hal
+++ b/tv/tuner/1.0/IDemux.hal
@@ -180,5 +180,220 @@
      *         UNKNOWN_ERROR if failed for other reasons.
      */
     close() generates (Result result);
-};
 
+    /**
+     * Add output to the demux
+     *
+     * It is used by the client to record output data from selected filters.
+     *
+     * @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
+     * 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.
+     */
+    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.
+     */
+    attachOutputTsFilter(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.
+     */
+    detachOutputTsFilter(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);
+};
diff --git a/tv/tuner/1.0/IDemuxCallback.hal b/tv/tuner/1.0/IDemuxCallback.hal
index 7efd2c3..55e8420 100644
--- a/tv/tuner/1.0/IDemuxCallback.hal
+++ b/tv/tuner/1.0/IDemuxCallback.hal
@@ -15,5 +15,19 @@
      * @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/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
index 05cee91..f9f78ef 100644
--- a/tv/tuner/1.0/IFrontend.hal
+++ b/tv/tuner/1.0/IFrontend.hal
@@ -16,6 +16,7 @@
 package android.hardware.tv.tuner@1.0;
 
 import IFrontendCallback;
+import ILnb;
 
 /**
  * A Tuner Frontend is used to tune to a frequency and lock signal. It provide
@@ -79,4 +80,98 @@
      *         UNKNOWN_ERROR if failed for other reasons.
      */
     close() generates (Result result);
+
+    /**
+     * Scan the frontend to use the settings given.
+     *
+     * This uses the frontend to start a scan from signal delivery information.
+     * If previous scan isn't completed, this call MUST stop previous scan,
+     * and start a new scan.
+     * Scan is an async call, with FrontendScanMessage sent via callback.
+     *
+     * @param settings Signal delivery information which the frontend uses to
+     * scan the signal.
+     * @param type the type which the frontend uses to scan the signal.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if tuning can't be applied at current stage,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     */
+    scan(FrontendSettings settings, FrontendScanType type) generates (Result result);
+
+    /**
+     * Stops a previous scanning.
+     *
+     * If the method completes successfully, the frontend stop previous
+     * scanning.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successfully stop tuning.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    stopScan() generates (Result result);
+
+    /**
+     * Gets the statuses of the frontend.
+     *
+     * This retrieve the statuses of the frontend for given status types.
+     *
+     * @param statusTypes an array of status type which the caller request.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if tuning can't be applied at current stage,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     * @return statuses an array of statuses which response the caller's
+     *         request.
+     */
+    getStatus(vec<FrontendStatusType> statusTypes) generates (Result result, vec<FrontendStatus> statuses);
+
+    /**
+     * Sets Low-Noise Block downconverter (LNB) for satellite frontend.
+     *
+     * This assigns a hardware LNB resource to the satellite frontend. It can be
+     * called multiple times to update LNB assignment. The LNB resource must be
+     * released when the frontend is closed.
+     *
+     * @param lnbId the Id of assigned LNB resource.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if the frontend can't be set with a LNB, such as
+     *         cable frontend.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setLnb(ILnb lnb) generates (Result result);
+
+    /**
+     * Enble or Disable Low Noise Amplifier (LNA).
+     *
+     * @param bEnable true if activate LNA module; false if deactivate LNA
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if the frontend doesn't support LNA.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setLna(bool bEnable) generates (Result result);
+
+    /**
+     *  Sends DiSEqC (Digital Satellite Equipment Control) message.
+     *
+     * Client sends DiSeqc message to DiSEqc compatible device through the
+     * frontend. The response message from the device comes back to the client
+     * through frontend's callback onDiseqcMessage.
+     *
+     * @param diseqcMessage a byte array of data for DiSEqC message which is
+     *        specified by EUTELSAT Bus Functional Specification Version 4.2.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_STATE if the frontend can't send DiSEqc Message, such as
+     *         cable frontend.
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    sendDiseqcMessage(vec<uint8_t> diseqcMessage) generates (Result result);
 };
diff --git a/tv/tuner/1.0/IFrontendCallback.hal b/tv/tuner/1.0/IFrontendCallback.hal
index e907049..8896a09 100644
--- a/tv/tuner/1.0/IFrontendCallback.hal
+++ b/tv/tuner/1.0/IFrontendCallback.hal
@@ -33,5 +33,13 @@
      * 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.
+     * @param message the scan message sent by HAL to the client.
+     */
+    oneway onScanMessage(FrontendScanMessageType type, FrontendScanMessage message);
+};
diff --git a/tv/tuner/1.0/ILnb.hal b/tv/tuner/1.0/ILnb.hal
new file mode 100644
index 0000000..49fc3b4
--- /dev/null
+++ b/tv/tuner/1.0/ILnb.hal
@@ -0,0 +1,68 @@
+/*
+ * 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;
+
+/**
+ * A Tuner LNB (low-noise block downconverter) is used by satellite frontend
+ * to receive the microwave signal from the satellite, amplify it, and
+ * downconvert the frequency to a lower frequency.
+ */
+interface ILnb {
+    /**
+     * Set the lnb's power voltage.
+     *
+     * @param voltage the power's voltage the Lnb to use.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if the selected voltage isn't allowed,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setVoltage(FrontendLnbVoltage voltage) generates (Result result);
+
+    /**
+     * Set the lnb's tone mode.
+     *
+     * @param tone the tone mode the Lnb to use.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if the selected tone mode isn't allowed,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setTone(FrontendLnbTone tone) generates (Result result);
+
+    /**
+     * Select the lnb's position.
+     *
+     * @param position the position the Lnb to use.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         INVALID_ARGUMENT if the selected position isn't allowed,
+     *         UNKNOWN_ERROR if failed for other reasons.
+     */
+    setSatellitePosition(FrontendLnbPosition position) generates (Result result);
+
+    /**
+     * Releases the LNB instance
+     *
+     * Associated resources are released.  close may be called more than once.
+     * Calls to any other method after this will return an error
+     *
+     * @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 a0f3e8e..f1a8617 100644
--- a/tv/tuner/1.0/ITuner.hal
+++ b/tv/tuner/1.0/ITuner.hal
@@ -19,6 +19,7 @@
 import IDemux;
 import IDescrambler;
 import IFrontend;
+import ILnb;
 
 /**
  * Top level interface to manage Frontend, Demux and Decrambler hardware
@@ -45,6 +46,7 @@
      * @param frontendId the id of the frontend to be opened.
      * @return result Result status of the operation.
      *         SUCCESS if successful,
+     *         UNAVAILABLE if no resource.
      *         UNKNOWN_ERROR if creation failed for other reasons.
      * @return frontend the newly created frontend interface.
      */
@@ -62,7 +64,7 @@
      * @return demuxId newly created demux id.
      * @return demux the newly created demux interface.
      */
-     openDemux()
+    openDemux()
          generates (Result result, DemuxId demuxId, IDemux demux);
 
     /**
@@ -75,6 +77,48 @@
      *         UNKNOWN_ERROR if creation failed for other reasons.
      * @return descrambler the newly created descrambler interface.
      */
-     openDescrambler()
+    openDescrambler()
          generates (Result result, IDescrambler descrambler);
+
+    /**
+     * Create a new instance of Descrambler.
+     *
+     * It is used by the client to create a Descrambler instance.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return descrambler the newly created descrambler interface.
+     */
+    getFrontendInfo(FrontendId frontendId)
+        generates (Result result, FrontendInfo info);
+
+    /**
+     * Get low-noise block downconverter (LNB) IDs.
+     *
+     * It is used by the client to get all available LNBs' IDs.
+     *
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNKNOWN_ERROR if tuning failed for other reasons.
+     * @return frontendIds an array of LnbId for the available LNBs.
+     */
+    getLnbIds() generates (Result result, vec<LnbId> lnbIds);
+
+    /**
+     * Create a new instance of Lnb given a lnbId.
+     *
+     * It is used by the client to create a Lnb instance for satellite Frontend.
+     *
+     * @param lnbId the id of the LNB to be opened.
+     * @return result Result status of the operation.
+     *         SUCCESS if successful,
+     *         UNAVAILABLE if no resource.
+     *         UNKNOWN_ERROR if creation failed for other reasons.
+     * @return lnb the newly created Lnb interface.
+     */
+    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 b211dd2..0ae8bcd 100644
--- a/tv/tuner/1.0/default/Android.bp
+++ b/tv/tuner/1.0/default/Android.bp
@@ -8,6 +8,7 @@
         "Descrambler.cpp",
         "Demux.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 4016c5a..889e42e 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -73,34 +73,6 @@
 
 Demux::~Demux() {}
 
-bool Demux::createAndSaveMQ(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.resize(filterId + 1);
-    mFilterMQs[filterId] = std::move(tmpFilterMQ);
-
-    EventFlag* mFilterEventFlag;
-    if (EventFlag::createEventFlag(mFilterMQs[filterId]->getEventFlagWord(), &mFilterEventFlag) !=
-        OK) {
-        return false;
-    }
-    mFilterEventFlags.resize(filterId + 1);
-    mFilterEventFlags[filterId] = mFilterEventFlag;
-    mFilterWriteCount.resize(filterId + 1);
-    mFilterWriteCount[filterId] = 0;
-    mThreadRunning.resize(filterId + 1);
-
-    return true;
-}
-
 Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
     ALOGV("%s", __FUNCTION__);
 
@@ -113,23 +85,42 @@
                               const sp<IDemuxCallback>& cb, addFilter_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    uint32_t filterId = mLastUsedFilterId + 1;
-    mLastUsedFilterId += 1;
+    uint32_t filterId;
+
+    if (!mUnusedFilterIds.empty()) {
+        filterId = *mUnusedFilterIds.begin();
+
+        mUnusedFilterIds.erase(filterId);
+    } else {
+        filterId = ++mLastUsedFilterId;
+
+        mDemuxCallbacks.resize(filterId + 1);
+        mFilterMQs.resize(filterId + 1);
+        mFilterEvents.resize(filterId + 1);
+        mFilterEventFlags.resize(filterId + 1);
+        mFilterThreadRunning.resize(filterId + 1);
+        mFilterThreads.resize(filterId + 1);
+    }
+
+    mUsedFilterIds.insert(filterId);
 
     if ((type != DemuxFilterType::PCR || type != DemuxFilterType::TS) && cb == nullptr) {
         ALOGW("callback can't be null");
         _hidl_cb(Result::INVALID_ARGUMENT, filterId);
         return Void();
     }
+
     // Add callback
-    mDemuxCallbacks.resize(filterId + 1);
     mDemuxCallbacks[filterId] = cb;
 
-    // Mapping from the filter ID to the filter type
-    mFilterTypes.resize(filterId + 1);
-    mFilterTypes[filterId] = type;
+    // Mapping from the filter ID to the filter event
+    DemuxFilterEvent event{
+            .filterId = filterId,
+            .filterType = type,
+    };
+    mFilterEvents[filterId] = event;
 
-    if (!createAndSaveMQ(bufferSize, filterId)) {
+    if (!createFilterMQ(bufferSize, filterId)) {
         _hidl_cb(Result::UNKNOWN_ERROR, -1);
         return Void();
     }
@@ -141,8 +132,8 @@
 Return<void> Demux::getFilterQueueDesc(uint32_t filterId, getFilterQueueDesc_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    if (filterId < 0 || filterId > mLastUsedFilterId) {
-        ALOGW("No filter with id: %d exists", filterId);
+    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();
     }
@@ -160,35 +151,29 @@
 
 Return<Result> Demux::startFilter(uint32_t filterId) {
     ALOGV("%s", __FUNCTION__);
+    Result result;
 
-    if (filterId < 0 || filterId > mLastUsedFilterId) {
-        ALOGW("No filter with id: %d exists", filterId);
+    if (mUsedFilterIds.find(filterId) == mUsedFilterIds.end()) {
+        ALOGW("No filter with id: %d exists to start filter", filterId);
         return Result::INVALID_ARGUMENT;
     }
 
-    DemuxFilterType filterType = mFilterTypes[filterId];
-    Result result;
-    DemuxFilterEvent event{
-            .filterId = filterId,
-            .filterType = filterType,
-    };
-
-    switch (filterType) {
+    switch (mFilterEvents[filterId].filterType) {
         case DemuxFilterType::SECTION:
-            result = startSectionFilterHandler(event);
+            result = startFilterLoop(filterId);
             break;
         case DemuxFilterType::PES:
-            result = startPesFilterHandler(event);
+            result = startPesFilterHandler(filterId);
             break;
         case DemuxFilterType::TS:
             result = startTsFilterHandler();
             return Result::SUCCESS;
         case DemuxFilterType::AUDIO:
         case DemuxFilterType::VIDEO:
-            result = startMediaFilterHandler(event);
+            result = startMediaFilterHandler(filterId);
             break;
         case DemuxFilterType::RECORD:
-            result = startRecordFilterHandler(event);
+            result = startRecordFilterHandler(filterId);
             break;
         case DemuxFilterType::PCR:
             result = startPcrFilterHandler();
@@ -212,9 +197,13 @@
     return Result::SUCCESS;
 }
 
-Return<Result> Demux::removeFilter(uint32_t /* filterId */) {
+Return<Result> Demux::removeFilter(uint32_t filterId) {
     ALOGV("%s", __FUNCTION__);
 
+    // resetFilterRecords(filterId);
+    mUsedFilterIds.erase(filterId);
+    mUnusedFilterIds.insert(filterId);
+
     return Result::SUCCESS;
 }
 
@@ -239,25 +228,291 @@
 Return<Result> Demux::close() {
     ALOGV("%s", __FUNCTION__);
 
+    set<uint32_t>::iterator it;
+    mInputThread = 0;
+    mOutputThread = 0;
+    mFilterThreads.clear();
+    mUnusedFilterIds.clear();
+    mUsedFilterIds.clear();
+    mDemuxCallbacks.clear();
+    mFilterMQs.clear();
+    mFilterEvents.clear();
+    mFilterEventFlags.clear();
+    mLastUsedFilterId = -1;
+
     return Result::SUCCESS;
 }
 
-bool Demux::writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum) {
-    event.events.resize(sectionNum);
-    for (int i = 0; i < sectionNum; i++) {
-        DemuxFilterSectionEvent secEvent;
-        secEvent = {
-                // temp dump meta data
-                .tableId = 0,
-                .version = 1,
-                .sectionNum = 1,
-                .dataLength = 530,
-        };
-        event.events[i].section(secEvent);
-        if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) {
-            return false;
-        }
+Return<Result> Demux::addOutput(uint32_t bufferSize, const sp<IDemuxCallback>& 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());
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, *mOutputMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Demux::configureOutput(const DemuxOutputSettings& /* settings */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::attachOutputTsFilter(uint32_t /*filterId*/) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::detachOutputTsFilter(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());
+        return Void();
+    }
+
+    _hidl_cb(Result::SUCCESS, *mInputMQ->getDesc());
+    return Void();
+}
+
+Return<Result> Demux::configureInput(const DemuxInputSettings& /* settings */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Demux::startInput() {
+    ALOGV("%s", __FUNCTION__);
+
+    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__);
+
+    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, vector<uint8_t> data) {
+    if (!writeSectionsAndCreateEvent(filterId, data)) {
+        ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId);
+        return Result::UNKNOWN_ERROR;
+    }
+
+    return Result::SUCCESS;
+}
+
+Result Demux::startPesFilterHandler(uint32_t filterId) {
+    // TODO generate multiple events in one event callback
+    DemuxFilterPesEvent pesEvent;
+    pesEvent = {
+            // temp dump meta data
+            .streamId = 0,
+            .dataLength = 530,
+    };
+    mFilterEvents[filterId].events.resize(1);
+    mFilterEvents[filterId].events[0].pes(pesEvent);
+    /*pthread_create(&mThreadId, NULL, __threadLoop, this);
+    pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/
+    if (!writeDataToFilterMQ(fakeDataInputBuffer, filterId)) {
+        return Result::INVALID_STATE;
+    }
+
+    if (mDemuxCallbacks[filterId] == nullptr) {
+        return Result::NOT_INITIALIZED;
+    }
+
+    mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
+    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;
+    // 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;
+    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);
+    int size = mFilterEvents[filterId].events.size();
+    mFilterEvents[filterId].events.resize(size + 1);
+    if (!writeDataToFilterMQ(data, filterId)) {
+        return false;
+    }
+    DemuxFilterSectionEvent secEvent;
+    secEvent = {
+            // temp dump meta data
+            .tableId = 0,
+            .version = 1,
+            .sectionNum = 1,
+            .dataLength = 530,
+    };
+    mFilterEvents[filterId].events[size].section(secEvent);
     return true;
 }
 
@@ -269,116 +524,82 @@
     return false;
 }
 
-Result Demux::startSectionFilterHandler(DemuxFilterEvent event) {
-    struct ThreadArgs* threadArgs = (struct ThreadArgs*)malloc(sizeof(struct ThreadArgs));
-    threadArgs->user = this;
-    threadArgs->event = &event;
+bool Demux::filterAndOutputData() {
+    ALOGD("[Demux] start to dispatch data to filters");
+    // Read input data from the input FMQ
+    int size = mInputMQ->availableToRead();
+    vector<uint8_t> dataOutputBuffer;
+    dataOutputBuffer.resize(size);
+    mInputMQ->read(dataOutputBuffer.data(), size);
 
-    pthread_create(&mThreadId, NULL, __threadLoop, (void*)threadArgs);
-    pthread_setname_np(mThreadId, "demux_filter_waiting_loop");
-
-    return Result::SUCCESS;
-}
-
-Result Demux::startPesFilterHandler(DemuxFilterEvent& event) {
-    // TODO generate multiple events in one event callback
-    DemuxFilterPesEvent pesEvent;
-    pesEvent = {
-            // temp dump meta data
-            .streamId = 0,
-            .dataLength = 530,
-    };
-    event.events.resize(1);
-    event.events[0].pes(pesEvent);
-    /*pthread_create(&mThreadId, NULL, __threadLoop, this);
-    pthread_setname_np(mThreadId, "demux_section_filter_waiting_loop");*/
-    if (!writeDataToFilterMQ(fakeDataInputBuffer, event.filterId)) {
-        return Result::INVALID_STATE;
+    Result result;
+    // Filter the data and feed the output to each filter
+    set<uint32_t>::iterator it;
+    for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
+        switch (mFilterEvents[*it].filterType) {
+            case DemuxFilterType::SECTION:
+                result = startSectionFilterHandler(*it, dataOutputBuffer);
+                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 (mDemuxCallbacks[event.filterId] == nullptr) {
-        return Result::NOT_INITIALIZED;
-    }
-
-    mDemuxCallbacks[event.filterId]->onFilterEvent(event);
-    return Result::SUCCESS;
+    return result == Result::SUCCESS;
 }
 
-Result Demux::startTsFilterHandler() {
-    // TODO handle starting TS filter
-    return Result::SUCCESS;
-}
-
-Result Demux::startMediaFilterHandler(DemuxFilterEvent& event) {
-    DemuxFilterMediaEvent mediaEvent;
-    mediaEvent = {
-            // temp dump meta data
-            .pts = 0,
-            .dataLength = 530,
-            .secureMemory = nullptr,
-    };
-    event.events.resize(1);
-    event.events[0].media() = mediaEvent;
-    // TODO handle write FQM for media stream
-    return Result::SUCCESS;
-}
-
-Result Demux::startRecordFilterHandler(DemuxFilterEvent& event) {
-    DemuxFilterRecordEvent recordEvent;
-    recordEvent = {
-            // temp dump meta data
-            .tpid = 0,
-            .packetNum = 0,
-    };
-    recordEvent.indexMask.tsIndexMask() = 0x01;
-    event.events.resize(1);
-    event.events[0].ts() = recordEvent;
-    return Result::SUCCESS;
-}
-
-Result Demux::startPcrFilterHandler() {
-    // TODO handle starting PCR filter
-    return Result::SUCCESS;
-}
-
-void* Demux::__threadLoop(void* threadArg) {
+void* Demux::__threadLoopFilter(void* threadArg) {
     Demux* const self = static_cast<Demux*>(((struct ThreadArgs*)threadArg)->user);
-    self->filterThreadLoop(((struct ThreadArgs*)threadArg)->event);
+    self->filterThreadLoop(((struct ThreadArgs*)threadArg)->filterId);
     return 0;
 }
 
-void Demux::filterThreadLoop(DemuxFilterEvent* event) {
-    uint32_t filterId = event->filterId;
-    ALOGD("[Demux] filter %d threadLoop start.", filterId);
-    mThreadRunning[filterId] = true;
+void* Demux::__threadLoopInput(void* user) {
+    Demux* const self = static_cast<Demux*>(user);
+    self->inputThreadLoop();
+    return 0;
+}
 
-    while (mThreadRunning[filterId]) {
+void Demux::filterThreadLoop(uint32_t filterId) {
+    ALOGD("[Demux] filter %d threadLoop start.", filterId);
+    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
+        mDemuxCallbacks[filterId]->onFilterEvent(mFilterEvents[filterId]);
+        mFilterEvents[filterId].events.resize(0);
+        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++) {
-            DemuxFilterEvent filterEvent{
-                    .filterId = filterId,
-                    .filterType = event->filterType,
-            };
-            if (!writeSectionsAndCreateEvent(filterEvent, 2)) {
-                ALOGD("[Demux] filter %d fails to write into FMQ. Ending thread", filterId);
-                break;
-            }
-            mFilterWriteCount[filterId]++;
-            if (mDemuxCallbacks[filterId] == nullptr) {
-                ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId);
-                break;
-            }
-            // After successfully write, send a callback and wait for the read to be done
-            mDemuxCallbacks[filterId]->onFilterEvent(filterEvent);
-            // 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;
-            }
-            while (mThreadRunning[filterId]) {
+            while (mFilterThreadRunning[filterId]) {
                 status_t status = mFilterEventFlags[filterId]->wait(
                         static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
                         WAIT_TIMEOUT, true /* retry on spurious wake */);
@@ -388,15 +609,60 @@
                 }
                 break;
             }
-        }
 
-        mFilterWriteCount[filterId] = 0;
-        mThreadRunning[filterId] = false;
+            if (mDemuxCallbacks[filterId] == nullptr) {
+                ALOGD("[Demux] filter %d does not hava callback. Ending thread", filterId);
+                break;
+            }
+
+            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
+                mDemuxCallbacks[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.");
+    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 (!filterAndOutputData()) {
+            ALOGD("[Demux] input data failed to be filtered. Ending thread");
+            break;
+        }
+    }
+
+    mInputThreadRunning = false;
+    ALOGD("[Demux] input thread ended.");
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 8b00266..2fdde8d 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/tv/tuner/1.0/IDemux.h>
 #include <fmq/MessageQueue.h>
+#include <set>
 
 using namespace std;
 
@@ -43,6 +44,8 @@
   public:
     Demux(uint32_t demuxId);
 
+    ~Demux();
+
     virtual Return<Result> setFrontendDataSource(uint32_t frontendId) override;
 
     virtual Return<Result> close() override;
@@ -68,8 +71,58 @@
 
     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<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> attachOutputTsFilter(uint32_t filterId) override;
+
+    virtual Return<Result> detachOutputTsFilter(uint32_t filterId) override;
+
+    virtual Return<Result> startOutput() override;
+
+    virtual Return<Result> stopOutput() override;
+
+    virtual Return<Result> flushOutput() override;
+
+    virtual Return<Result> removeOutput() override;
+
   private:
-    virtual ~Demux();
+    // A struct that passes the arguments to a newly created filter thread
+    struct ThreadArgs {
+        Demux* user;
+        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, vector<uint8_t> data);
+    Result startPesFilterHandler(uint32_t filterId);
+    Result startTsFilterHandler();
+    Result startMediaFilterHandler(uint32_t filterId);
+    Result startRecordFilterHandler(uint32_t filterId);
+    Result startPcrFilterHandler();
+    Result startFilterLoop(uint32_t filterId);
+
     /**
      * To create a FilterMQ with the the next available Filter ID.
      * Creating Event Flag at the same time.
@@ -77,60 +130,80 @@
      *
      * Return false is any of the above processes fails.
      */
-    bool createAndSaveMQ(uint32_t bufferSize, uint32_t filterId);
+    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);
-    Result startSectionFilterHandler(DemuxFilterEvent event);
-    Result startPesFilterHandler(DemuxFilterEvent& event);
-    Result startTsFilterHandler();
-    Result startMediaFilterHandler(DemuxFilterEvent& event);
-    Result startRecordFilterHandler(DemuxFilterEvent& event);
-    Result startPcrFilterHandler();
-    bool writeSectionsAndCreateEvent(DemuxFilterEvent& event, uint32_t sectionNum);
-    void filterThreadLoop(DemuxFilterEvent* event);
-    static void* __threadLoop(void* data);
+    bool readDataFromMQ();
+    bool writeSectionsAndCreateEvent(uint32_t filterId, vector<uint8_t> data);
+    /**
+     * 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 filterAndOutputData();
+    static void* __threadLoopFilter(void* data);
+    static void* __threadLoopInput(void* user);
+    void filterThreadLoop(uint32_t filterId);
+    void inputThreadLoop();
 
     uint32_t mDemuxId;
     uint32_t mSourceFrontendId;
     /**
-     * Record the last used filer id. Initial value is -1.
+     * Record the last used filter id. Initial value is -1.
      * Filter Id starts with 0.
      */
     uint32_t mLastUsedFilterId = -1;
     /**
+     * Record all the used filter Ids.
+     * Any removed filter id should be removed from this set.
+     */
+    set<uint32_t> mUsedFilterIds;
+    /**
+     * Record all the unused filter Ids within mLastUsedFilterId.
+     * Removed filter Id should be added into this set.
+     * When this set is not empty, ids here should be allocated first
+     * and added into usedFilterIds.
+     */
+    set<uint32_t> mUnusedFilterIds;
+    /**
      * A list of created FilterMQ ptrs.
      * The array number is the filter ID.
      */
     vector<unique_ptr<FilterMQ>> mFilterMQs;
-    vector<DemuxFilterType> mFilterTypes;
     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>> mDemuxCallbacks;
-    /**
-     * How many times a specific filter has written since started
-     */
-    vector<uint16_t> mFilterWriteCount;
-    pthread_t mThreadId = 0;
+    sp<IDemuxCallback> mInputCallback;
+    sp<IDemuxCallback> mOutputCallback;
+    // Thread handlers
+    pthread_t mInputThread;
+    pthread_t mOutputThread;
+    vector<pthread_t> mFilterThreads;
     /**
      * If a specific filter's writing loop is still running
      */
-    vector<bool> mThreadRunning;
+    vector<bool> mFilterThreadRunning;
+    bool mInputThreadRunning;
     /**
      * Lock to protect writes to the FMQs
      */
     std::mutex mWriteLock;
     /**
+     * Lock to protect writes to the filter event
+     */
+    std::mutex mFilterEventLock;
+    /**
      * How many times a filter should write
      * TODO make this dynamic/random/can take as a parameter
      */
     const uint16_t SECTION_WRITE_COUNT = 10;
-    // A struct that passes the arguments to a newly created filter thread
-    struct ThreadArgs {
-        Demux* user;
-        DemuxFilterEvent* event;
-    };
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 3dcc2b1..0609d05 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -77,6 +77,46 @@
     return Result::SUCCESS;
 }
 
+Return<Result> Frontend::scan(const FrontendSettings& /* settings */, FrontendScanType /* type */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::stopScan() {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<void> Frontend::getStatus(const hidl_vec<FrontendStatusType>& /* statusTypes */,
+                                 getStatus_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<FrontendStatus> statuses;
+    _hidl_cb(Result::SUCCESS, statuses);
+
+    return Void();
+}
+
+Return<Result> Frontend::setLna(bool /* bEnable */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::setLnb(const sp<ILnb>& /* lnb */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Frontend::sendDiseqcMessage(const hidl_vec<uint8_t>& /* diseqcMessage */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
 FrontendType Frontend::getFrontendType() {
     return mType;
 }
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
index f77a0d8..fc586b5 100644
--- a/tv/tuner/1.0/default/Frontend.h
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -38,6 +38,7 @@
 class Frontend : public IFrontend {
   public:
     Frontend();
+
     Frontend(FrontendType type, FrontendId id);
 
     virtual Return<Result> close() override;
@@ -48,6 +49,19 @@
 
     virtual Return<Result> stopTune() override;
 
+    virtual Return<Result> scan(const FrontendSettings& settings, FrontendScanType type) override;
+
+    virtual Return<Result> stopScan() override;
+
+    virtual Return<void> getStatus(const hidl_vec<FrontendStatusType>& statusTypes,
+                                   getStatus_cb _hidl_cb) override;
+
+    virtual Return<Result> sendDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) override;
+
+    virtual Return<Result> setLna(bool bEnable) override;
+
+    virtual Return<Result> setLnb(const sp<ILnb>& lnb) override;
+
     FrontendType getFrontendType();
 
     FrontendId getFrontendId();
diff --git a/tv/tuner/1.0/default/Lnb.cpp b/tv/tuner/1.0/default/Lnb.cpp
new file mode 100644
index 0000000..b81bb15
--- /dev/null
+++ b/tv/tuner/1.0/default/Lnb.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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-Lnb"
+
+#include "Lnb.h"
+#include <utils/Log.h>
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+namespace V1_0 {
+namespace implementation {
+
+Lnb::Lnb() {}
+
+Lnb::~Lnb() {}
+
+Return<Result> Lnb::setVoltage(FrontendLnbVoltage /* voltage */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setTone(FrontendLnbTone /* tone */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::setSatellitePosition(FrontendLnbPosition /* position */) {
+    ALOGV("%s", __FUNCTION__);
+
+    return Result::SUCCESS;
+}
+
+Return<Result> Lnb::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/Lnb.h b/tv/tuner/1.0/default/Lnb.h
new file mode 100644
index 0000000..df7e0fe
--- /dev/null
+++ b/tv/tuner/1.0/default/Lnb.h
@@ -0,0 +1,60 @@
+/*
+ * 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_LNB_H_
+#define ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_
+
+#include <android/hardware/tv/tuner/1.0/ILnb.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+
+using namespace std;
+
+namespace android {
+namespace hardware {
+namespace tv {
+namespace tuner {
+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::Result;
+
+class Lnb : public ILnb {
+  public:
+    Lnb();
+
+    virtual Return<Result> setVoltage(FrontendLnbVoltage voltage);
+
+    virtual Return<Result> setTone(FrontendLnbTone tone) override;
+
+    virtual Return<Result> setSatellitePosition(FrontendLnbPosition position) override;
+
+    virtual Return<Result> close() override;
+
+  private:
+    virtual ~Lnb();
+};
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace tuner
+}  // namespace tv
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_TV_TUNER_V1_0_LNB_H_
\ No newline at end of file
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 68b3436..00831ae 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -22,6 +22,7 @@
 #include "Demux.h"
 #include "Descrambler.h"
 #include "Frontend.h"
+#include "Lnb.h"
 
 namespace android {
 namespace hardware {
@@ -95,6 +96,33 @@
     return Void();
 }
 
+Return<void> Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    FrontendInfo info;
+
+    _hidl_cb(Result::SUCCESS, info);
+    return Void();
+}
+
+Return<void> Tuner::getLnbIds(getLnbIds_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    vector<LnbId> lnbIds;
+
+    _hidl_cb(Result::SUCCESS, lnbIds);
+    return Void();
+}
+
+Return<void> Tuner::openLnbById(LnbId /* lnbId */, openLnbById_cb _hidl_cb) {
+    ALOGV("%s", __FUNCTION__);
+
+    sp<ILnb> lnb = new Lnb();
+
+    _hidl_cb(Result::SUCCESS, lnb);
+    return Void();
+}
+
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Tuner.h b/tv/tuner/1.0/default/Tuner.h
index 12e9594..62227ee 100644
--- a/tv/tuner/1.0/default/Tuner.h
+++ b/tv/tuner/1.0/default/Tuner.h
@@ -41,6 +41,13 @@
 
     virtual Return<void> openDescrambler(openDescrambler_cb _hidl_cb) override;
 
+    virtual Return<void> getFrontendInfo(FrontendId frontendId,
+                                         getFrontendInfo_cb _hidl_cb) override;
+
+    virtual Return<void> getLnbIds(getLnbIds_cb _hidl_cb) override;
+
+    virtual Return<void> openLnbById(LnbId lnbId, openLnbById_cb _hidl_cb) override;
+
   private:
     virtual ~Tuner();
     // Static mFrontends array to maintain local frontends information
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 4522db2..a1153e9 100644
--- a/tv/tuner/1.0/types.hal
+++ b/tv/tuner/1.0/types.hal
@@ -41,42 +41,121 @@
 enum FrontendType : uint32_t {
     UNDEFINED = 0,
     ANALOG,
+    /* Advanced Television Systems Committee (ATSC) Standard A/72. */
     ATSC,
+    /* Advanced Television Systems Committee (ATSC 3.0) Standard A/330. */
+    ATSC3,
+    /**
+     * Digital Video Broadcasting - Cable
+     * DVB Cable Frontend Standard ETSI EN 300 468 V1.15.1.
+     */
     DVBC,
+    /**
+     * Digital Video Broadcasting - Satellite
+     * DVB Satellite Frontend Standard ETSI EN 300 468 V1.15.1 and
+     * ETSI EN 302 307-2 V1.1.1.
+     */
     DVBS,
+    /**
+     * Digital Video Broadcasting - Terrestrial
+     * DVB Terresttrial Frontend Standard ETSI EN 300 468 V1.15.1 and
+     * ETSI EN 302 755 V1.4.1.
+     */
     DVBT,
+    /* Integrated Services Digital Broadcasting-Satellite (ISDB-S)
+     * ARIB SDT-B20 is technical document of ISDB-S.
+     */
+    ISDBS,
+    /* Integrated Services Digital Broadcasting-Satellite (ISDB-S)
+     * ARIB TR-B15 is technical document of ISDB-S3.
+     */
+    ISDBS3,
+    /* Integrated Services Digital Broadcasting-Terrestrial (ISDB-T or SBTVD)
+     * ABNT NBR 15603 is technical document of ISDB-T.
+     */
     ISDBT,
 };
 
 /**
  *  Inner Forward Error Correction type as specified in ETSI EN 300 468 V1.15.1
- *  It's a 4-bit field specifying the inner FEC scheme used according to the
- *  table 35 in the spec.
+ *  and ETSI EN 302 307-2 V1.1.1.
  */
 @export
-enum FrontendInnerFec : uint32_t {
+enum FrontendInnerFec : uint64_t {
     /* Not defined */
     FEC_UNDEFINED = 0,
-    /* 1/2 conv. code rate */
-    FEC_1_2 = 1 << 0,
-    /* 2/3 conv. code rate */
-    FEC_2_3 = 1 << 1,
-    /* 3/4 conv. code rate */
-    FEC_3_4 = 1 << 2,
-    /* 5/6 conv. code rate */
-    FEC_5_6 = 1 << 3,
-    /* 7/8 conv. code rate */
-    FEC_7_8 = 1 << 4,
-    /* 8/9 conv. code rate */
-    FEC_8_9 = 1 << 5,
-    /* 3/5 conv. code rate */
-    FEC_3_5 = 1 << 6,
-    /* 4/5 conv. code rate */
-    FEC_4_5 = 1 << 7,
-    /* 9/10 conv. code rate */
-    FEC_9_10 = 1 << 8,
     /* hardware is able to detect and set FEC automatically */
-    FEC_AUTO = 1 << 9,
+    AUTO = 1 << 0,
+    /* 1/2 conv. code rate */
+    FEC_1_2 = 1 << 1,
+    /* 1/3 conv. code rate */
+    FEC_1_3 = 1 << 2,
+    /* 1/4 conv. code rate */
+    FEC_1_4 = 1 << 3,
+    /* 1/5 conv. code rate */
+    FEC_1_5 = 1 << 4,
+    /* 2/3 conv. code rate */
+    FEC_2_3 = 1 << 5,
+    /* 2/5 conv. code rate */
+    FEC_2_5 = 1 << 6,
+    /* 2/9 conv. code rate */
+    FEC_2_9 = 1 << 7,
+    /* 3/4 conv. code rate */
+    FEC_3_4 = 1 << 8,
+    /* 3/5 conv. code rate */
+    FEC_3_5 = 1 << 9,
+    /* 4/5 conv. code rate */
+    FEC_4_5 = 1 << 10,
+    /* 4/15 conv. code rate */
+    FEC_4_15 = 1 << 11,
+    /* 5/6 conv. code rate */
+    FEC_5_6 = 1 << 12,
+    /* 5/9 conv. code rate */
+    FEC_5_9 = 1 << 13,
+    /* 6/7 conv. code rate */
+    FEC_6_7 = 1 << 14,
+    /* 7/8 conv. code rate */
+    FEC_7_8 = 1 << 15,
+    /* 7/9 conv. code rate */
+    FEC_7_9 = 1 << 16,
+    /* 7/15 conv. code rate */
+    FEC_7_15 = 1 << 17,
+    /* 8/9 conv. code rate */
+    FEC_8_9 = 1 << 18,
+    /* 8/15 conv. code rate */
+    FEC_8_15 = 1 << 19,
+    /* 9/10 conv. code rate */
+    FEC_9_10 = 1 << 20,
+    /* 9/20 conv. code rate */
+    FEC_9_20 = 1 << 21,
+    /* 11/15 conv. code rate */
+    FEC_11_15 = 1 << 22,
+    /* 11/20 conv. code rate */
+    FEC_11_20 = 1 << 23,
+    /* 11/45 conv. code rate */
+    FEC_11_45 = 1 << 24,
+    /* 13/18 conv. code rate */
+    FEC_13_18 = 1 << 25,
+    /* 13/45 conv. code rate */
+    FEC_13_45 = 1 << 26,
+    /* 14/45 conv. code rate */
+    FEC_14_45 = 1 << 27,
+    /* 23/36 conv. code rate */
+    FEC_23_36 = 1 << 28,
+    /* 25/36 conv. code rate */
+    FEC_25_36 = 1 << 29,
+    /* 26/45 conv. code rate */
+    FEC_26_45 = 1 << 30,
+    /* 28/45 conv. code rate */
+    FEC_28_45 = 1 << 31,
+    /* 29/45 conv. code rate */
+    FEC_29_45 = 1 << 32,
+    /* 31/45 conv. code rate */
+    FEC_31_45 = 1 << 33,
+    /* 32/45 conv. code rate */
+    FEC_32_45 = 1 << 34,
+    /* 77/90 conv. code rate */
+    FEC_77_90 = 1 << 35,
 };
 
 /**
@@ -99,21 +178,760 @@
 };
 
 /**
+ *  Capabilities for ATSC Frontend.
+ */
+struct FrontendAtscCapabilities {
+    /** Modulation capability */
+    bitfield<FrontendAtscModulation> modulationCap;
+};
+
+/**
+ *  Modulation Type for ATSC3.
+ */
+@export
+enum FrontendAtsc3Modulation : uint32_t {
+    UNDEFINED = 0,
+    MOD_QPSK = 1 << 0,
+    MOD_16QAM = 1 << 1,
+    MOD_64QAM = 1 << 2,
+    MOD_256QAM = 1 << 3,
+    MOD_1024QAM = 1 << 4,
+    MOD_4096QAM = 1 << 5,
+};
+
+/**
+ *  Bandwidth for ATSC3.
+ */
+@export
+enum FrontendAtsc3Bandwidth : uint32_t {
+    UNDEFINED = 0,
+    BANDWIDTH_8MHZ = 1 << 0,
+    BANDWIDTH_7MHZ = 1 << 1,
+    BANDWIDTH_6MHZ = 1 << 2,
+};
+
+/**
+ *  Time Interleave Mode for ATSC3.
+ */
+@export
+enum FrontendAtsc3TimeInterleaveMode : uint32_t {
+    UNDEFINED,
+    CTI,
+    HTI,
+};
+
+/**
+ *  Code Rate for ATSC3.
+ */
+@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,
+};
+
+/**
+ *  Forward Error Correction (FEC) for ATSC3.
+ */
+@export
+enum FrontendAtsc3Fec : uint32_t {
+    UNDEFINED,
+    BCH_LDPC_16K,
+    BCH_LDPC_64K,
+    CRC_LDPC_16K,
+    CRC_LDPC_64K,
+    LDPC_16K,
+    LDPC_64K,
+};
+
+/**
+ *  Signal Settings for an ATSC3 Frontend.
+ */
+struct FrontendAtsc3Settings {
+    /** Signal frequency in Hertz */
+    uint32_t frequency;
+    FrontendAtsc3Bandwidth bandwidth;
+    FrontendAtsc3TimeInterleaveMode interleaveMode;
+    FrontendAtsc3CodeRate codeRate;
+    FrontendAtsc3Fec fec;
+    vec<uint8_t> plpIdList;
+};
+
+/**
+ *  Capabilities for ATSC3 Frontend.
+ */
+struct FrontendAtsc3Capabilities {
+    /** Modulation capability */
+    bitfield<FrontendAtsc3Modulation> modulationCap;
+    /** Bandwidth capability */
+    bitfield<FrontendAtsc3Bandwidth> bandwidthCap;
+};
+
+/**
+ *  Modulation Type for DVBS.
+ */
+@export
+enum FrontendDvbsModulation : int32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Modulation automatically */
+    AUTO = 1 << 0,
+    MOD_QPSK = 1 << 1,
+    MOD_8PSK = 1 << 2,
+    MOD_16QAM = 1 << 3,
+    MOD_16PSK = 1 << 4,
+    MOD_32PSK = 1 << 5,
+    MOD_ACM = 1 << 6,
+    MOD_8APSK = 1 << 7,
+    MOD_16APSK = 1 << 8,
+    MOD_32APSK = 1 << 9,
+    MOD_64APSK = 1 << 10,
+    MOD_128APSK = 1 << 11,
+    MOD_256APSK = 1 << 12,
+    /** Reserved for Proprietary modulation */
+    MOD_RESERVED = 1 << 13,
+};
+
+/**
+ *  Roll Off value for DVBS.
+ */
+@export
+enum FrontendDvbsRolloff : uint32_t {
+    UNDEFINED,
+    ROLLOFF_0_35,
+    ROLLOFF_0_25,
+    ROLLOFF_0_20,
+    ROLLOFF_0_15,
+    ROLLOFF_0_10,
+    ROLLOFF_0_5,
+};
+
+/**
+ *  Pilot mode for DVBS.
+ */
+@export
+enum FrontendDvbsPilot : uint32_t {
+    UNDEFINED,
+    ON,
+    OFF,
+    AUTO,
+};
+
+/**
+ *  Code Rate for DVBS.
+ */
+struct FrontendDvbsCodeRate {
+    FrontendInnerFec fec;
+    bool isLinear;
+    /* true if enable short frame */
+    bool isShortFrames;
+    /* bits number in 1000 symbol. 0 if use the default. */
+    uint32_t bitsPer1000Symbol;
+};
+
+/**
+ *  Sub standards in DVBS.
+ */
+@export
+enum FrontendDvbsStandard : uint8_t {
+    AUTO = 1 << 0,
+    S = 1 << 1,
+    S2 = 1 << 2,
+    S2X = 1 << 3,
+};
+
+/**
+ *  Signal Settings for an DVBS Frontend.
+ */
+struct FrontendDvbsSettings {
+    /** Signal frequency in Hertz */
+    uint32_t frequency;
+    FrontendDvbsModulation modulation;
+    FrontendDvbsCodeRate coderate;
+    /** Symbols per second */
+    uint32_t symbolRate;
+    FrontendDvbsRolloff rolloff;
+    FrontendDvbsPilot pilot;
+    uint32_t inputStreamId;
+    FrontendDvbsStandard standard;
+};
+
+/**
+ *  Capabilities for DVBS Frontend.
+ */
+struct FrontendDvbsCapabilities {
+    bitfield<FrontendDvbsModulation> modulationCap;
+    bitfield<FrontendInnerFec> innerfecCap;
+    bitfield<FrontendDvbsStandard>  standard;
+};
+
+/**
+ *  Modulation Type for DVBC.
+ */
+@export
+enum FrontendDvbcModulation : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Modulation automatically */
+    AUTO = 1 << 0,
+    MOD_16QAM = 1 << 1,
+    MOD_32QAM = 1 << 2,
+    MOD_64QAM = 1 << 3,
+    MOD_128QAM = 1 << 4,
+    MOD_256QAM = 1 << 5,
+};
+
+/**
+ *  Outer Forward Error Correction (FEC) Type for DVBC.
+ */
+@export
+enum FrontendDvbcOuterFec : uint32_t {
+    UNDEFINED = 0,
+    OUTER_FEC_NONE,
+    OUTER_FEC_RS,
+};
+
+/**
+ *   Annex Type for DVBC.
+ */
+@export
+enum FrontendDvbcAnnex : uint8_t {
+    UNDEFINED = 0,
+    A = 1 << 0,
+    B = 1 << 1,
+    C = 1 << 2,
+};
+
+/**
+ *   Spectral Inversion Type for DVBC.
+ */
+@export
+enum FrontendDvbcSpectralInversion : uint32_t {
+    UNDEFINED,
+    NORMAL,
+    INVERTED,
+};
+
+/**
+ *  Signal Settings for an DVBC Frontend.
+ */
+struct FrontendDvbcSettings {
+    /** Signal frequency in Hertz */
+    uint32_t frequency;
+    FrontendDvbcModulation modulation;
+    FrontendInnerFec fec;
+    /** Symbols per second */
+    uint32_t symbolRate;
+    FrontendDvbcOuterFec outerFec;
+    FrontendDvbcAnnex annex;
+    FrontendDvbcSpectralInversion spectralInversion;
+};
+
+/**
+ *  Capabilities for DVBC Frontend.
+ */
+struct FrontendDvbcCapabilities {
+    bitfield<FrontendDvbcModulation> modulationCap;
+    bitfield<FrontendInnerFec> fecCap;
+    bitfield<FrontendDvbcAnnex> annexCap;
+};
+
+/**
+ *  Bandwidth Type for DVBT.
+ */
+@export
+enum FrontendDvbtBandwidth : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Bandwidth automatically */
+    AUTO = 1 << 0,
+    BANDWIDTH_8MHZ = 1 << 1,
+    BANDWIDTH_7MHZ = 1 << 2,
+    BANDWIDTH_6MHZ = 1 << 3,
+    BANDWIDTH_5MHZ = 1 << 4,
+    BANDWIDTH_1_7MHZ = 1 << 5,
+    BANDWIDTH_10MHZ = 1 << 6,
+};
+
+/**
+ *  Constellation Type for DVBT.
+ */
+@export
+enum FrontendDvbtConstellation : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Constellation automatically */
+    AUTO = 1 << 0,
+    CONSTELLATION_QPSK = 1 << 1,
+    CONSTELLATION_16QAM = 1 << 2,
+    CONSTELLATION_64QAM = 1 << 3,
+    CONSTELLATION_256QAM = 1 << 4,
+};
+
+/**
+ *  Hierarchy Type for DVBT.
+ */
+@export
+enum FrontendDvbtHierarchy : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Hierarchy automatically */
+    AUTO = 1 << 0,
+    HIERARCHY_NON_NATIVE = 1 << 1,
+    HIERARCHY_1_NATIVE = 1 << 2,
+    HIERARCHY_2_NATIVE = 1 << 3,
+    HIERARCHY_4_NATIVE = 1 << 4,
+    HIERARCHY_NON_INDEPTH = 1 << 5,
+    HIERARCHY_1_INDEPTH = 1 << 6,
+    HIERARCHY_2_INDEPTH = 1 << 7,
+    HIERARCHY_4_INDEPTH = 1 << 8,
+};
+
+/**
+ *  Hierarchy Type for DVBT.
+ */
+@export
+enum FrontendDvbtCoderate : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Hierarchy 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,
+    CODERATE_3_5 = 1 << 6,
+    CODERATE_4_5 = 1 << 7,
+    CODERATE_6_7 = 1 << 8,
+    CODERATE_8_9 = 1 << 9,
+};
+
+/**
+ *  Guard Interval Type for DVBT.
+ */
+@export
+enum FrontendDvbtGuardInterval : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Guard Interval automatically */
+    AUTO = 1 << 0,
+    INTERVAL_1_32 = 1 << 1,
+    INTERVAL_1_16 = 1 << 2,
+    INTERVAL_1_8 = 1 << 3,
+    INTERVAL_1_4 = 1 << 4,
+    INTERVAL_1_128 = 1 << 5,
+    INTERVAL_19_128 = 1 << 6,
+    INTERVAL_19_256 = 1 << 7,
+};
+
+/**
+ *  Transmission Mode for DVBT.
+ */
+@export
+enum FrontendDvbtTransmissionMode : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Transmission Mode automatically */
+    AUTO = 1 << 0,
+    MODE_2K = 1 << 1,
+    MODE_8K = 1 << 2,
+    MODE_4K = 1 << 3,
+    MODE_1K = 1 << 4,
+    MODE_16K = 1 << 5,
+    MODE_32K = 1 << 6,
+};
+
+/**
+ *   Physical Layer Pipe (PLP) Mode for DVBT.
+ */
+enum FrontendDvbtPlpMode : uint32_t {
+    UNDEFINED,
+    AUTO,
+    MANUAL,
+};
+
+/**
+ *  Sub standards in DVBT.
+ */
+@export
+enum FrontendDvbtStandard : uint8_t {
+    AUTO = 1 << 0,
+    T = 1 << 1,
+    T2 = 1 << 2,
+};
+
+/**
  *  Signal Setting for DVBT Frontend.
  */
 struct FrontendDvbtSettings {
     /** Signal frequencey in Herhz */
     uint32_t frequency;
-    FrontendAtscModulation modulation;
-    FrontendInnerFec fec;
+    FrontendDvbtTransmissionMode transmissionMode;
+    FrontendDvbtBandwidth bandwidth;
+    FrontendDvbtConstellation constellation;
+    FrontendDvbtHierarchy hierarchy;
+    /** Code Rate for High Priority level */
+    FrontendDvbtCoderate hpCoderate;
+    /** Code Rate for Low Priority level */
+    FrontendDvbtCoderate lpCoderate;
+    FrontendDvbtGuardInterval guardInterval;
+    bool isHighPriority;
+    FrontendDvbtStandard standard;
+    bool isMiso;
+    FrontendDvbtPlpMode plpMode;
+    /** Physical Layer Pipe (PLP) Id */
+    uint8_t plpId;
+    /** Group Id for Physical Layer Pipe (PLP) */
+    uint8_t plpGroupId;
 };
 
 /**
- *  Modulation Type for ATSC.
+ *  Capabilities for DVBT Frontend.
+ */
+struct FrontendDvbtCapabilities {
+    bitfield<FrontendDvbtTransmissionMode> transmissionModeCap;
+    bitfield<FrontendDvbtBandwidth> bandwidthCap;
+    bitfield<FrontendDvbtConstellation> constellationCap;
+    bitfield<FrontendDvbtCoderate> coderateCap;
+    bitfield<FrontendDvbtHierarchy> hierarchyCap;
+    bitfield<FrontendDvbtGuardInterval> guardIntervalCap;
+    bool isT2Supported;
+    bool isMisoSupported;
+};
+
+/**
+ *  Roll Off Type for ISDBS.
+ */
+@export
+enum FrontendIsdbsRolloff : uint32_t {
+    UNDEFINED,
+    ROLLOFF_0_35,
+};
+
+/**
+ *  Modulaltion Type for ISDBS.
+ */
+@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,
+};
+
+/**
+ *  Code Rate Type for ISDBS.
+ */
+@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,
+};
+
+/**
+ *  Stream Id Type for ISDBS.
+ */
+@export
+enum FrontendIsdbsStreamIdType : uint32_t {
+    STREAM_ID,
+    RELATIVE_STREAM_ID,
+};
+
+/**
+ *  Signal Setting for ISDBS Frontend.
+ */
+struct FrontendIsdbsSettings {
+    /** Signal frequency in Hertz */
+    uint32_t frequency;
+    uint16_t streamId;
+    FrontendIsdbsStreamIdType streamIdType;
+    FrontendIsdbsModulation modulation;
+    FrontendIsdbsCoderate coderate;
+    /** Symbols per second */
+    uint32_t symbolRate;
+    FrontendIsdbsRolloff rolloff;
+};
+
+/**
+ *  Capabilities for ISDBS Frontend.
+ */
+struct FrontendIsdbsCapabilities {
+    bitfield<FrontendIsdbsModulation> modulationCap;
+    bitfield<FrontendIsdbsCoderate> coderateCap;
+};
+
+/**
+ *  Roll of Type for ISDBS3.
+ */
+@export
+enum FrontendIsdbs3Rolloff : uint32_t {
+    UNDEFINED,
+    ROLLOFF_0_03,
+};
+
+/**
+ *  Modulaltion Type for ISDBS3.
+ */
+@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,
+};
+
+/**
+ *  Code Rate Type for ISDBS3.
+ */
+@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,
+};
+
+/**
+ *  Signal Setting for ISDBS3 Frontend.
+ */
+struct FrontendIsdbs3Settings {
+    /** Signal frequency in Hertz */
+    uint32_t frequency;
+    uint16_t streamId;
+    FrontendIsdbsStreamIdType streamIdType;
+    FrontendIsdbs3Modulation modulation;
+    FrontendIsdbs3Coderate coderate;
+    /** Symbols per second */
+    uint32_t symbolRate;
+    FrontendIsdbs3Rolloff rolloff;
+};
+
+/**
+ *  Capabilities for ISDBS3 Frontend.
+ */
+struct FrontendIsdbs3Capabilities {
+    bitfield<FrontendIsdbs3Modulation> modulationCap;
+    bitfield<FrontendIsdbs3Coderate> coderateCap;
+};
+
+/**
+ *   Mode for ISDBT.
+ */
+@export
+enum FrontendIsdbtMode : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Mode automatically */
+    AUTO = 1 << 0,
+    MODE_1 = 1 << 1,
+    MODE_2 = 1 << 2,
+    MODE_3 = 1 << 3,
+};
+
+/**
+ *   Bandwidth for ISDBT.
+ */
+@export
+enum FrontendIsdbtBandwidth : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Bandwidth automatically */
+    AUTO = 1 << 0,
+    BANDWIDTH_8MHZ = 1 << 1,
+    BANDWIDTH_7MHZ = 1 << 2,
+    BANDWIDTH_6MHZ = 1 << 3,
+};
+
+/**
+ *   Modulation for ISDBT.
+ */
+@export
+enum FrontendIsdbtModulation : uint32_t {
+    UNDEFINED = 0,
+    /** hardware is able to detect and set Modulation automatically */
+    AUTO = 1 << 0,
+    MOD_DQPSK = 1 << 1,
+    MOD_QPSK = 1 << 2,
+    MOD_16QAM = 1 << 3,
+    MOD_64QAM = 1 << 4,
+};
+
+/** Code Rate for ISDBT. */
+typedef FrontendDvbtCoderate FrontendIsdbtCoderate;
+
+/** Guard Interval for ISDBT. */
+typedef FrontendDvbtGuardInterval FrontendIsdbtGuardInterval;
+
+/**
+ *  Signal Setting for ISDBT Frontend.
+ */
+struct FrontendIsdbtSettings {
+    /** Signal frequency in Hertz */
+    uint32_t frequency;
+    FrontendIsdbtModulation modulation;
+    FrontendIsdbtBandwidth bandwidth;
+    FrontendIsdbtMode mode;
+    FrontendIsdbtCoderate coderate;
+    FrontendIsdbtGuardInterval guardInterval;
+    uint32_t serviceAreaId;
+};
+
+/**
+ *  Capabilities for ISDBT Frontend.
+ */
+struct FrontendIsdbtCapabilities {
+    bitfield<FrontendIsdbtMode> modeCap;
+    bitfield<FrontendIsdbtBandwidth> bandwidthCap;
+    bitfield<FrontendIsdbtModulation> constellationCap;
+    bitfield<FrontendIsdbtCoderate> coderateCap;
+    bitfield<FrontendIsdbtGuardInterval> guardIntervalCap;
+};
+
+/**
+ *   Signal Type for Analog Frontend.
+ */
+@export
+enum FrontendAnalogType : uint32_t {
+    UNDEFINED = 0,
+    PAL = 1 << 0,
+    SECAM = 1 << 1,
+    NTSC = 1 << 2,
+};
+
+/**
+ *   Standard Interchange Format (SIF) for Analog Frontend.
+ */
+@export
+enum FrontendAnalogSifStandard : uint32_t {
+    UNDEFINED = 0,
+    BG = 1 << 0,
+    BG_A2 = 1 << 1,
+    BG_NICAM  = 1 << 2,
+    I = 1 << 3,
+    DK = 1 << 4,
+    DK1 = 1 << 5,
+    DK2 = 1 << 6,
+    DK3 = 1 << 7,
+    DK_NICAM = 1 << 8,
+    L = 1 << 9,
+    M = 1 << 10,
+    M_BTSC = 1 << 11,
+    M_A2 = 1 << 12,
+    M_EIA_J = 1 << 13,
+    I_NICAM = 1 << 14,
+    L_NICAM = 1 << 15,
+};
+
+/**
+ *  Signal Setting for Analog Frontend.
+ */
+struct FrontendAnalogSettings {
+    /** Signal frequency in Hertz */
+    uint32_t frequency;
+    FrontendAnalogType type;
+    FrontendAnalogSifStandard sifStandard;
+};
+
+/**
+ *  Capabilities for Analog Frontend.
+ */
+struct FrontendAnalogCapabilities {
+    bitfield<FrontendAnalogType> typeCap;
+    bitfield<FrontendAnalogSifStandard> sifStandardCap;
+};
+
+/**
+ *  Signal Setting for Frontend.
  */
 safe_union FrontendSettings {
+    FrontendAnalogSettings analog;
     FrontendAtscSettings atsc;
+    FrontendAtsc3Settings atsc3;
+    FrontendDvbsSettings dvbs;
+    FrontendDvbcSettings dvbc;
     FrontendDvbtSettings dvbt;
+    FrontendIsdbsSettings isdbs;
+    FrontendIsdbs3Settings isdbs3;
+    FrontendIsdbtSettings isdbt;
+};
+
+/**
+ *  Scan type for Frontend.
+ */
+enum FrontendScanType : uint32_t {
+    SCAN_UNDEFINED = 0,
+    SCAN_AUTO = 1 << 0,
+    SCAN_BLIND = 1 << 1,
+};
+
+/**
+ *  Scan Message Type for Frontend.
+ */
+enum FrontendScanMessageType : uint32_t {
+    /** Scan locked the signal. */
+    LOCKED,
+    /** Scan stopped. */
+    END,
+    /** Scan progress report. */
+    PROGRESS_PERCENT,
+    /** Locked frequency report. */
+    FREQUENCY,
+    /** Locked symbol rate. */
+    SYMBOL_RATE,
+    /** Locked Plp Ids for DVBT2 frontend. */
+    PLP_IDS,
+    /** Locked group Ids for DVBT2 frontend. */
+    GROUP_IDS,
+    /** Locked the number of the Plps. */
+   INPUT_STREAM_IDS,
+    /** Locked signal stardard.  */
+    STANDARD,
+};
+
+/**
+ *  Scan Message for Frontend.
+ */
+safe_union FrontendScanMessage {
+    bool islocked;
+    bool isEnd;
+    /** scan progress percent (0..100) */
+    uint8_t progressPercent;
+    /** Signal frequency in Hertz */
+    uint32_t frequency;
+    /** Symbols per second */
+    uint32_t symbolRate;
+    vec<uint8_t> plpIds;
+    vec<uint8_t> groupIds;
+    vec<uint8_t> inputStreamIds;
+    safe_union standard {
+        FrontendDvbsStandard sStd;
+        FrontendDvbtStandard tStd;
+    } std;
 };
 
 /**
@@ -136,8 +954,174 @@
      * 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,
 };
 
+/**
+ * Frontend Status Type.
+ */
+@export
+enum FrontendStatusType : uint32_t {
+    /** Lock status for RF or Demod. */
+    LOCK,
+    /** Signal to Noise Ratio. */
+    SNR,
+    /** Bit Error Ratio. */
+    BER,
+    /** Packages Error Ratio. */
+    PER,
+    /** Bit Error Ratio befor 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. */
+    SIGGAL_STRENGTH,
+    /** Symbol Rate. */
+    SYMBOL_RATE,
+    /** Forward Error Correction Type. */
+    FEC,
+    /** Modulation Type. */
+    MODULATION,
+    /** Spectral Inversion Type. */
+    SPECTRAL,
+    /** LNB Voltage. */
+    LNB_VOLTAGE,
+    /** Physical Layer Pipe ID. */
+    PLP_ID,
+    /** Status for Emergency Warning Broadcasting System. */
+    EWBS,
+};
+
+/**
+ * Modulation Type for Frontend's status.
+ */
+safe_union FrontendModulationStatus {
+    FrontendDvbsModulation dvbs;
+    FrontendAtsc3Modulation atsc3;
+};
+
+/**
+ *  The status for Frontend.
+ */
+safe_union FrontendStatus {
+    bool isLocked;
+    /** SNR value measured by 0.001 dB. */
+    int32_t snr;
+    /** The number of error bit per 1 billion bits. */
+    uint32_t ber;
+    /** The number of error package per 1 billion packages. */
+    uint32_t per;
+    /** The number of error bit per 1 billion bits before FEC. */
+    uint32_t preBer;
+    /** Signal Quality in percent. */
+    uint32_t signalQuality;
+    /** Signal Strength measured by 0.001 dBm. */
+    int32_t signalStrength;
+    /** Symbols per second */
+    uint32_t symbolRate;
+    FrontendInnerFec innerFec;
+    FrontendModulationStatus modulation;
+    FrontendDvbcSpectralInversion inversion;
+    FrontendLnbVoltage lnbVoltage;
+    uint8_t plpId;
+    bool isEWBS;
+};
+
+/**
+ *  Information for the Frontend.
+ */
+struct FrontendInfo {
+    FrontendType type;
+    /** Frequency in Hertz */
+    uint32_t minFrequency;
+    /** Frequency in Hertz */
+    uint32_t maxFrequency;
+    /** Minimum symbols per second */
+    uint32_t minSymbolRate;
+    /** Maximum symbols per second */
+    uint32_t maxSymbolRate;
+    /** 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 */
+    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;
+};
+
+/*
+ * Low-Noise Block downconverter (LNB) ID is used to associate with a hardware
+ * LNB module.
+ */
+typedef uint32_t LnbId;
+
+/**
+ *  Power Voltage Type for LNB.
+ */
+@export
+enum FrontendLnbVoltage : uint32_t {
+    NONE,
+    VOLTAGE_5V,
+    VOLTAGE_11V,
+    VOLTAGE_12V,
+    VOLTAGE_13V,
+    VOLTAGE_14V,
+    VOLTAGE_15V,
+    VOLTAGE_18V,
+    VOLTAGE_19V,
+};
+
+/**
+ *  Tone Type for LNB.
+ */
+@export
+enum FrontendLnbTone : int32_t {
+    NONE,
+    CONTINUOUS,
+};
+
+/**
+ *  The Position of LNB.
+ */
+@export
+enum FrontendLnbPosition : int32_t {
+    UNDEFINED,
+    POSITION_A,
+    POSITION_B,
+};
+
+
 /* Demux ID is used to associate with a hardware demux resource. */
 typedef uint32_t DemuxId;
 
@@ -248,7 +1232,7 @@
     /* Version number for Section Filter */
     uint16_t version;
     /* true if the filter checks CRC and discards data with wrong CRC */
-    bool checkCrc;
+    bool isCheckCrc;
     /* true if the filter repeats the data with the same version */
     bool isRepeat;
     /* true if the filter output raw data */
@@ -265,7 +1249,7 @@
     DemuxTpid tpid;
     DemuxStreamId streamId;
     /* true if the filter output raw data */
-    bool bIsRaw;
+    bool isRaw;
 };
 
 /**
@@ -283,7 +1267,7 @@
     /**
      * true if the filter output goes to decoder directly in pass through mode.
      */
-    bool bPassthrough;
+    bool isPassthrough;
 };
 
 /**
@@ -294,7 +1278,7 @@
     /**
      * true if the filter output goes to decoder directly in pass through mode.
      */
-    bool bPassthrough;
+    bool isPassthrough;
 };
 
 /**
@@ -479,3 +1463,99 @@
  *  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. */
+    TS,
+    /* Data is Packetized Elementary Stream. */
+    PES,
+    /* Data is Elementary Stream. */
+    ES,
+};
+
+/**
+ * A status of the demux's output.
+ */
+typedef DemuxFilterStatus DemuxOutputStatus;
+
+/**
+ *  The Settings for the demux's output.
+ */
+struct DemuxOutputSettings {
+    /**
+     * Register for interested status events so that the HAL can send these
+     * status events back to client.
+     */
+    bitfield<DemuxOutputStatus> statusMask;
+    /**
+     * Unconsumed data size in bytes in the output. The HAL uses it to trigger
+     * DemuxOutputStatus::LOW_WATER.
+     */
+    uint32_t lowThreshold;
+    /**
+     * Unconsumed data size in bytes in the output. The HAL uses it to trigger
+     * DemuxOutputStatus::High_WATER.
+     */
+    uint32_t highThreshold;
+    /**
+     * The data format in the output.
+     */
+    DemuxDataFormat dataFormat;
+    /**
+     * The packet size in bytes in the output.
+     */
+    uint8_t packetSize;
+};
+
+/**
+ * A status of the demux's input.
+ */
+@export
+enum DemuxInputStatus : uint32_t {
+    /**
+     * The space of the demux's input is empty.
+     */
+    SPACE_EMPTY        = 1 << 0,
+    /**
+     * The spece of the demux's input is almost empty.
+     */
+    SPACE_ALMOST_EMPTY = 1 << 1,
+    /**
+     * The space of the demux's input is almost full.
+     */
+    SPACE_ALMOST_FULL  = 1 << 2,
+    /**
+     * The space of the demux's input is full.
+     */
+    SPACE_FULL         = 1 << 3,
+};
+
+struct DemuxInputSettings {
+    /**
+     * Register for interested status events so that the HAL can send these
+     * status events back to client.
+     */
+    bitfield<DemuxInputStatus> statusMask;
+    /**
+     * Unused space size in bytes in the input. The HAL uses it to trigger
+     * DemuxInputStatus::SPACE_ALMOST_EMPTY.
+     */
+    uint32_t lowThreshold;
+    /**
+     * Unused space size in bytes in the input. The HAL uses it to trigger
+     * DemuxInputStatus::SPACE_ALMOST_FULL.
+     */
+    uint32_t highThreshold;
+    /**
+     * The data format in the input.
+     */
+    DemuxDataFormat dataFormat;
+    /**
+     * The packet size in bytes in the input.
+     */
+    uint8_t packetSize;
+};
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index 66adb2a..7256cc4 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -34,6 +34,9 @@
 #include <hidlmemory/FrameworkUtils.h>
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
+#include <fstream>
+#include <iostream>
+#include <map>
 
 #define WAIT_TIMEOUT 3000000000
 
@@ -53,11 +56,16 @@
 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::DemuxFilterEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
+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::FrontendAtscModulation;
 using android::hardware::tv::tuner::V1_0::FrontendAtscSettings;
@@ -65,6 +73,8 @@
 using android::hardware::tv::tuner::V1_0::FrontendEventType;
 using android::hardware::tv::tuner::V1_0::FrontendId;
 using android::hardware::tv::tuner::V1_0::FrontendInnerFec;
+using android::hardware::tv::tuner::V1_0::FrontendScanMessage;
+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;
@@ -77,9 +87,9 @@
 namespace {
 
 using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
-using FilterMQDesc = MQDescriptorSync<uint8_t>;
+using MQDesc = MQDescriptorSync<uint8_t>;
 
-const std::vector<uint8_t> goldenDataInputBuffer{
+const std::vector<uint8_t> goldenDataOutputBuffer{
         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,
@@ -119,10 +129,21 @@
 };
 
 const uint16_t FMQ_SIZE_4K = 0x1000;
+const uint32_t FMQ_SIZE_1M = 0x100000;
 // Equal to SECTION_WRITE_COUNT on the HAL impl side
 // The HAL impl will repeatedly write to the FMQ the count times
 const uint16_t SECTION_READ_COUNT = 10;
 
+struct FilterConf {
+    DemuxFilterType type;
+    DemuxFilterSettings setting;
+};
+
+struct InputConf {
+    string inputDataFile;
+    DemuxInputSettings setting;
+};
+
 class FrontendCallback : public IFrontendCallback {
   public:
     virtual Return<void> onEvent(FrontendEventType frontendEventType) override {
@@ -141,12 +162,21 @@
         return Void();
     }
 
+    virtual Return<void> onScanMessage(FrontendScanMessageType /* type */,
+                                       const FrontendScanMessage& /* message */) override {
+        android::Mutex::Autolock autoLock(mMsgLock);
+        mScanMessageReceived = true;
+        mMsgCondition.signal();
+        return Void();
+    };
+
     void testOnEvent(sp<IFrontend>& frontend, FrontendSettings settings);
     void testOnDiseqcMessage(sp<IFrontend>& frontend, FrontendSettings settings);
 
   private:
     bool mEventReceived = false;
     bool mDiseqcMessageReceived = false;
+    bool mScanMessageReceived = false;
     FrontendEventType mEventType;
     hidl_vec<uint8_t> mEventMessage;
     android::Mutex mMsgLock;
@@ -184,9 +214,11 @@
 class DemuxCallback : public IDemuxCallback {
   public:
     virtual Return<void> onFilterEvent(const DemuxFilterEvent& filterEvent) override {
+        ALOGW("[VTS] FILTER EVENT %d", filterEvent.filterId);
         android::Mutex::Autolock autoLock(mMsgLock);
         mFilterEventReceived = true;
-        mFilterEvent = filterEvent;
+        mFilterIdToEvent[filterEvent.filterId] = filterEvent;
+        startFilterEventThread(filterEvent);
         mMsgCondition.signal();
         return Void();
     }
@@ -196,26 +228,75 @@
         return Void();
     }
 
+    virtual Return<void> onOutputStatus(DemuxOutputStatus /*status*/) override { return Void(); }
+
+    virtual Return<void> onInputStatus(DemuxInputStatus status) override {
+        // android::Mutex::Autolock autoLock(mMsgLock);
+        switch (status) {
+            case DemuxInputStatus::SPACE_EMPTY:
+            case DemuxInputStatus::SPACE_ALMOST_EMPTY:
+                mKeepWritingInputFMQ = true;
+                break;
+            case DemuxInputStatus::SPACE_ALMOST_FULL:
+            case DemuxInputStatus::SPACE_FULL:
+                mKeepWritingInputFMQ = false;
+                break;
+        }
+        return Void();
+    }
+
     void testOnFilterEvent(uint32_t filterId);
-    void testOnSectionFilterEvent(sp<IDemux>& demux, uint32_t filterId,
-                                  FilterMQDesc& filterMQDescriptor);
-    void testOnPesFilterEvent(sp<IDemux>& demux, uint32_t filterId,
-                              FilterMQDesc& filterMQDescriptor);
-    void readAndCompareSectionEventData();
-    void readAndComparePesEventData();
+    void testOnSectionFilterEvent(sp<IDemux>& demux, uint32_t filterId, MQDesc& filterMQDescriptor,
+                                  MQDesc& inputMQDescriptor);
+    void testFilterDataOutput();
+    // Legacy
+    bool readAndCompareSectionEventData(uint32_t filterId);
+
+    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, MQDesc& inputMQDescriptor);
+    void filterThreadLoop(DemuxFilterEvent& event);
+
+    void updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor);
+    void updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile);
 
   private:
-    bool mFilterEventReceived = false;
-    std::vector<uint8_t> mDataOutputBuffer;
-    std::unique_ptr<FilterMQ> mFilterMQ;
+    struct InputThreadArgs {
+        DemuxCallback* user;
+        InputConf inputConf;
+        bool* keepWritingInputFMQ;
+        MQDesc& inputMQDesc;
+    };
+    struct FilterThreadArgs {
+        DemuxCallback* user;
+        DemuxFilterEvent& event;
+    };
     uint16_t mDataLength = 0;
-    DemuxFilterEvent mFilterEvent;
+    std::vector<uint8_t> mDataOutputBuffer;
+
+    bool mFilterEventReceived;
+    std::map<uint32_t, string> mFilterIdToGoldenOutput;
+    std::map<uint32_t, DemuxFilterEvent> mFilterIdToEvent;
+
+    std::map<uint32_t, std::unique_ptr<FilterMQ>> mFilterIdToMQ;
+    std::unique_ptr<FilterMQ> mInputMQ;
+    std::map<uint32_t, EventFlag*> mFilterIdToMQEventFlag;
+    EventFlag* mInputMQEventFlag;
+
     android::Mutex mMsgLock;
-    android::Mutex mReadLock;
+    android::Mutex mFilterOutputLock;
     android::Condition mMsgCondition;
-    EventFlag* mFilterMQEventFlag;
+    android::Condition mFilterOutputCondition;
+
+    bool mKeepWritingInputFMQ;
+    bool mInputThreadRunning;
+    pthread_t mInputThread;
+    pthread_t mFilterThread;
 };
 
+// Legacy
 void DemuxCallback::testOnFilterEvent(uint32_t filterId) {
     android::Mutex::Autolock autoLock(mMsgLock);
     while (!mFilterEventReceived) {
@@ -227,86 +308,190 @@
     // Reset the filter event recieved flag
     mFilterEventReceived = false;
     // Check if filter id match
-    EXPECT_TRUE(filterId == mFilterEvent.filterId) << "filter id match";
+    EXPECT_TRUE(filterId == mFilterIdToEvent[filterId].filterId) << "filter id match";
 }
 
+void DemuxCallback::startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor) {
+    struct InputThreadArgs* threadArgs =
+            (struct InputThreadArgs*)malloc(sizeof(struct InputThreadArgs));
+    threadArgs->user = this;
+    threadArgs->inputConf = inputConf;
+    threadArgs->keepWritingInputFMQ = &mKeepWritingInputFMQ;
+    threadArgs->inputMQDesc = inputMQDescriptor;
+
+    pthread_create(&mInputThread, NULL, __threadLoopInput, (void*)threadArgs);
+    pthread_setname_np(mInputThread, "test_playback_input_loop");
+}
+
+void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) {
+    struct FilterThreadArgs* threadArgs =
+            (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
+    threadArgs->user = this;
+    threadArgs->event = event;
+
+    pthread_create(&mFilterThread, NULL, __threadLoopFilter, (void*)threadArgs);
+    pthread_setname_np(mFilterThread, "test_playback_input_loop");
+}
+
+void DemuxCallback::testFilterDataOutput() {
+    android::Mutex::Autolock autoLock(mFilterOutputLock);
+    while (!mFilterIdToMQ.empty()) {
+        if (-ETIMEDOUT == mFilterOutputCondition.waitRelative(mFilterOutputLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "filter output does not match golden output within timeout";
+            return;
+        }
+    }
+}
+
+// Legacy
 void DemuxCallback::testOnSectionFilterEvent(sp<IDemux>& demux, uint32_t filterId,
-                                             FilterMQDesc& filterMQDescriptor) {
+                                             MQDesc& filterMQDescriptor,
+                                             MQDesc& inputMQDescriptor) {
     Result status;
     // Create MQ to read the output into the local buffer
-    mFilterMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mFilterMQ);
+    mFilterIdToMQ[filterId] =
+            std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mFilterIdToMQ[filterId]);
+    // Get the MQ to write the input to the HAL
+    mInputMQ = std::make_unique<FilterMQ>(inputMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mInputMQ);
     // Create the EventFlag that is used to signal the HAL impl that data have been
     // read the Filter FMQ
-    EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) ==
+    EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(),
+                                           &mFilterIdToMQEventFlag[filterId]) == android::OK);
+    // Create the EventFlag that is used to signal the HAL impl that data have been
+    // written into the Input FMQ
+    EXPECT_TRUE(EventFlag::createEventFlag(mInputMQ->getEventFlagWord(), &mInputMQEventFlag) ==
                 android::OK);
     // Start filter
     status = demux->startFilter(filterId);
+    status = demux->startInput();
+
     EXPECT_EQ(status, Result::SUCCESS);
     // Test start filter and receive callback event
     for (int i = 0; i < SECTION_READ_COUNT; i++) {
+        // Write input FMQ and notify the Tuner Implementation
+        EXPECT_TRUE(mInputMQ->write(goldenDataOutputBuffer.data(), goldenDataOutputBuffer.size()));
+        mInputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
         testOnFilterEvent(filterId);
         // checksum of mDataOutputBuffer and Input golden input
-        readAndCompareSectionEventData();
+        if (readAndCompareSectionEventData(filterId) && i < SECTION_READ_COUNT - 1) {
+            mFilterIdToMQEventFlag[filterId]->wake(
+                    static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+        }
     }
 }
 
-void DemuxCallback::testOnPesFilterEvent(sp<IDemux>& demux, uint32_t filterId,
-                                         FilterMQDesc& filterMQDescriptor) {
-    Result status;
-    // Create MQ to read the output into the local buffer
-    mFilterMQ = std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
-    EXPECT_TRUE(mFilterMQ);
-    // Create the EventFlag that is used to signal the HAL impl that data have been
-    // read the Filter FMQ
-    EXPECT_TRUE(EventFlag::createEventFlag(mFilterMQ->getEventFlagWord(), &mFilterMQEventFlag) ==
-                android::OK);
-    // Start filter
-    status = demux->startFilter(filterId);
-    EXPECT_EQ(status, Result::SUCCESS);
-    // Test start filter and receive callback event
-    testOnFilterEvent(filterId);
-    // checksum of mDataOutputBuffer and Input golden input
-    readAndComparePesEventData();
-}
-
-void DemuxCallback::readAndCompareSectionEventData() {
+// Legacy
+bool DemuxCallback::readAndCompareSectionEventData(uint32_t filterId) {
     bool result = false;
-    for (int i = 0; i < mFilterEvent.events.size(); i++) {
-        DemuxFilterSectionEvent event = mFilterEvent.events[i].section();
+    DemuxFilterEvent filterEvent = mFilterIdToEvent[filterId];
+    for (int i = 0; i < filterEvent.events.size(); i++) {
+        DemuxFilterSectionEvent event = filterEvent.events[i].section();
         mDataLength = event.dataLength;
-        EXPECT_TRUE(mDataLength == goldenDataInputBuffer.size()) << "buffer size does not match";
+        EXPECT_TRUE(mDataLength == goldenDataOutputBuffer.size()) << "buffer size does not match";
 
         mDataOutputBuffer.resize(mDataLength);
-        result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength);
+        result = mFilterIdToMQ[filterId]->read(mDataOutputBuffer.data(), mDataLength);
         EXPECT_TRUE(result) << "can't read from Filter MQ";
 
         for (int i = 0; i < mDataLength; i++) {
-            EXPECT_TRUE(goldenDataInputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
+            EXPECT_TRUE(goldenDataOutputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
         }
     }
-    if (result) {
-        mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
-    }
+    return result;
 }
 
-void DemuxCallback::readAndComparePesEventData() {
-    // TODO handle multiple events in one filter callback event
-    DemuxFilterPesEvent event = mFilterEvent.events[0].pes();
-    mDataLength = event.dataLength;
-    EXPECT_TRUE(mDataLength == goldenDataInputBuffer.size()) << "buffer size does not match";
+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);
+}
 
-    mDataOutputBuffer.resize(mDataLength);
-    bool result = mFilterMQ->read(mDataOutputBuffer.data(), mDataLength);
-    EXPECT_TRUE(result) << "can't read from Filter MQ";
+void DemuxCallback::updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile) {
+    mFilterIdToGoldenOutput[filterId] = goldenOutputFile;
+}
 
-    if (result) {
-        mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+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,
+                          ((struct InputThreadArgs*)threadArgs)->inputMQDesc);
+    return 0;
+}
+
+void DemuxCallback::inputThreadLoop(InputConf inputConf, bool* keepWritingInputFMQ,
+                                    MQDesc& inputMQDescriptor) {
+    mInputThreadRunning = true;
+
+    std::unique_ptr inputMQ =
+            std::make_unique<FilterMQ>(inputMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(inputMQ);
+
+    // 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(inputMQ->getEventFlagWord(), &inputMQEventFlag) ==
+                android::OK);
+
+    // open the stream and get its length
+    std::ifstream inputData(inputConf.inputDataFile /*"ts/test1.ts"*/, std::ifstream::binary);
+    int writeSize = inputConf.setting.packetSize * 6;
+    char* buffer = new char[writeSize];
+    if (!inputData) {
+        // log
+        mInputThreadRunning = false;
     }
 
-    for (int i = 0; i < mDataLength; i++) {
-        EXPECT_TRUE(goldenDataInputBuffer[i] == mDataOutputBuffer[i]) << "data does not match";
+    while (mInputThreadRunning) {
+        // move the stream pointer for packet size * 2k? every read until end
+        while (*keepWritingInputFMQ) {
+            inputData.read(buffer, writeSize);
+            if (!inputData) {
+                int leftSize = inputData.gcount();
+                inputData.clear();
+                inputData.read(buffer, leftSize);
+                // Write the left over of the input data and quit the thread
+                if (leftSize > 0) {
+                    EXPECT_TRUE(inputMQ->write((unsigned char*)&buffer[0],
+                                               leftSize / inputConf.setting.packetSize));
+                    inputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+                }
+                mInputThreadRunning = false;
+                break;
+            }
+            // Write input FMQ and notify the Tuner Implementation
+            EXPECT_TRUE(inputMQ->write((unsigned char*)&buffer[0], 6));
+            inputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
+            inputData.seekg(writeSize, inputData.cur);
+        }
     }
+
+    delete[] buffer;
+    inputData.close();
+}
+
+void* DemuxCallback::__threadLoopFilter(void* threadArgs) {
+    DemuxCallback* const self =
+            static_cast<DemuxCallback*>(((struct FilterThreadArgs*)threadArgs)->user);
+    self->filterThreadLoop(((struct FilterThreadArgs*)threadArgs)->event);
+    return 0;
+}
+
+void DemuxCallback::filterThreadLoop(DemuxFilterEvent& /*event*/) {
+    android::Mutex::Autolock autoLock(mFilterOutputLock);
+    // Read from MQ[event.filterId] per event and filter type
+
+    // Assemble to filterOutput[filterId]
+
+    // check if filterOutput[filterId] matches goldenOutput[filterId]
+
+    // If match, remove filterId entry from MQ map
+
+    // end thread
 }
 
 // Test environment for Tuner HIDL HAL.
@@ -341,24 +526,36 @@
     sp<IDescrambler> mDescrambler;
     sp<IDemux> mDemux;
     sp<DemuxCallback> mDemuxCallback;
-    FilterMQDesc mFilterMQDescriptor;
+    MQDesc mFilterMQDescriptor;
+    MQDesc mInputMQDescriptor;
+
     uint32_t mDemuxId;
     uint32_t mFilterId;
 
+    pthread_t mInputThread;
+    bool mInputThreadRunning;
+
     ::testing::AssertionResult createFrontend(int32_t frontendId);
     ::testing::AssertionResult tuneFrontend(int32_t frontendId);
     ::testing::AssertionResult stopTuneFrontend(int32_t frontendId);
     ::testing::AssertionResult closeFrontend(int32_t frontendId);
     ::testing::AssertionResult createDemux();
     ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId);
-    ::testing::AssertionResult addSectionFilterToDemux();
-    ::testing::AssertionResult addPesFilterToDemux();
-    ::testing::AssertionResult getFilterMQDescriptor(sp<IDemux>& demux, const uint32_t filterId);
-    ::testing::AssertionResult readSectionFilterDataOutput();
-    ::testing::AssertionResult readPesFilterDataOutput();
+    ::testing::AssertionResult getInputMQDescriptor();
+    ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting);
+    ::testing::AssertionResult addFilterToDemux(DemuxFilterType type, DemuxFilterSettings setting);
+    ::testing::AssertionResult getFilterMQDescriptor(const uint32_t filterId);
     ::testing::AssertionResult closeDemux();
     ::testing::AssertionResult createDescrambler();
     ::testing::AssertionResult closeDescrambler();
+
+    ::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
+                                                    InputConf inputConf,
+                                                    vector<string> goldenOutputFiles);
+
+    // Legacy
+    ::testing::AssertionResult addSectionFilterToDemux();
+    ::testing::AssertionResult readSectionFilterDataOutput();
 };
 
 ::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) {
@@ -394,8 +591,6 @@
 
     FrontendDvbtSettings frontendDvbtSettings{
             .frequency = 0,
-            .modulation = FrontendAtscModulation::UNDEFINED,
-            .fec = FrontendInnerFec::FEC_UNDEFINED,
     };
     frontendSettings.dvbt(frontendDvbtSettings);
     mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
@@ -405,7 +600,7 @@
 
 ::testing::AssertionResult TunerHidlTest::stopTuneFrontend(int32_t frontendId) {
     Result status;
-    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
 
@@ -415,11 +610,12 @@
 
 ::testing::AssertionResult TunerHidlTest::closeFrontend(int32_t frontendId) {
     Result status;
-    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
 
     status = mFrontend->close();
+    mFrontend = nullptr;
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
@@ -437,11 +633,11 @@
 ::testing::AssertionResult TunerHidlTest::createDemuxWithFrontend(int32_t frontendId) {
     Result status;
 
-    if (createDemux() == ::testing::AssertionFailure()) {
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
 
-    if (createFrontend(frontendId) == ::testing::AssertionFailure()) {
+    if (!mFrontend && createFrontend(frontendId) == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
 
@@ -450,111 +646,14 @@
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
-::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() {
-    Result status;
-
-    if (createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Create demux callback
-    mDemuxCallback = new DemuxCallback();
-
-    // Add section filter to the local demux
-    mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback,
-                      [&](Result result, uint32_t filterId) {
-                          mFilterId = filterId;
-                          status = result;
-                      });
-
-    // Add another section filter to the local demux
-    mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback,
-                      [&](Result result, uint32_t filterId) {
-                          mFilterId = filterId;
-                          status = result;
-                      });
-
-    // TODO Test configure the filter
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::addPesFilterToDemux() {
-    Result status;
-
-    if (createDemux() == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Create demux callback
-    mDemuxCallback = new DemuxCallback();
-
-    // Add PES filter to the local demux
-    mDemux->addFilter(DemuxFilterType::PES, FMQ_SIZE_4K, mDemuxCallback,
-                      [&](Result result, uint32_t filterId) {
-                          mFilterId = filterId;
-                          status = result;
-                      });
-
-    // Add another PES filter to the local demux
-    mDemux->addFilter(DemuxFilterType::PES, FMQ_SIZE_4K, mDemuxCallback,
-                      [&](Result result, uint32_t filterId) {
-                          mFilterId = filterId;
-                          status = result;
-                      });
-
-    // TODO Test configure the filter
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(sp<IDemux>& demux,
-                                                                const uint32_t filterId) {
-    Result status;
-
-    if (!demux) {
-        return ::testing::AssertionFailure();
-    }
-
-    mDemux->getFilterQueueDesc(filterId, [&](Result result, const FilterMQDesc& filterMQDesc) {
-        mFilterMQDescriptor = filterMQDesc;
-        status = result;
-    });
-
-    return ::testing::AssertionResult(status == Result::SUCCESS);
-}
-
-::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() {
-    if (addSectionFilterToDemux() == ::testing::AssertionFailure() ||
-        getFilterMQDescriptor(mDemux, mFilterId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Test start filter and read the output data
-    mDemuxCallback->testOnSectionFilterEvent(mDemux, mFilterId, mFilterMQDescriptor);
-
-    return ::testing::AssertionResult(true);
-}
-
-::testing::AssertionResult TunerHidlTest::readPesFilterDataOutput() {
-    if (addPesFilterToDemux() == ::testing::AssertionFailure() ||
-        getFilterMQDescriptor(mDemux, mFilterId) == ::testing::AssertionFailure()) {
-        return ::testing::AssertionFailure();
-    }
-
-    // Test start filter and read the output data
-    mDemuxCallback->testOnPesFilterEvent(mDemux, mFilterId, mFilterMQDescriptor);
-
-    return ::testing::AssertionResult(true);
-}
-
 ::testing::AssertionResult TunerHidlTest::closeDemux() {
     Result status;
-    if (createDemux() == ::testing::AssertionFailure()) {
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
 
     status = mDemux->close();
+    mDemux = nullptr;
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
@@ -569,7 +668,7 @@
         return ::testing::AssertionFailure();
     }
 
-    if (createDemux() == ::testing::AssertionFailure()) {
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
 
@@ -585,14 +684,190 @@
 
 ::testing::AssertionResult TunerHidlTest::closeDescrambler() {
     Result status;
-    if (createDescrambler() == ::testing::AssertionFailure()) {
+    if (!mDescrambler && createDescrambler() == ::testing::AssertionFailure()) {
         return ::testing::AssertionFailure();
     }
 
     status = mDescrambler->close();
+    mDescrambler = nullptr;
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
+::testing::AssertionResult TunerHidlTest::addInputToDemux(DemuxInputSettings setting) {
+    Result status;
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Create demux callback
+    if (!mDemuxCallback) {
+        mDemuxCallback = new DemuxCallback();
+    }
+
+    // Add section filter to the local demux
+    status = mDemux->addInput(FMQ_SIZE_1M, mDemuxCallback);
+
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    status = mDemux->configureInput(setting);
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::getInputMQDescriptor() {
+    Result status;
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    mDemux->getInputQueueDesc([&](Result result, const MQDesc& inputMQDesc) {
+        mInputMQDescriptor = inputMQDesc;
+        status = result;
+    });
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+// Legacy
+::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() {
+    Result status;
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Create demux callback
+    if (!mDemuxCallback) {
+        mDemuxCallback = new DemuxCallback();
+    }
+
+    // Add section filter to the local demux
+    mDemux->addFilter(DemuxFilterType::SECTION, FMQ_SIZE_4K, mDemuxCallback,
+                      [&](Result result, uint32_t filterId) {
+                          mFilterId = filterId;
+                          status = result;
+                      });
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::addFilterToDemux(DemuxFilterType type,
+                                                           DemuxFilterSettings setting) {
+    Result status;
+
+    if (!mDemux && createDemux() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Create demux callback
+    if (!mDemuxCallback) {
+        mDemuxCallback = new DemuxCallback();
+    }
+
+    // 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
+        mFilterId = filterId;
+        status = result;
+    });
+
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Configure the filter
+    status = mDemux->configureFilter(mFilterId, setting);
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+::testing::AssertionResult TunerHidlTest::getFilterMQDescriptor(const uint32_t filterId) {
+    Result status;
+
+    if (!mDemux) {
+        return ::testing::AssertionFailure();
+    }
+
+    mDemux->getFilterQueueDesc(filterId, [&](Result result, const MQDesc& filterMQDesc) {
+        mFilterMQDescriptor = filterMQDesc;
+        status = result;
+    });
+
+    return ::testing::AssertionResult(status == Result::SUCCESS);
+}
+
+// Legacy
+::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() {
+    // Filter Configuration Module
+    DemuxInputSettings setting{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x100000,
+            .dataFormat = DemuxDataFormat::TS,
+            .packetSize = 188,
+    };
+    if (addSectionFilterToDemux() == ::testing::AssertionFailure() ||
+        getFilterMQDescriptor(mFilterId) == ::testing::AssertionFailure() ||
+        addInputToDemux(setting) == ::testing::AssertionFailure() ||
+        getInputMQDescriptor() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Data Verify Module
+    // Test start filter and read the output data
+    mDemuxCallback->testOnSectionFilterEvent(mDemux, mFilterId, mFilterMQDescriptor,
+                                             mInputMQDescriptor);
+
+    // Clean Up Module
+    return closeDemux();  //::testing::AssertionSuccess();
+}
+
+::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(vector<FilterConf> filterConf,
+                                                               InputConf inputConf,
+                                                               vector<string> goldenOutputFiles) {
+    Result status;
+    // Filter Configuration Module
+    for (int i = 0; i < filterConf.size(); i++) {
+        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()) {
+            return ::testing::AssertionFailure();
+        }
+        mDemuxCallback->updateFilterMQ(mFilterId, mFilterMQDescriptor);
+        mDemuxCallback->updateGoldenOutputMap(mFilterId, goldenOutputFiles[i]);
+        status = mDemux->startFilter(mFilterId);
+        if (status != Result::SUCCESS) {
+            return ::testing::AssertionFailure();
+        }
+    }
+
+    // Playback Input Module
+    DemuxInputSettings inputSetting = inputConf.setting;
+    if (addInputToDemux(inputSetting) == ::testing::AssertionFailure() ||
+        getInputMQDescriptor() == ::testing::AssertionFailure()) {
+        return ::testing::AssertionFailure();
+    }
+    mDemuxCallback->startPlaybackInputThread(inputConf, mInputMQDescriptor);
+    status = mDemux->startInput();
+    if (status != Result::SUCCESS) {
+        return ::testing::AssertionFailure();
+    }
+
+    // Data Verify Module
+    mDemuxCallback->testFilterDataOutput();
+
+    // Clean Up Module
+    return closeDemux();
+}
+
+/*
+ * API STATUS TESTS
+ */
 TEST_F(TunerHidlTest, CreateFrontend) {
     Result status;
     hidl_vec<FrontendId> feIds;
@@ -673,12 +948,6 @@
     }
 }
 
-TEST_F(TunerHidlTest, CreateDemux) {
-    description("Create Demux");
-
-    ASSERT_TRUE(createDemux());
-}
-
 TEST_F(TunerHidlTest, CreateDemuxWithFrontend) {
     Result status;
     hidl_vec<FrontendId> feIds;
@@ -699,50 +968,34 @@
     }
 }
 
-TEST_F(TunerHidlTest, AddSectionFilterToDemux) {
-    description("Add a section filter to a created demux");
-    ASSERT_TRUE(addSectionFilterToDemux());
-}
-
-TEST_F(TunerHidlTest, AddPesFilterToDemux) {
-    description("Add a pes filter to a created demux");
-    ASSERT_TRUE(addPesFilterToDemux());
-}
-
-TEST_F(TunerHidlTest, GetFilterMQDescriptor) {
-    description("Get MQ Descriptor from a created filter");
-    ASSERT_TRUE(addSectionFilterToDemux());
-    ASSERT_TRUE(getFilterMQDescriptor(mDemux, mFilterId));
-}
-
-TEST_F(TunerHidlTest, ReadSectionFilterOutput) {
-    description("Read data output from FMQ of a Section Filter");
-    ASSERT_TRUE(readSectionFilterDataOutput());
-}
-
-TEST_F(TunerHidlTest, ReadPesFilterOutput) {
-    description("Read data output from FMQ of a PES Filter");
-    ASSERT_TRUE(readPesFilterDataOutput());
+TEST_F(TunerHidlTest, CreateDemux) {
+    description("Create Demux");
+    ASSERT_TRUE(createDemux());
 }
 
 TEST_F(TunerHidlTest, CloseDemux) {
     description("Close Demux");
-
     ASSERT_TRUE(closeDemux());
 }
 
 TEST_F(TunerHidlTest, CreateDescrambler) {
     description("Create Descrambler");
-
     ASSERT_TRUE(createDescrambler());
 }
 
 TEST_F(TunerHidlTest, CloseDescrambler) {
     description("Close Descrambler");
-
     ASSERT_TRUE(closeDescrambler());
 }
 
+/*
+ * DATA FLOW TESTS
+ */
+TEST_F(TunerHidlTest, ReadSectionFilterOutput) {
+    description("Read data output from FMQ of a Section Filter");
+    ASSERT_TRUE(readSectionFilterDataOutput());
+}
+
 }  // namespace
 
 int main(int argc, char** argv) {