Merge "wifi: add pmk cache interface"
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index 4a42d79..c8e11e3 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -85,6 +85,28 @@
     0x0666 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
 
 /**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * For example: Mocking hard button press triggering a HVAC fan speed change.
+ * Android set kSetPropertyFromVehcileForTest with an array of integer {HVAC_FAN_SPEED, value of
+ * fan speed} and a long value indicates the timestamp of the events .
+ * It only works with integer type properties.
+ */
+const int32_t kSetIntPropertyFromVehcileForTest =
+        0x1112 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * It only works with float type properties.
+ */
+const int32_t kSetFloatPropertyFromVehcileForTest =
+        0x1113 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+/**
+ * This property is used for test purpose to set properties' value from vehicle.
+ * It only works with boolean type properties.
+ */
+const int32_t kSetBooleanPropertyFromVehcileForTest =
+        0x1114 | VehiclePropertyGroup::VENDOR | VehicleArea::GLOBAL | VehiclePropertyType::MIXED;
+
+/**
  * This property is used for test purpose. End to end tests use this property to test set and get
  * method for MIXED type properties.
  */
@@ -636,6 +658,37 @@
                                 .prop = kGenerateFakeDataControllingProperty,
                                 .access = VehiclePropertyAccess::WRITE,
                                 .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {1, 0, 0, 2, 0, 0, 0, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetIntPropertyFromVehcileForTest,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 0, 0, 2, 1, 0, 0, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetFloatPropertyFromVehcileForTest,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 0, 1, 0, 1, 0, 1, 0, 0},
+                        },
+        },
+
+        {
+                .config =
+                        {
+                                .prop = kSetBooleanPropertyFromVehcileForTest,
+                                .access = VehiclePropertyAccess::WRITE,
+                                .changeMode = VehiclePropertyChangeMode::ON_CHANGE,
+                                .configArray = {0, 1, 1, 0, 1, 0, 0, 0, 0},
                         },
         },
 
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
index b4f1f07..9d249be 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedVehicleHal.cpp
@@ -131,6 +131,36 @@
 StatusCode EmulatedVehicleHal::set(const VehiclePropValue& propValue) {
     static constexpr bool shouldUpdateStatus = false;
 
+    // set the value from vehcile side, used in end to end test.
+    if (propValue.prop == kSetIntPropertyFromVehcileForTest) {
+        auto mockValue = createVehiclePropValue(VehiclePropertyType::INT32, 1);
+        mockValue->prop = propValue.value.int32Values[0];
+        mockValue->value.int32Values[0] = propValue.value.int32Values[1];
+        mockValue->timestamp = propValue.value.int64Values[0];
+        mockValue->areaId = propValue.areaId;
+        setPropertyFromVehicle(*mockValue);
+        return StatusCode::OK;
+    }
+
+    if (propValue.prop == kSetFloatPropertyFromVehcileForTest) {
+        auto mockValue = createVehiclePropValue(VehiclePropertyType::FLOAT, 1);
+        mockValue->prop = propValue.value.int32Values[0];
+        mockValue->value.floatValues[0] = propValue.value.floatValues[0];
+        mockValue->timestamp = propValue.value.int64Values[0];
+        mockValue->areaId = propValue.areaId;
+        setPropertyFromVehicle(*mockValue);
+        return StatusCode::OK;
+    }
+    if (propValue.prop == kSetBooleanPropertyFromVehcileForTest) {
+        auto mockValue = createVehiclePropValue(VehiclePropertyType::BOOLEAN, 1);
+        mockValue->prop = propValue.value.int32Values[1];
+        mockValue->value.int32Values[0] = propValue.value.int32Values[0];
+        mockValue->timestamp = propValue.value.int64Values[0];
+        mockValue->areaId = propValue.areaId;
+        setPropertyFromVehicle(*mockValue);
+        return StatusCode::OK;
+    }
+
     if (propValue.prop == kGenerateFakeDataControllingProperty) {
         StatusCode status = handleGenerateFakeDataRequest(propValue);
         if (status != StatusCode::OK) {
@@ -198,12 +228,19 @@
         return StatusCode::NOT_AVAILABLE;
     }
 
-    if (!mPropStore->writeValue(propValue, shouldUpdateStatus)) {
-        return StatusCode::INVALID_ARG;
+    /**
+     * After checking all conditions, such as the property is available, a real vhal will
+     * sent the events to Car ECU to take actions.
+     * Google HAL will just add a timestamp for the value and triggle the callback to android.
+     */
+    VehiclePropValuePtr updatedPropValue = getValuePool()->obtain(propValue);
+    updatedPropValue->timestamp = elapsedRealtimeNano();
+    if (!mPropStore->writeValue(*updatedPropValue, shouldUpdateStatus)) {
+        return StatusCode::INTERNAL_ERROR;
     }
 
-    getEmulatorOrDie()->doSetValueFromClient(propValue);
-    doHalEvent(getValuePool()->obtain(propValue));
+    getEmulatorOrDie()->doSetValueFromClient(*updatedPropValue);
+    doHalEvent(std::move(updatedPropValue));
 
     return StatusCode::OK;
 }
diff --git a/confirmationui/1.0/vts/functional/Android.bp b/confirmationui/1.0/vts/functional/Android.bp
index d19d702..fd088cd 100644
--- a/confirmationui/1.0/vts/functional/Android.bp
+++ b/confirmationui/1.0/vts/functional/Android.bp
@@ -23,7 +23,7 @@
     static_libs: [
         "android.hardware.confirmationui@1.0",
         "android.hardware.keymaster@4.0",
-        "libcrypto",
+        "libcrypto_static",
         "libcn-cbor",
         "android.hardware.confirmationui-support-lib",
     ],
diff --git a/current.txt b/current.txt
index 83657b2..3352f8a 100644
--- a/current.txt
+++ b/current.txt
@@ -579,3 +579,6 @@
 40e71cd693de5b832325c5d8f081f2ff20a7ba2b89d401cee5b4b3eb0e241681 android.hardware.neuralnetworks@1.2::IPreparedModel
 1a6e2bd289f22931c526b21916910f1d4c436b7acb9556e4243de4ce8e6cc2e4 android.hardware.soundtrigger@2.0::ISoundTriggerHwCallback
 fd65298e1e09e0e3c781ab18305920d757dbe55a3b459ce17814ec5cf6dfee99 android.hardware.wifi@1.0::IWifiP2pIface
+
+# HALs released in Android R
+04395b26be33db17747c3d3b0e8066d323f891ff4f9f3b3ddb490b2f3f844a18 android.hardware.wifi@1.4::IWifi
diff --git a/drm/1.0/vts/functional/Android.bp b/drm/1.0/vts/functional/Android.bp
index d6ebfdd..61d4d58 100644
--- a/drm/1.0/vts/functional/Android.bp
+++ b/drm/1.0/vts/functional/Android.bp
@@ -30,7 +30,7 @@
         "libhidlmemory",
         "libnativehelper",
         "libssl",
-        "libcrypto",
+        "libcrypto_static",
     ],
     test_suites: ["general-tests"],
 }
diff --git a/drm/1.2/vts/functional/Android.bp b/drm/1.2/vts/functional/Android.bp
index 6b4a4c0..95883bf 100644
--- a/drm/1.2/vts/functional/Android.bp
+++ b/drm/1.2/vts/functional/Android.bp
@@ -34,7 +34,7 @@
         "libhidlmemory",
         "libnativehelper",
         "libssl",
-        "libcrypto",
+        "libcrypto_static",
     ],
     test_suites: ["general-tests"],
 }
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/keymaster/3.0/vts/functional/Android.bp b/keymaster/3.0/vts/functional/Android.bp
index b0371c7..69aa56d 100644
--- a/keymaster/3.0/vts/functional/Android.bp
+++ b/keymaster/3.0/vts/functional/Android.bp
@@ -26,7 +26,7 @@
     ],
     static_libs: [
         "android.hardware.keymaster@3.0",
-        "libcrypto",
+        "libcrypto_static",
         "libsoftkeymasterdevice",
     ],
     test_suites: ["general-tests"],
diff --git a/keymaster/4.0/vts/functional/Android.bp b/keymaster/4.0/vts/functional/Android.bp
index 333e408..0401362 100644
--- a/keymaster/4.0/vts/functional/Android.bp
+++ b/keymaster/4.0/vts/functional/Android.bp
@@ -25,7 +25,7 @@
     ],
     static_libs: [
         "android.hardware.keymaster@4.0",
-        "libcrypto",
+        "libcrypto_static",
         "libkeymaster4support",
         "libsoftkeymasterdevice",
     ],
diff --git a/sensors/2.0/multihal/HalProxy.cpp b/sensors/2.0/multihal/HalProxy.cpp
index 81d1b64..1fbc787 100644
--- a/sensors/2.0/multihal/HalProxy.cpp
+++ b/sensors/2.0/multihal/HalProxy.cpp
@@ -49,8 +49,15 @@
 }
 
 HalProxy::~HalProxy() {
-    // TODO: Join any running threads and clean up FMQs and any other allocated
-    // state.
+    {
+        std::lock_guard<std::mutex> lockGuard(mEventQueueWriteMutex);
+        mPendingWritesRun = false;
+        mEventQueueWriteCV.notify_one();
+    }
+    if (mPendingWritesThread.joinable()) {
+        mPendingWritesThread.join();
+    }
+    // TODO: Cleanup wakeup thread once it is implemented
 }
 
 Return<void> HalProxy::getSensorsList(getSensorsList_cb _hidl_cb) {
@@ -120,7 +127,8 @@
         result = Result::BAD_VALUE;
     }
 
-    // TODO: start threads to read wake locks and process events from sub HALs.
+    mPendingWritesThread = std::thread(startPendingWritesThread, this);
+    // TODO: start threads to read wake locks.
 
     for (size_t i = 0; i < mSubHalList.size(); i++) {
         auto subHal = mSubHalList[i];
@@ -146,30 +154,50 @@
     return getSubHalForSensorHandle(sensorHandle)->flush(clearSubHalIndex(sensorHandle));
 }
 
-Return<Result> HalProxy::injectSensorData(const Event& /* event */) {
-    // TODO: Proxy API call to appropriate sub-HAL.
-    return Result::INVALID_OPERATION;
+Return<Result> HalProxy::injectSensorData(const Event& event) {
+    Result result = Result::OK;
+    if (mCurrentOperationMode == OperationMode::NORMAL &&
+        event.sensorType != V1_0::SensorType::ADDITIONAL_INFO) {
+        ALOGE("An event with type != ADDITIONAL_INFO passed to injectSensorData while operation"
+              " mode was NORMAL.");
+        result = Result::BAD_VALUE;
+    }
+    if (result == Result::OK) {
+        Event subHalEvent = event;
+        subHalEvent.sensorHandle = clearSubHalIndex(event.sensorHandle);
+        result = getSubHalForSensorHandle(event.sensorHandle)->injectSensorData(subHalEvent);
+    }
+    return result;
 }
 
-Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& /* mem */,
+Return<void> HalProxy::registerDirectChannel(const SharedMemInfo& mem,
                                              registerDirectChannel_cb _hidl_cb) {
-    // TODO: During init, discover the first sub-HAL in the config that has sensors with direct
-    // channel support, if any, and proxy the API call there.
-    _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+    if (mDirectChannelSubHal == nullptr) {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* channelHandle */);
+    } else {
+        mDirectChannelSubHal->registerDirectChannel(mem, _hidl_cb);
+    }
     return Return<void>();
 }
 
-Return<Result> HalProxy::unregisterDirectChannel(int32_t /* channelHandle */) {
-    // TODO: During init, discover the first sub-HAL in the config that has sensors with direct
-    // channel support, if any, and proxy the API call there.
-    return Result::INVALID_OPERATION;
+Return<Result> HalProxy::unregisterDirectChannel(int32_t channelHandle) {
+    Result result;
+    if (mDirectChannelSubHal == nullptr) {
+        result = Result::INVALID_OPERATION;
+    } else {
+        result = mDirectChannelSubHal->unregisterDirectChannel(channelHandle);
+    }
+    return result;
 }
 
-Return<void> HalProxy::configDirectReport(int32_t /* sensorHandle */, int32_t /* channelHandle */,
-                                          RateLevel /* rate */, configDirectReport_cb _hidl_cb) {
-    // TODO: During init, discover the first sub-HAL in the config that has sensors with direct
-    // channel support, if any, and proxy the API call there.
-    _hidl_cb(Result::INVALID_OPERATION, 0 /* reportToken */);
+Return<void> HalProxy::configDirectReport(int32_t sensorHandle, int32_t channelHandle,
+                                          RateLevel rate, configDirectReport_cb _hidl_cb) {
+    if (mDirectChannelSubHal == nullptr) {
+        _hidl_cb(Result::INVALID_OPERATION, -1 /* reportToken */);
+    } else {
+        mDirectChannelSubHal->configDirectReport(clearSubHalIndex(sensorHandle), channelHandle,
+                                                 rate, _hidl_cb);
+    }
     return Return<void>();
 }
 
@@ -257,21 +285,66 @@
     initializeSensorList();
 }
 
+void HalProxy::startPendingWritesThread(HalProxy* halProxy) {
+    halProxy->handlePendingWrites();
+}
+
+void HalProxy::handlePendingWrites() {
+    // TODO: Find a way to optimize locking strategy maybe using two mutexes instead of one.
+    std::unique_lock<std::mutex> lock(mEventQueueWriteMutex);
+    while (mPendingWritesRun) {
+        mEventQueueWriteCV.wait(
+                lock, [&] { return !mPendingWriteEventsQueue.empty() || !mPendingWritesRun; });
+        if (!mPendingWriteEventsQueue.empty() && mPendingWritesRun) {
+            std::vector<Event>& pendingWriteEvents = mPendingWriteEventsQueue.front();
+            size_t eventQueueSize = mEventQueue->getQuantumCount();
+            size_t numToWrite = std::min(pendingWriteEvents.size(), eventQueueSize);
+            lock.unlock();
+            // TODO: Find a way to interrup writeBlocking if the thread should exit
+            // so we don't have to wait for timeout on framework restarts.
+            if (!mEventQueue->writeBlocking(
+                        pendingWriteEvents.data(), numToWrite,
+                        static_cast<uint32_t>(EventQueueFlagBits::EVENTS_READ),
+                        static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS),
+                        kWakelockTimeoutNs, mEventQueueFlag)) {
+                ALOGE("Dropping %zu events after blockingWrite failed.", numToWrite);
+            } else {
+                mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+            }
+            lock.lock();
+            if (pendingWriteEvents.size() > eventQueueSize) {
+                // TODO: Check if this erase operation is too inefficient. It will copy all the
+                // events ahead of it down to fill gap off array at front after the erase.
+                pendingWriteEvents.erase(pendingWriteEvents.begin(),
+                                         pendingWriteEvents.begin() + eventQueueSize);
+            } else {
+                mPendingWriteEventsQueue.pop();
+            }
+        }
+    }
+}
+
 void HalProxy::postEventsToMessageQueue(const std::vector<Event>& events) {
-    std::lock_guard<std::mutex> lock(mEventQueueMutex);
-    size_t numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
-    if (numToWrite > 0) {
-        if (mEventQueue->write(events.data(), numToWrite)) {
-            // TODO: While loop if mEventQueue->avaiableToWrite > 0 to possibly fit in more writes
-            // immediately
-            mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
-        } else {
-            numToWrite = 0;
+    size_t numToWrite = 0;
+    std::lock_guard<std::mutex> lock(mEventQueueWriteMutex);
+    if (mPendingWriteEventsQueue.empty()) {
+        numToWrite = std::min(events.size(), mEventQueue->availableToWrite());
+        if (numToWrite > 0) {
+            if (mEventQueue->write(events.data(), numToWrite)) {
+                // TODO: While loop if mEventQueue->avaiableToWrite > 0 to possibly fit in more
+                // writes immediately
+                mEventQueueFlag->wake(static_cast<uint32_t>(EventQueueFlagBits::READ_AND_PROCESS));
+            } else {
+                numToWrite = 0;
+            }
         }
     }
     if (numToWrite < events.size()) {
-        // TODO: Post from events[numToWrite -> end] to background events queue
-        // Signal background thread
+        // TODO: Bound the mPendingWriteEventsQueue so that we do not trigger OOMs if framework
+        // stalls
+        mPendingWriteEventsQueue.push(
+                std::vector<Event>(events.begin() + numToWrite, events.end()));
+        mEventQueueWriteCV.notify_one();
     }
 }
 
diff --git a/sensors/2.0/multihal/include/HalProxy.h b/sensors/2.0/multihal/include/HalProxy.h
index bdcc1ff..ae4b2c5 100644
--- a/sensors/2.0/multihal/include/HalProxy.h
+++ b/sensors/2.0/multihal/include/HalProxy.h
@@ -24,7 +24,12 @@
 #include <hidl/MQDescriptor.h>
 #include <hidl/Status.h>
 
+#include <atomic>
+#include <condition_variable>
 #include <map>
+#include <mutex>
+#include <queue>
+#include <thread>
 
 namespace android {
 namespace hardware {
@@ -159,6 +164,7 @@
      */
     std::vector<ISensorsSubHal*> mSubHalList;
 
+    //! The list of subhal callbacks for each subhal where the indices correlate with mSubHalList
     std::vector<const sp<IHalProxyCallback>> mSubHalCallbacks;
 
     /**
@@ -179,6 +185,9 @@
     //! The mutex for the event queue.
     std::mutex mEventQueueMutex;
 
+    //! The timeout for each pending write on background thread for events.
+    static const int64_t kWakelockTimeoutNs = 5 * INT64_C(1000000000) /* 5 seconds */;
+
     //! The scoped wakelock ref count.
     size_t mWakelockRefCount = 0;
 
@@ -188,6 +197,21 @@
     //! The bit mask used to get the subhal index from a sensor handle.
     static constexpr uint32_t kSensorHandleSubHalIndexMask = 0xFF000000;
 
+    //! The events that were not able to be written to fmq right away
+    std::queue<std::vector<Event>> mPendingWriteEventsQueue;
+
+    //! The mutex protecting writing to the fmq and the pending events queue
+    std::mutex mEventQueueWriteMutex;
+
+    //! The condition variable waiting on pending write events to stack up
+    std::condition_variable mEventQueueWriteCV;
+
+    //! The thread object ptr that handles pending writes
+    std::thread mPendingWritesThread;
+
+    //! The bool indicating whether to end the pending writes background thread or not
+    bool mPendingWritesRun = true;
+
     /**
      * Initialize the list of SubHal objects in mSubHalList by reading from dynamic libraries
      * listed in a config file.
@@ -211,6 +235,16 @@
     void initializeSubHalCallbacksAndSensorList();
 
     /**
+     * Starts the thread that handles pending writes to event fmq.
+     *
+     * @param halProxy The HalProxy object pointer.
+     */
+    static void startPendingWritesThread(HalProxy* halProxy);
+
+    //! Handles the pending writes on events to eventqueue.
+    void handlePendingWrites();
+
+    /**
      * Clear direct channel flags if the HalProxy has already chosen a subhal as its direct channel
      * subhal. Set the directChannelSubHal pointer to the subHal passed in if this is the first
      * direct channel enabled sensor seen.
diff --git a/sensors/2.0/multihal/tests/HalProxy_test.cpp b/sensors/2.0/multihal/tests/HalProxy_test.cpp
index 4b1a15e..61fb14c 100644
--- a/sensors/2.0/multihal/tests/HalProxy_test.cpp
+++ b/sensors/2.0/multihal/tests/HalProxy_test.cpp
@@ -22,11 +22,10 @@
 #include "ScopedWakelock.h"
 #include "SensorsSubHal.h"
 
+#include <chrono>
+#include <thread>
 #include <vector>
 
-#undef LOG_TAG
-#define LOG_TAG "HalProxy_test"
-
 namespace {
 
 using ::android::hardware::hidl_vec;
@@ -98,7 +97,7 @@
  * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
  *    which is a wakeup type sensor.
  *
- * @ return A proximity event.
+ * @return A proximity event.
  */
 Event makeProximityEvent();
 
@@ -106,10 +105,30 @@
  * Construct and return a HIDL Event type thats sensorHandle refers to a proximity sensor
  *    which is a wakeup type sensor.
  *
- * @ return A proximity event.
+ * @return A proximity event.
  */
 Event makeAccelerometerEvent();
 
+/**
+ * Make a certain number of proximity type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<Event> makeMultipleProximityEvents(size_t numEvents);
+
+/**
+ * Make a certain number of accelerometer type events with the sensorHandle field set to
+ * the proper number for AllSensorsSubHal subhal type.
+ *
+ * @param numEvents The number of events to make.
+ *
+ * @return The created list of events.
+ */
+std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents);
+
 // Tests follow
 TEST(HalProxyTest, GetSensorsListOneSubHalTest) {
     AllSensorsSubHal subHal;
@@ -232,10 +251,7 @@
     ::android::sp<ISensorsCallback> callback = new SensorsCallback();
     proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
 
-    std::vector<Event> events;
-    for (size_t i = 0; i < kNumEvents; i++) {
-        events.push_back(makeAccelerometerEvent());
-    }
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
     subHal.postEvents(events, false /* wakeup */);
 
     EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
@@ -272,15 +288,114 @@
     ::android::sp<ISensorsCallback> callback = new SensorsCallback();
     proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
 
-    std::vector<Event> events;
-    for (size_t i = 0; i < kNumEvents; i++) {
-        events.push_back(makeProximityEvent());
-    }
+    std::vector<Event> events = makeMultipleProximityEvents(kNumEvents);
     subHal.postEvents(events, true /* wakeup */);
 
     EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
 }
 
+TEST(HalProxyTest, PostEventsMultipleSubhals) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue =
+            std::make_unique<EventMessageQueue>(kQueueSize, true);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
+            std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal1.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents);
+
+    subHal2.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, PostEventsDelayedWrite) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 6;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue =
+            std::make_unique<EventMessageQueue>(kQueueSize, true);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
+            std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal1.postEvents(events, false /* wakeup */);
+
+    EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
+
+    Event eventOut;
+    // writeblock 1 event out of queue, timeout for half a second
+    EXPECT_TRUE(eventQueue->readBlocking(&eventOut, 1, 500000000));
+
+    // Sleep for a half second so that blocking write has time complete in background thread
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+    // proxy background thread should have wrote last event when it saw space
+    EXPECT_EQ(eventQueue->availableToRead(), kQueueSize);
+}
+
+TEST(HalProxyTest, PostEventsMultipleSubhalsThreaded) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 2;
+    AllSensorsSubHal subHal1, subHal2;
+    std::vector<ISensorsSubHal*> subHals{&subHal1, &subHal2};
+    HalProxy proxy(subHals);
+    std::unique_ptr<EventMessageQueue> eventQueue =
+            std::make_unique<EventMessageQueue>(kQueueSize, true);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
+            std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+
+    std::thread t1(&AllSensorsSubHal::postEvents, &subHal1, events, false);
+    std::thread t2(&AllSensorsSubHal::postEvents, &subHal2, events, false);
+
+    t1.join();
+    t2.join();
+
+    EXPECT_EQ(eventQueue->availableToRead(), kNumEvents * 2);
+}
+
+TEST(HalProxyTest, DestructingWithEventsPendingOnBackgroundThreadTest) {
+    constexpr size_t kQueueSize = 5;
+    constexpr size_t kNumEvents = 6;
+    AllSensorsSubHal subHal;
+    std::vector<ISensorsSubHal*> subHals{&subHal};
+
+    std::unique_ptr<EventMessageQueue> eventQueue =
+            std::make_unique<EventMessageQueue>(kQueueSize, true);
+    std::unique_ptr<WakeupMessageQueue> wakeLockQueue =
+            std::make_unique<WakeupMessageQueue>(kQueueSize, true);
+    ::android::sp<ISensorsCallback> callback = new SensorsCallback();
+    HalProxy proxy(subHals);
+    proxy.initialize(*eventQueue->getDesc(), *wakeLockQueue->getDesc(), callback);
+
+    std::vector<Event> events = makeMultipleAccelerometerEvents(kNumEvents);
+    subHal.postEvents(events, false /* wakeup */);
+
+    // Sleep for a half second so that background thread has time to attempt it's blocking write
+    std::this_thread::sleep_for(std::chrono::milliseconds(500));
+
+    // Should see a 5 second wait for blocking write timeout here
+
+    // Should be one events left on pending writes queue here and proxy will destruct
+    // If this TEST completes then it was a success, if it hangs we will see a crash
+}
+
 // Helper implementations follow
 void testSensorsListFromProxyAndSubHal(const std::vector<SensorInfo>& proxySensorsList,
                                        const std::vector<SensorInfo>& subHalSensorsList) {
@@ -332,4 +447,20 @@
     return event;
 }
 
+std::vector<Event> makeMultipleProximityEvents(size_t numEvents) {
+    std::vector<Event> events;
+    for (size_t i = 0; i < numEvents; i++) {
+        events.push_back(makeProximityEvent());
+    }
+    return events;
+}
+
+std::vector<Event> makeMultipleAccelerometerEvents(size_t numEvents) {
+    std::vector<Event> events;
+    for (size_t i = 0; i < numEvents; i++) {
+        events.push_back(makeAccelerometerEvent());
+    }
+    return events;
+}
+
 }  // namespace
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/IFrontend.hal b/tv/tuner/1.0/IFrontend.hal
index f7237ba..8788643 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.
@@ -81,4 +82,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/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/default/service.cpp b/tv/tuner/1.0/default/service.cpp
index c360fcf..7bbc09e 100644
--- a/tv/tuner/1.0/default/service.cpp
+++ b/tv/tuner/1.0/default/service.cpp
@@ -21,7 +21,6 @@
 #define LOG_TAG "android.hardware.tv.tuner@1.0-service"
 #endif
 
-#include <binder/ProcessState.h>
 #include <hidl/HidlTransportSupport.h>
 #include <hidl/LegacySupport.h>
 
diff --git a/tv/tuner/1.0/types.hal b/tv/tuner/1.0/types.hal
index 77f7ead..d37f63a 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 frequency in Hertz */
     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;
 };
 
 /**
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index d272d71..7256cc4 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -36,6 +36,7 @@
 #include <utils/Mutex.h>
 #include <fstream>
 #include <iostream>
+#include <map>
 
 #define WAIT_TIMEOUT 3000000000
 
@@ -72,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;
@@ -159,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;
@@ -205,8 +217,8 @@
         ALOGW("[VTS] FILTER EVENT %d", filterEvent.filterId);
         android::Mutex::Autolock autoLock(mMsgLock);
         mFilterEventReceived = true;
-        // maybe assemble here??
-        mFilterEvent = filterEvent;
+        mFilterIdToEvent[filterEvent.filterId] = filterEvent;
+        startFilterEventThread(filterEvent);
         mMsgCondition.signal();
         return Void();
     }
@@ -236,11 +248,19 @@
     void testOnFilterEvent(uint32_t filterId);
     void testOnSectionFilterEvent(sp<IDemux>& demux, uint32_t filterId, MQDesc& filterMQDescriptor,
                                   MQDesc& inputMQDescriptor);
-    void startPlaybackInputThread(InputConf inputConf, MQDesc& inputMQDescriptor);
-    bool readAndCompareSectionEventData();
+    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:
     struct InputThreadArgs {
@@ -249,22 +269,34 @@
         bool* keepWritingInputFMQ;
         MQDesc& inputMQDesc;
     };
-    bool mFilterEventReceived = false;
-    std::vector<uint8_t> mDataOutputBuffer;
-    std::unique_ptr<FilterMQ> mFilterMQ;
-    std::unique_ptr<FilterMQ> mInputMQ;
+    struct FilterThreadArgs {
+        DemuxCallback* user;
+        DemuxFilterEvent& event;
+    };
     uint16_t mDataLength = 0;
-    DemuxFilterEvent mFilterEvent;
-    android::Mutex mMsgLock;
-    android::Mutex mReadLock;
-    android::Condition mMsgCondition;
-    EventFlag* mFilterMQEventFlag;
+    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 mFilterOutputLock;
+    android::Condition mMsgCondition;
+    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) {
@@ -276,7 +308,7 @@
     // 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) {
@@ -291,28 +323,42 @@
     pthread_setname_np(mInputThread, "test_playback_input_loop");
 }
 
-/*void DemuxCallback::testPlaybackDataFlow(bool* keepWritingInputFMQ) {
-    // timeout logic here
+void DemuxCallback::startFilterEventThread(DemuxFilterEvent event) {
+    struct FilterThreadArgs* threadArgs =
+            (struct FilterThreadArgs*)malloc(sizeof(struct FilterThreadArgs));
+    threadArgs->user = this;
+    threadArgs->event = event;
 
-    // assemble logic here
+    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,
                                              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) ==
-                android::OK);
+    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) ==
@@ -329,21 +375,24 @@
         mInputMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
         testOnFilterEvent(filterId);
         // checksum of mDataOutputBuffer and Input golden input
-        if (readAndCompareSectionEventData() && i < SECTION_READ_COUNT - 1) {
-            mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
+        if (readAndCompareSectionEventData(filterId) && i < SECTION_READ_COUNT - 1) {
+            mFilterIdToMQEventFlag[filterId]->wake(
+                    static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
         }
     }
 }
 
-bool 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 == 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++) {
@@ -353,6 +402,18 @@
     return result;
 }
 
+void DemuxCallback::updateFilterMQ(uint32_t filterId, MQDesc& filterMQDescriptor) {
+    mFilterIdToMQ[filterId] =
+            std::make_unique<FilterMQ>(filterMQDescriptor, true /* resetPointers */);
+    EXPECT_TRUE(mFilterIdToMQ[filterId]);
+    EXPECT_TRUE(EventFlag::createEventFlag(mFilterIdToMQ[filterId]->getEventFlagWord(),
+                                           &mFilterIdToMQEventFlag[filterId]) == android::OK);
+}
+
+void DemuxCallback::updateGoldenOutputMap(uint32_t filterId, string goldenOutputFile) {
+    mFilterIdToGoldenOutput[filterId] = goldenOutputFile;
+}
+
 void* DemuxCallback::__threadLoopInput(void* threadArgs) {
     DemuxCallback* const self =
             static_cast<DemuxCallback*>(((struct InputThreadArgs*)threadArgs)->user);
@@ -413,6 +474,26 @@
     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.
 class TunerHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase {
   public:
@@ -462,16 +543,19 @@
     ::testing::AssertionResult createDemuxWithFrontend(int32_t frontendId);
     ::testing::AssertionResult getInputMQDescriptor();
     ::testing::AssertionResult addInputToDemux(DemuxInputSettings setting);
-    ::testing::AssertionResult addSectionFilterToDemux();
     ::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 readSectionFilterDataOutput();
     ::testing::AssertionResult playbackDataFlowTest(vector<FilterConf> filterConf,
-                                                    InputConf inputConf, string goldenOutput);
+                                                    InputConf inputConf,
+                                                    vector<string> goldenOutputFiles);
+
+    // Legacy
+    ::testing::AssertionResult addSectionFilterToDemux();
+    ::testing::AssertionResult readSectionFilterDataOutput();
 };
 
 ::testing::AssertionResult TunerHidlTest::createFrontend(int32_t frontendId) {
@@ -507,8 +591,6 @@
 
     FrontendDvbtSettings frontendDvbtSettings{
             .frequency = 0,
-            .modulation = FrontendAtscModulation::UNDEFINED,
-            .fec = FrontendInnerFec::FEC_UNDEFINED,
     };
     frontendSettings.dvbt(frontendDvbtSettings);
     mFrontendCallback->testOnEvent(mFrontend, frontendSettings);
@@ -650,6 +732,7 @@
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
+// Legacy
 ::testing::AssertionResult TunerHidlTest::addSectionFilterToDemux() {
     Result status;
 
@@ -717,6 +800,7 @@
     return ::testing::AssertionResult(status == Result::SUCCESS);
 }
 
+// Legacy
 ::testing::AssertionResult TunerHidlTest::readSectionFilterDataOutput() {
     // Filter Configuration Module
     DemuxInputSettings setting{
@@ -744,7 +828,7 @@
 
 ::testing::AssertionResult TunerHidlTest::playbackDataFlowTest(vector<FilterConf> filterConf,
                                                                InputConf inputConf,
-                                                               string /*goldenOutput*/) {
+                                                               vector<string> goldenOutputFiles) {
     Result status;
     // Filter Configuration Module
     for (int i = 0; i < filterConf.size(); i++) {
@@ -754,6 +838,12 @@
             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
@@ -769,12 +859,9 @@
     }
 
     // Data Verify Module
-    // golden output, created FMQ to read and EventFlags to DATA_CONSUMED
-    // Maintain each filter's real output (and how to assemble?????)
-    // mDemuxCallback->testPlaybackDataFlow();
+    mDemuxCallback->testFilterDataOutput();
 
     // Clean Up Module
-    // TODO what about remove input, remove filters
     return closeDemux();
 }