Add tuner legacy HIDL HAL support.

The AIDL HAL based solution will be the default implementation. The
tuner service will only create the legacy HIDL HAL based implementation
when the HIDL HAL is available.

Bug: 191825295
Test: atest android.media.tv.tuner.cts on both AIDL and HIDL HAL.
Test: sampletunertvinput
Change-Id: I8436ae80721ad943c60b5814b535f3b87a54ccda
diff --git a/services/tuner/hidl/TunerHidlDemux.cpp b/services/tuner/hidl/TunerHidlDemux.cpp
new file mode 100644
index 0000000..5a921b9
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlDemux.cpp
@@ -0,0 +1,278 @@
+/**
+ * Copyright 2021, 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 "TunerHidlDemux"
+
+#include "TunerHidlDemux.h"
+
+#include "TunerHidlDvr.h"
+#include "TunerHidlFilter.h"
+#include "TunerHidlTimeFilter.h"
+
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSubType;
+
+using HidlDemuxAlpFilterType = ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterType;
+using HidlDemuxFilterMainType = ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using HidlDemuxFilterType = ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
+using HidlDemuxIpFilterType = ::android::hardware::tv::tuner::V1_0::DemuxIpFilterType;
+using HidlDemuxMmtpFilterType = ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using HidlDemuxTlvFilterType = ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterType;
+using HidlDemuxTsFilterType = ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using HidlDvrType = ::android::hardware::tv::tuner::V1_0::DvrType;
+using HidlResult = ::android::hardware::tv::tuner::V1_0::Result;
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+TunerHidlDemux::TunerHidlDemux(sp<IDemux> demux, int id) {
+    mDemux = demux;
+    mDemuxId = id;
+}
+
+TunerHidlDemux::~TunerHidlDemux() {
+    mDemux = nullptr;
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::setFrontendDataSource(
+        const shared_ptr<ITunerFrontend>& in_frontend) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    int frontendId;
+    in_frontend->getFrontendId(&frontendId);
+    HidlResult res = mDemux->setFrontendDataSource(frontendId);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::setFrontendDataSourceById(int frontendId) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    HidlResult res = mDemux->setFrontendDataSource(frontendId);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::openFilter(const DemuxFilterType& in_type,
+                                                int32_t in_bufferSize,
+                                                const shared_ptr<ITunerFilterCallback>& in_cb,
+                                                shared_ptr<ITunerFilter>* _aidl_return) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    HidlDemuxFilterMainType mainType = static_cast<HidlDemuxFilterMainType>(in_type.mainType);
+    HidlDemuxFilterType filterType{
+            .mainType = mainType,
+    };
+
+    switch (mainType) {
+    case HidlDemuxFilterMainType::TS:
+        filterType.subType.tsFilterType(static_cast<HidlDemuxTsFilterType>(
+                in_type.subType.get<DemuxFilterSubType::Tag::tsFilterType>()));
+        break;
+    case HidlDemuxFilterMainType::MMTP:
+        filterType.subType.mmtpFilterType(static_cast<HidlDemuxMmtpFilterType>(
+                in_type.subType.get<DemuxFilterSubType::Tag::mmtpFilterType>()));
+        break;
+    case HidlDemuxFilterMainType::IP:
+        filterType.subType.ipFilterType(static_cast<HidlDemuxIpFilterType>(
+                in_type.subType.get<DemuxFilterSubType::Tag::ipFilterType>()));
+        break;
+    case HidlDemuxFilterMainType::TLV:
+        filterType.subType.tlvFilterType(static_cast<HidlDemuxTlvFilterType>(
+                in_type.subType.get<DemuxFilterSubType::Tag::tlvFilterType>()));
+        break;
+    case HidlDemuxFilterMainType::ALP:
+        filterType.subType.alpFilterType(static_cast<HidlDemuxAlpFilterType>(
+                in_type.subType.get<DemuxFilterSubType::Tag::alpFilterType>()));
+        break;
+    }
+    HidlResult status;
+    sp<HidlIFilter> filterSp;
+    sp<::android::hardware::tv::tuner::V1_0::IFilterCallback> cbSp =
+            new TunerHidlFilter::FilterCallback(in_cb);
+    mDemux->openFilter(filterType, static_cast<uint32_t>(in_bufferSize), cbSp,
+                       [&](HidlResult r, const sp<HidlIFilter>& filter) {
+                           filterSp = filter;
+                           status = r;
+                       });
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+
+    *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlFilter>(filterSp, in_type);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::openTimeFilter(shared_ptr<ITunerTimeFilter>* _aidl_return) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    HidlResult status;
+    sp<HidlITimeFilter> filterSp;
+    mDemux->openTimeFilter([&](HidlResult r, const sp<HidlITimeFilter>& filter) {
+        filterSp = filter;
+        status = r;
+    });
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+
+    *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlTimeFilter>(filterSp);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::getAvSyncHwId(const shared_ptr<ITunerFilter>& tunerFilter,
+                                                   int32_t* _aidl_return) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    uint32_t avSyncHwId;
+    HidlResult res;
+    sp<HidlIFilter> halFilter = static_cast<TunerHidlFilter*>(tunerFilter.get())->getHalFilter();
+    mDemux->getAvSyncHwId(halFilter, [&](HidlResult r, uint32_t id) {
+        res = r;
+        avSyncHwId = id;
+    });
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    *_aidl_return = (int)avSyncHwId;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::getAvSyncTime(int32_t avSyncHwId, int64_t* _aidl_return) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    uint64_t time;
+    HidlResult res;
+    mDemux->getAvSyncTime(static_cast<uint32_t>(avSyncHwId), [&](HidlResult r, uint64_t ts) {
+        res = r;
+        time = ts;
+    });
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    *_aidl_return = (int64_t)time;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::openDvr(DvrType in_dvbType, int32_t in_bufferSize,
+                                             const shared_ptr<ITunerDvrCallback>& in_cb,
+                                             shared_ptr<ITunerDvr>* _aidl_return) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    HidlResult res;
+    sp<HidlIDvrCallback> callback = new TunerHidlDvr::DvrCallback(in_cb);
+    sp<HidlIDvr> hidlDvr;
+    mDemux->openDvr(static_cast<HidlDvrType>(in_dvbType), in_bufferSize, callback,
+                    [&](HidlResult r, const sp<HidlIDvr>& dvr) {
+                        hidlDvr = dvr;
+                        res = r;
+                    });
+    if (res != HidlResult::SUCCESS) {
+        *_aidl_return = nullptr;
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlDvr>(hidlDvr, in_dvbType);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::connectCiCam(int32_t ciCamId) {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    HidlResult res = mDemux->connectCiCam(static_cast<uint32_t>(ciCamId));
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::disconnectCiCam() {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    HidlResult res = mDemux->disconnectCiCam();
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDemux::close() {
+    if (mDemux == nullptr) {
+        ALOGE("IDemux is not initialized.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(HidlResult::UNAVAILABLE));
+    }
+
+    HidlResult res = mDemux->close();
+    mDemux = nullptr;
+
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
diff --git a/services/tuner/hidl/TunerHidlDemux.h b/services/tuner/hidl/TunerHidlDemux.h
new file mode 100644
index 0000000..d535da6
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlDemux.h
@@ -0,0 +1,75 @@
+/**
+ * Copyright 2021, 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_MEDIA_TUNERHIDLDEMUX_H
+#define ANDROID_MEDIA_TUNERHIDLDEMUX_H
+
+#include <aidl/android/media/tv/tuner/BnTunerDemux.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+
+using ::aidl::android::hardware::tv::tuner::DemuxFilterType;
+using ::aidl::android::hardware::tv::tuner::DvrType;
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::tv::tuner::V1_0::IDemux;
+using ::std::shared_ptr;
+using ::std::vector;
+
+using HidlIDemux = ::android::hardware::tv::tuner::V1_0::IDemux;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+class TunerHidlDemux : public BnTunerDemux {
+public:
+    TunerHidlDemux(sp<HidlIDemux> demux, int demuxId);
+    virtual ~TunerHidlDemux();
+
+    ::ndk::ScopedAStatus setFrontendDataSource(
+            const shared_ptr<ITunerFrontend>& in_frontend) override;
+    ::ndk::ScopedAStatus setFrontendDataSourceById(int frontendId) override;
+    ::ndk::ScopedAStatus openFilter(const DemuxFilterType& in_type, int32_t in_bufferSize,
+                                    const shared_ptr<ITunerFilterCallback>& in_cb,
+                                    shared_ptr<ITunerFilter>* _aidl_return) override;
+    ::ndk::ScopedAStatus openTimeFilter(shared_ptr<ITunerTimeFilter>* _aidl_return) override;
+    ::ndk::ScopedAStatus getAvSyncHwId(const shared_ptr<ITunerFilter>& in_tunerFilter,
+                                       int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getAvSyncTime(int32_t in_avSyncHwId, int64_t* _aidl_return) override;
+    ::ndk::ScopedAStatus openDvr(DvrType in_dvbType, int32_t in_bufferSize,
+                                 const shared_ptr<ITunerDvrCallback>& in_cb,
+                                 shared_ptr<ITunerDvr>* _aidl_return) override;
+    ::ndk::ScopedAStatus connectCiCam(int32_t in_ciCamId) override;
+    ::ndk::ScopedAStatus disconnectCiCam() override;
+    ::ndk::ScopedAStatus close() override;
+
+    int getId() { return mDemuxId; }
+
+private:
+    sp<HidlIDemux> mDemux;
+    int mDemuxId;
+};
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
+
+#endif  // ANDROID_MEDIA_TUNERHIDLDEMUX_H
diff --git a/services/tuner/hidl/TunerHidlDescrambler.cpp b/services/tuner/hidl/TunerHidlDescrambler.cpp
new file mode 100644
index 0000000..dd8cd9c
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlDescrambler.cpp
@@ -0,0 +1,149 @@
+/**
+ * Copyright 2021, 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 "TunerHidlDescrambler"
+
+#include "TunerHidlDescrambler.h"
+
+#include <aidl/android/hardware/tv/tuner/Result.h>
+
+#include "TunerHidlDemux.h"
+#include "TunerHidlFilter.h"
+
+using ::aidl::android::hardware::tv::tuner::Result;
+
+using HidlResult = ::android::hardware::tv::tuner::V1_0::Result;
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+TunerHidlDescrambler::TunerHidlDescrambler(sp<HidlIDescrambler> descrambler) {
+    mDescrambler = descrambler;
+}
+
+TunerHidlDescrambler::~TunerHidlDescrambler() {
+    mDescrambler = nullptr;
+}
+
+::ndk::ScopedAStatus TunerHidlDescrambler::setDemuxSource(
+        const shared_ptr<ITunerDemux>& in_tunerDemux) {
+    if (mDescrambler == nullptr) {
+        ALOGE("IDescrambler is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mDescrambler->setDemuxSource(
+            static_cast<TunerHidlDemux*>(in_tunerDemux.get())->getId());
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDescrambler::setKeyToken(const vector<uint8_t>& in_keyToken) {
+    if (mDescrambler == nullptr) {
+        ALOGE("IDescrambler is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mDescrambler->setKeyToken(in_keyToken);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDescrambler::addPid(
+        const DemuxPid& in_pid, const shared_ptr<ITunerFilter>& in_optionalSourceFilter) {
+    if (mDescrambler == nullptr) {
+        ALOGE("IDescrambler is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    sp<HidlIFilter> halFilter =
+            (in_optionalSourceFilter == nullptr)
+                    ? nullptr
+                    : static_cast<TunerHidlFilter*>(in_optionalSourceFilter.get())->getHalFilter();
+    HidlResult res = mDescrambler->addPid(getHidlDemuxPid(in_pid), halFilter);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDescrambler::removePid(
+        const DemuxPid& in_pid, const shared_ptr<ITunerFilter>& in_optionalSourceFilter) {
+    if (mDescrambler == nullptr) {
+        ALOGE("IDescrambler is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    sp<HidlIFilter> halFilter =
+            (in_optionalSourceFilter == nullptr)
+                    ? nullptr
+                    : static_cast<TunerHidlFilter*>(in_optionalSourceFilter.get())->getHalFilter();
+    HidlResult res = mDescrambler->removePid(getHidlDemuxPid(in_pid), halFilter);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDescrambler::close() {
+    if (mDescrambler == nullptr) {
+        ALOGE("IDescrambler is not initialized.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mDescrambler->close();
+    mDescrambler = nullptr;
+
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+HidlDemuxPid TunerHidlDescrambler::getHidlDemuxPid(const DemuxPid& pid) {
+    HidlDemuxPid hidlPid;
+    switch (pid.getTag()) {
+    case DemuxPid::tPid: {
+        hidlPid.tPid((uint16_t)pid.get<DemuxPid::Tag::tPid>());
+        break;
+    }
+    case DemuxPid::mmtpPid: {
+        hidlPid.mmtpPid((uint16_t)pid.get<DemuxPid::Tag::mmtpPid>());
+        break;
+    }
+    }
+    return hidlPid;
+}
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
diff --git a/services/tuner/hidl/TunerHidlDescrambler.h b/services/tuner/hidl/TunerHidlDescrambler.h
new file mode 100644
index 0000000..9494968
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlDescrambler.h
@@ -0,0 +1,66 @@
+/**
+ * Copyright 2021, 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_MEDIA_TUNERHIDLDESCRAMBLER_H
+#define ANDROID_MEDIA_TUNERHIDLDESCRAMBLER_H
+
+#include <aidl/android/hardware/tv/tuner/IDescrambler.h>
+#include <aidl/android/media/tv/tuner/BnTunerDescrambler.h>
+#include <android/hardware/tv/tuner/1.0/IDescrambler.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+
+using ::aidl::android::hardware::tv::tuner::DemuxPid;
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using HidlDemuxPid = ::android::hardware::tv::tuner::V1_0::DemuxPid;
+using HidlIDescrambler = ::android::hardware::tv::tuner::V1_0::IDescrambler;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+class TunerHidlDescrambler : public BnTunerDescrambler {
+public:
+    TunerHidlDescrambler(sp<HidlIDescrambler> descrambler);
+    virtual ~TunerHidlDescrambler();
+
+    ::ndk::ScopedAStatus setDemuxSource(const std::shared_ptr<ITunerDemux>& in_tunerDemux) override;
+    ::ndk::ScopedAStatus setKeyToken(const std::vector<uint8_t>& in_keyToken) override;
+    ::ndk::ScopedAStatus addPid(
+            const DemuxPid& in_pid,
+            const std::shared_ptr<ITunerFilter>& in_optionalSourceFilter) override;
+    ::ndk::ScopedAStatus removePid(
+            const DemuxPid& in_pid,
+            const std::shared_ptr<ITunerFilter>& in_optionalSourceFilter) override;
+    ::ndk::ScopedAStatus close() override;
+
+private:
+    HidlDemuxPid getHidlDemuxPid(const DemuxPid& pid);
+
+    sp<HidlIDescrambler> mDescrambler;
+};
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
+
+#endif  // ANDROID_MEDIA_TUNERHIDLDESCRAMBLER_H
diff --git a/services/tuner/hidl/TunerHidlDvr.cpp b/services/tuner/hidl/TunerHidlDvr.cpp
new file mode 100644
index 0000000..1a619d5
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlDvr.cpp
@@ -0,0 +1,257 @@
+/**
+ * Copyright 2021, 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 "TunerHidlDvr"
+
+#include "TunerHidlDvr.h"
+
+#include <aidl/android/hardware/tv/tuner/DataFormat.h>
+#include <aidl/android/hardware/tv/tuner/PlaybackStatus.h>
+#include <aidl/android/hardware/tv/tuner/RecordStatus.h>
+#include <aidl/android/hardware/tv/tuner/Result.h>
+#include <fmq/ConvertMQDescriptors.h>
+
+using ::aidl::android::hardware::tv::tuner::DataFormat;
+using ::aidl::android::hardware::tv::tuner::PlaybackStatus;
+using ::aidl::android::hardware::tv::tuner::RecordStatus;
+using ::aidl::android::hardware::tv::tuner::Result;
+using ::android::unsafeHidlToAidlMQDescriptor;
+using ::android::hardware::MessageQueue;
+using ::android::hardware::MQDescriptorSync;
+
+using HidlDataFormat = ::android::hardware::tv::tuner::V1_0::DataFormat;
+using HidlResult = ::android::hardware::tv::tuner::V1_0::Result;
+using MQDesc = MQDescriptorSync<uint8_t>;
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+TunerHidlDvr::TunerHidlDvr(sp<HidlIDvr> dvr, DvrType type) {
+    mDvr = dvr;
+    mType = type;
+}
+
+TunerHidlDvr::~TunerHidlDvr() {
+    mDvr = nullptr;
+}
+
+::ndk::ScopedAStatus TunerHidlDvr::getQueueDesc(AidlMQDesc* _aidl_return) {
+    if (mDvr == nullptr) {
+        ALOGE("IDvr is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    MQDesc dvrMQDesc;
+    HidlResult res;
+    mDvr->getQueueDesc([&](HidlResult r, const MQDesc& desc) {
+        dvrMQDesc = desc;
+        res = r;
+    });
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    AidlMQDesc aidlMQDesc;
+    unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(dvrMQDesc, &aidlMQDesc);
+    *_aidl_return = move(aidlMQDesc);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDvr::configure(const DvrSettings& in_settings) {
+    if (mDvr == nullptr) {
+        ALOGE("IDvr is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mDvr->configure(getHidlDvrSettings(in_settings));
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDvr::attachFilter(const shared_ptr<ITunerFilter>& in_filter) {
+    if (mDvr == nullptr) {
+        ALOGE("IDvr is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    if (in_filter == nullptr) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    sp<HidlIFilter> hidlFilter = static_cast<TunerHidlFilter*>(in_filter.get())->getHalFilter();
+    if (hidlFilter == nullptr) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    HidlResult res = mDvr->attachFilter(hidlFilter);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDvr::detachFilter(const shared_ptr<ITunerFilter>& in_filter) {
+    if (mDvr == nullptr) {
+        ALOGE("IDvr is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    if (in_filter == nullptr) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    sp<HidlIFilter> halFilter = (static_cast<TunerHidlFilter*>(in_filter.get()))->getHalFilter();
+    if (halFilter == nullptr) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    HidlResult res = mDvr->detachFilter(halFilter);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDvr::start() {
+    if (mDvr == nullptr) {
+        ALOGE("IDvr is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mDvr->start();
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDvr::stop() {
+    if (mDvr == nullptr) {
+        ALOGE("IDvr is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mDvr->stop();
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDvr::flush() {
+    if (mDvr == nullptr) {
+        ALOGE("IDvr is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mDvr->flush();
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlDvr::close() {
+    if (mDvr == nullptr) {
+        ALOGE("IDvr is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mDvr->close();
+    mDvr = nullptr;
+
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+HidlDvrSettings TunerHidlDvr::getHidlDvrSettings(const DvrSettings& settings) {
+    HidlDvrSettings s;
+    switch (mType) {
+    case DvrType::PLAYBACK: {
+        s.playback({
+                .statusMask =
+                        static_cast<uint8_t>(settings.get<DvrSettings::playback>().statusMask),
+                .lowThreshold =
+                        static_cast<uint32_t>(settings.get<DvrSettings::playback>().lowThreshold),
+                .highThreshold =
+                        static_cast<uint32_t>(settings.get<DvrSettings::playback>().highThreshold),
+                .dataFormat = static_cast<HidlDataFormat>(
+                        settings.get<DvrSettings::playback>().dataFormat),
+                .packetSize =
+                        static_cast<uint8_t>(settings.get<DvrSettings::playback>().packetSize),
+        });
+        return s;
+    }
+    case DvrType::RECORD: {
+        s.record({
+                .statusMask = static_cast<uint8_t>(settings.get<DvrSettings::record>().statusMask),
+                .lowThreshold =
+                        static_cast<uint32_t>(settings.get<DvrSettings::record>().lowThreshold),
+                .highThreshold =
+                        static_cast<uint32_t>(settings.get<DvrSettings::record>().highThreshold),
+                .dataFormat =
+                        static_cast<HidlDataFormat>(settings.get<DvrSettings::record>().dataFormat),
+                .packetSize = static_cast<uint8_t>(settings.get<DvrSettings::record>().packetSize),
+        });
+        return s;
+    }
+    default:
+        break;
+    }
+    return s;
+}
+
+/////////////// IDvrCallback ///////////////////////
+Return<void> TunerHidlDvr::DvrCallback::onRecordStatus(const HidlRecordStatus status) {
+    if (mTunerDvrCallback != nullptr) {
+        mTunerDvrCallback->onRecordStatus(static_cast<RecordStatus>(status));
+    }
+    return Void();
+}
+
+Return<void> TunerHidlDvr::DvrCallback::onPlaybackStatus(const HidlPlaybackStatus status) {
+    if (mTunerDvrCallback != nullptr) {
+        mTunerDvrCallback->onPlaybackStatus(static_cast<PlaybackStatus>(status));
+    }
+    return Void();
+}
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
diff --git a/services/tuner/hidl/TunerHidlDvr.h b/services/tuner/hidl/TunerHidlDvr.h
new file mode 100644
index 0000000..a280ff7
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlDvr.h
@@ -0,0 +1,91 @@
+/**
+ * Copyright 2021, 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_MEDIA_TUNERHIDLDVR_H
+#define ANDROID_MEDIA_TUNERHIDLDVR_H
+
+#include <aidl/android/hardware/tv/tuner/DvrSettings.h>
+#include <aidl/android/hardware/tv/tuner/DvrType.h>
+#include <aidl/android/media/tv/tuner/BnTunerDvr.h>
+#include <aidl/android/media/tv/tuner/ITunerDvrCallback.h>
+#include <android/hardware/tv/tuner/1.0/IDvr.h>
+#include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
+
+#include "TunerHidlFilter.h"
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::tv::tuner::DvrSettings;
+using ::aidl::android::hardware::tv::tuner::DvrType;
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::std::shared_ptr;
+using ::std::vector;
+
+using HidlDvrSettings = ::android::hardware::tv::tuner::V1_0::DvrSettings;
+using HidlIDvr = ::android::hardware::tv::tuner::V1_0::IDvr;
+using HidlIDvrCallback = ::android::hardware::tv::tuner::V1_0::IDvrCallback;
+using HidlPlaybackStatus = ::android::hardware::tv::tuner::V1_0::PlaybackStatus;
+using HidlRecordStatus = ::android::hardware::tv::tuner::V1_0::RecordStatus;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+using AidlMQDesc = MQDescriptor<int8_t, SynchronizedReadWrite>;
+
+class TunerHidlDvr : public BnTunerDvr {
+public:
+    TunerHidlDvr(sp<HidlIDvr> dvr, DvrType type);
+    ~TunerHidlDvr();
+
+    ::ndk::ScopedAStatus getQueueDesc(AidlMQDesc* _aidl_return) override;
+    ::ndk::ScopedAStatus configure(const DvrSettings& in_settings) override;
+    ::ndk::ScopedAStatus attachFilter(const shared_ptr<ITunerFilter>& in_filter) override;
+    ::ndk::ScopedAStatus detachFilter(const shared_ptr<ITunerFilter>& in_filter) override;
+    ::ndk::ScopedAStatus start() override;
+    ::ndk::ScopedAStatus stop() override;
+    ::ndk::ScopedAStatus flush() override;
+    ::ndk::ScopedAStatus close() override;
+
+    struct DvrCallback : public HidlIDvrCallback {
+        DvrCallback(const shared_ptr<ITunerDvrCallback> tunerDvrCallback)
+              : mTunerDvrCallback(tunerDvrCallback){};
+
+        virtual Return<void> onRecordStatus(const HidlRecordStatus status);
+        virtual Return<void> onPlaybackStatus(const HidlPlaybackStatus status);
+
+    private:
+        shared_ptr<ITunerDvrCallback> mTunerDvrCallback;
+    };
+
+private:
+    HidlDvrSettings getHidlDvrSettings(const DvrSettings& settings);
+
+    sp<HidlIDvr> mDvr;
+    DvrType mType;
+};
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
+
+#endif  // ANDROID_MEDIA_TUNERHIDLDVR_H
diff --git a/services/tuner/hidl/TunerHidlFilter.cpp b/services/tuner/hidl/TunerHidlFilter.cpp
new file mode 100644
index 0000000..1573c8e
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlFilter.cpp
@@ -0,0 +1,1002 @@
+/**
+ * Copyright 2021, 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 "TunerHidlFilter"
+
+#include "TunerHidlFilter.h"
+
+#include <aidl/android/hardware/tv/tuner/Constant.h>
+#include <aidl/android/hardware/tv/tuner/Result.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <fmq/ConvertMQDescriptors.h>
+
+using ::aidl::android::hardware::tv::tuner::AudioExtraMetaData;
+using ::aidl::android::hardware::tv::tuner::Constant;
+using ::aidl::android::hardware::tv::tuner::DemuxAlpFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxAlpFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterDownloadEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterIpPayloadEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMainType;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMediaEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMediaEventExtraMetaData;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMmtpRecordEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterMonitorEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterPesEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterScIndexMask;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionBits;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionSettingsCondition;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionSettingsConditionTableInfo;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSubType;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterTemiEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterTsRecordEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxIpAddress;
+using ::aidl::android::hardware::tv::tuner::DemuxIpAddressIpAddress;
+using ::aidl::android::hardware::tv::tuner::DemuxIpFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxIpFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxMmtpFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxMmtpFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxMmtpFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxPid;
+using ::aidl::android::hardware::tv::tuner::DemuxTlvFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTlvFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTsFilterSettingsFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxTsFilterType;
+using ::aidl::android::hardware::tv::tuner::Result;
+using ::aidl::android::hardware::tv::tuner::ScramblingStatus;
+using ::android::dupToAidl;
+using ::android::makeFromAidl;
+using ::android::unsafeHidlToAidlMQDescriptor;
+using ::android::hardware::hidl_handle;
+
+using HidlDemuxAlpLengthType = ::android::hardware::tv::tuner::V1_0::DemuxAlpLengthType;
+using HidlDemuxFilterMainType = ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using HidlDemuxIpAddress = ::android::hardware::tv::tuner::V1_0::DemuxIpAddress;
+using HidlDemuxMmtpFilterType = ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterType;
+using HidlDemuxMmtpPid = ::android::hardware::tv::tuner::V1_0::DemuxMmtpPid;
+using HidlDemuxRecordScIndexType = ::android::hardware::tv::tuner::V1_0::DemuxRecordScIndexType;
+using HidlDemuxStreamId = ::android::hardware::tv::tuner::V1_0::DemuxStreamId;
+using HidlDemuxTsFilterType = ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
+using HidlResult = ::android::hardware::tv::tuner::V1_0::Result;
+using HidlAudioStreamType = ::android::hardware::tv::tuner::V1_1::AudioStreamType;
+using HidlConstant = ::android::hardware::tv::tuner::V1_1::Constant;
+using HidlVideoStreamType = ::android::hardware::tv::tuner::V1_1::VideoStreamType;
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+TunerHidlFilter::TunerHidlFilter(sp<HidlIFilter> filter, DemuxFilterType type)
+      : mFilter(filter), mType(type) {
+    mFilter_1_1 = ::android::hardware::tv::tuner::V1_1::IFilter::castFrom(filter);
+}
+
+TunerHidlFilter::~TunerHidlFilter() {
+    mFilter = nullptr;
+    mFilter_1_1 = nullptr;
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::getQueueDesc(AidlMQDesc* _aidl_return) {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    MQDesc filterMQDesc;
+    HidlResult res;
+    mFilter->getQueueDesc([&](HidlResult r, const MQDesc& desc) {
+        filterMQDesc = desc;
+        res = r;
+    });
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    AidlMQDesc aidlMQDesc;
+    unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(filterMQDesc, &aidlMQDesc);
+    *_aidl_return = move(aidlMQDesc);
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::getId(int32_t* _aidl_return) {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res;
+    mFilter->getId([&](HidlResult r, uint32_t filterId) {
+        res = r;
+        mId = filterId;
+    });
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    *_aidl_return = mId;
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::getId64Bit(int64_t* _aidl_return) {
+    if (mFilter_1_1 == nullptr) {
+        ALOGE("IFilter_1_1 is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res;
+    mFilter_1_1->getId64Bit([&](HidlResult r, uint64_t filterId) {
+        res = r;
+        mId64Bit = filterId;
+    });
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    *_aidl_return = mId64Bit;
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::configure(const DemuxFilterSettings& in_settings) {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlDemuxFilterSettings settings;
+    switch (in_settings.getTag()) {
+    case DemuxFilterSettings::ts: {
+        getHidlTsSettings(in_settings, settings);
+        break;
+    }
+    case DemuxFilterSettings::mmtp: {
+        getHidlMmtpSettings(in_settings, settings);
+        break;
+    }
+    case DemuxFilterSettings::ip: {
+        getHidlIpSettings(in_settings, settings);
+        break;
+    }
+    case DemuxFilterSettings::tlv: {
+        getHidlTlvSettings(in_settings, settings);
+        break;
+    }
+    case DemuxFilterSettings::alp: {
+        getHidlAlpSettings(in_settings, settings);
+        break;
+    }
+    }
+
+    HidlResult res = mFilter->configure(settings);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::configureMonitorEvent(int32_t monitorEventType) {
+    if (mFilter_1_1 == nullptr) {
+        ALOGE("IFilter_1_1 is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mFilter_1_1->configureMonitorEvent(monitorEventType);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::configureIpFilterContextId(int32_t cid) {
+    if (mFilter_1_1 == nullptr) {
+        ALOGE("IFilter_1_1 is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mFilter_1_1->configureIpCid(cid);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::configureAvStreamType(const AvStreamType& in_avStreamType) {
+    if (mFilter_1_1 == nullptr) {
+        ALOGE("IFilter_1_1 is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlAvStreamType type;
+    if (!getHidlAvStreamType(in_avStreamType, type)) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_STATE));
+    }
+
+    HidlResult res = mFilter_1_1->configureAvStreamType(type);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::setDataSource(const shared_ptr<ITunerFilter>& filter) {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    if (filter == nullptr) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    sp<HidlIFilter> hidlFilter = static_cast<TunerHidlFilter*>(filter.get())->getHalFilter();
+    HidlResult res = mFilter->setDataSource(hidlFilter);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::getAvSharedHandle(NativeHandle* out_avMemory,
+                                                        int64_t* _aidl_return) {
+    if (mFilter_1_1 == nullptr) {
+        ALOGE("IFilter_1_1 is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res;
+    mFilter_1_1->getAvSharedHandle([&](HidlResult r, hidl_handle avMemory, uint64_t avMemSize) {
+        res = r;
+        if (res == HidlResult::SUCCESS) {
+            *out_avMemory = dupToAidl(avMemory);
+            *_aidl_return = static_cast<int64_t>(avMemSize);
+        } else {
+            _aidl_return = nullptr;
+        }
+    });
+
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::releaseAvHandle(const NativeHandle& in_handle,
+                                                      int64_t in_avDataId) {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mFilter->releaseAvHandle(hidl_handle(makeFromAidl(in_handle)), in_avDataId);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::start() {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mFilter->start();
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::stop() {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mFilter->stop();
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::flush() {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mFilter->flush();
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFilter::close() {
+    if (mFilter == nullptr) {
+        ALOGE("IFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mFilter->close();
+    mFilter = nullptr;
+    mFilter_1_1 = nullptr;
+
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+sp<HidlIFilter> TunerHidlFilter::getHalFilter() {
+    return mFilter;
+}
+
+bool TunerHidlFilter::getHidlAvStreamType(const AvStreamType avStreamType, HidlAvStreamType& type) {
+    if (isAudioFilter()) {
+        type.audio(static_cast<HidlAudioStreamType>(avStreamType.get<AvStreamType::audio>()));
+        return true;
+    }
+
+    if (isVideoFilter()) {
+        type.video(static_cast<HidlVideoStreamType>(avStreamType.get<AvStreamType::video>()));
+        return true;
+    }
+
+    return false;
+}
+
+bool TunerHidlFilter::isAudioFilter() {
+    return (mType.mainType == DemuxFilterMainType::TS &&
+            mType.subType.get<DemuxFilterSubType::tsFilterType>() == DemuxTsFilterType::AUDIO) ||
+           (mType.mainType == DemuxFilterMainType::MMTP &&
+            mType.subType.get<DemuxFilterSubType::mmtpFilterType>() == DemuxMmtpFilterType::AUDIO);
+}
+
+bool TunerHidlFilter::isVideoFilter() {
+    return (mType.mainType == DemuxFilterMainType::TS &&
+            mType.subType.get<DemuxFilterSubType::tsFilterType>() == DemuxTsFilterType::VIDEO) ||
+           (mType.mainType == DemuxFilterMainType::MMTP &&
+            mType.subType.get<DemuxFilterSubType::mmtpFilterType>() == DemuxMmtpFilterType::VIDEO);
+}
+
+void TunerHidlFilter::getHidlTsSettings(const DemuxFilterSettings& settings,
+                                        HidlDemuxFilterSettings& hidlSettings) {
+    const DemuxTsFilterSettings& tsConf = settings.get<DemuxFilterSettings::ts>();
+    HidlDemuxTsFilterSettings ts{
+            .tpid = static_cast<uint16_t>(tsConf.tpid),
+    };
+
+    switch (tsConf.filterSettings.getTag()) {
+    case DemuxTsFilterSettingsFilterSettings::av: {
+        ts.filterSettings.av(getHidlAvSettings(
+                tsConf.filterSettings.get<DemuxTsFilterSettingsFilterSettings::av>()));
+        break;
+    }
+    case DemuxTsFilterSettingsFilterSettings::section: {
+        ts.filterSettings.section(getHidlSectionSettings(
+                tsConf.filterSettings.get<DemuxTsFilterSettingsFilterSettings::section>()));
+        break;
+    }
+    case DemuxTsFilterSettingsFilterSettings::pesData: {
+        ts.filterSettings.pesData(getHidlPesDataSettings(
+                tsConf.filterSettings.get<DemuxTsFilterSettingsFilterSettings::pesData>()));
+        break;
+    }
+    case DemuxTsFilterSettingsFilterSettings::record: {
+        ts.filterSettings.record(getHidlRecordSettings(
+                tsConf.filterSettings.get<DemuxTsFilterSettingsFilterSettings::record>()));
+        break;
+    }
+    default: {
+        ts.filterSettings.noinit();
+        break;
+    }
+    }
+    hidlSettings.ts(ts);
+}
+
+void TunerHidlFilter::getHidlMmtpSettings(const DemuxFilterSettings& settings,
+                                          HidlDemuxFilterSettings& hidlSettings) {
+    const DemuxMmtpFilterSettings& mmtpConf = settings.get<DemuxFilterSettings::mmtp>();
+    HidlDemuxMmtpFilterSettings mmtp{
+            .mmtpPid = static_cast<HidlDemuxMmtpPid>(mmtpConf.mmtpPid),
+    };
+
+    switch (mmtpConf.filterSettings.getTag()) {
+    case DemuxMmtpFilterSettingsFilterSettings::av: {
+        mmtp.filterSettings.av(getHidlAvSettings(
+                mmtpConf.filterSettings.get<DemuxMmtpFilterSettingsFilterSettings::av>()));
+        break;
+    }
+    case DemuxMmtpFilterSettingsFilterSettings::section: {
+        mmtp.filterSettings.section(getHidlSectionSettings(
+                mmtpConf.filterSettings.get<DemuxMmtpFilterSettingsFilterSettings::section>()));
+        break;
+    }
+    case DemuxMmtpFilterSettingsFilterSettings::pesData: {
+        mmtp.filterSettings.pesData(getHidlPesDataSettings(
+                mmtpConf.filterSettings.get<DemuxMmtpFilterSettingsFilterSettings::pesData>()));
+        break;
+    }
+    case DemuxMmtpFilterSettingsFilterSettings::record: {
+        mmtp.filterSettings.record(getHidlRecordSettings(
+                mmtpConf.filterSettings.get<DemuxMmtpFilterSettingsFilterSettings::record>()));
+        break;
+    }
+    case DemuxMmtpFilterSettingsFilterSettings::download: {
+        mmtp.filterSettings.download(getHidlDownloadSettings(
+                mmtpConf.filterSettings.get<DemuxMmtpFilterSettingsFilterSettings::download>()));
+        break;
+    }
+    default: {
+        mmtp.filterSettings.noinit();
+        break;
+    }
+    }
+    hidlSettings.mmtp(mmtp);
+}
+
+void TunerHidlFilter::getHidlIpSettings(const DemuxFilterSettings& settings,
+                                        HidlDemuxFilterSettings& hidlSettings) {
+    const DemuxIpFilterSettings& ipConf = settings.get<DemuxFilterSettings::ip>();
+    HidlDemuxIpAddress ipAddr{
+            .srcPort = static_cast<uint16_t>(ipConf.ipAddr.srcPort),
+            .dstPort = static_cast<uint16_t>(ipConf.ipAddr.dstPort),
+    };
+
+    ipConf.ipAddr.srcIpAddress.getTag() == DemuxIpAddressIpAddress::v6
+            ? ipAddr.srcIpAddress.v6(getIpV6Address(ipConf.ipAddr.srcIpAddress))
+            : ipAddr.srcIpAddress.v4(getIpV4Address(ipConf.ipAddr.srcIpAddress));
+    ipConf.ipAddr.dstIpAddress.getTag() == DemuxIpAddressIpAddress::v6
+            ? ipAddr.dstIpAddress.v6(getIpV6Address(ipConf.ipAddr.dstIpAddress))
+            : ipAddr.dstIpAddress.v4(getIpV4Address(ipConf.ipAddr.dstIpAddress));
+
+    HidlDemuxIpFilterSettings ip;
+    ip.ipAddr = ipAddr;
+
+    switch (ipConf.filterSettings.getTag()) {
+    case DemuxIpFilterSettingsFilterSettings::section: {
+        ip.filterSettings.section(getHidlSectionSettings(
+                ipConf.filterSettings.get<DemuxIpFilterSettingsFilterSettings::section>()));
+        break;
+    }
+    case DemuxIpFilterSettingsFilterSettings::bPassthrough: {
+        ip.filterSettings.bPassthrough(
+                ipConf.filterSettings.get<DemuxIpFilterSettingsFilterSettings::bPassthrough>());
+        break;
+    }
+    default: {
+        ip.filterSettings.noinit();
+        break;
+    }
+    }
+    hidlSettings.ip(ip);
+}
+
+hidl_array<uint8_t, IP_V6_LENGTH> TunerHidlFilter::getIpV6Address(
+        const DemuxIpAddressIpAddress& addr) {
+    hidl_array<uint8_t, IP_V6_LENGTH> ip;
+    if (addr.get<DemuxIpAddressIpAddress::v6>().size() != IP_V6_LENGTH) {
+        return ip;
+    }
+    copy(addr.get<DemuxIpAddressIpAddress::v6>().begin(),
+         addr.get<DemuxIpAddressIpAddress::v6>().end(), ip.data());
+    return ip;
+}
+
+hidl_array<uint8_t, IP_V4_LENGTH> TunerHidlFilter::getIpV4Address(
+        const DemuxIpAddressIpAddress& addr) {
+    hidl_array<uint8_t, IP_V4_LENGTH> ip;
+    if (addr.get<DemuxIpAddressIpAddress::v4>().size() != IP_V4_LENGTH) {
+        return ip;
+    }
+    copy(addr.get<DemuxIpAddressIpAddress::v4>().begin(),
+         addr.get<DemuxIpAddressIpAddress::v4>().end(), ip.data());
+    return ip;
+}
+
+void TunerHidlFilter::getHidlTlvSettings(const DemuxFilterSettings& settings,
+                                         HidlDemuxFilterSettings& hidlSettings) {
+    const DemuxTlvFilterSettings& tlvConf = settings.get<DemuxFilterSettings::tlv>();
+    HidlDemuxTlvFilterSettings tlv{
+            .packetType = static_cast<uint8_t>(tlvConf.packetType),
+            .isCompressedIpPacket = tlvConf.isCompressedIpPacket,
+    };
+
+    switch (tlvConf.filterSettings.getTag()) {
+    case DemuxTlvFilterSettingsFilterSettings::section: {
+        tlv.filterSettings.section(getHidlSectionSettings(
+                tlvConf.filterSettings.get<DemuxTlvFilterSettingsFilterSettings::section>()));
+        break;
+    }
+    case DemuxTlvFilterSettingsFilterSettings::bPassthrough: {
+        tlv.filterSettings.bPassthrough(
+                tlvConf.filterSettings.get<DemuxTlvFilterSettingsFilterSettings::bPassthrough>());
+        break;
+    }
+    default: {
+        tlv.filterSettings.noinit();
+        break;
+    }
+    }
+    hidlSettings.tlv(tlv);
+}
+
+void TunerHidlFilter::getHidlAlpSettings(const DemuxFilterSettings& settings,
+                                         HidlDemuxFilterSettings& hidlSettings) {
+    const DemuxAlpFilterSettings& alpConf = settings.get<DemuxFilterSettings::alp>();
+    HidlDemuxAlpFilterSettings alp{
+            .packetType = static_cast<uint8_t>(alpConf.packetType),
+            .lengthType = static_cast<HidlDemuxAlpLengthType>(alpConf.lengthType),
+    };
+
+    switch (alpConf.filterSettings.getTag()) {
+    case DemuxAlpFilterSettingsFilterSettings::section: {
+        alp.filterSettings.section(getHidlSectionSettings(
+                alpConf.filterSettings.get<DemuxAlpFilterSettingsFilterSettings::section>()));
+        break;
+    }
+    default: {
+        alp.filterSettings.noinit();
+        break;
+    }
+    }
+    hidlSettings.alp(alp);
+}
+
+HidlDemuxFilterAvSettings TunerHidlFilter::getHidlAvSettings(
+        const DemuxFilterAvSettings& settings) {
+    HidlDemuxFilterAvSettings av{
+            .isPassthrough = settings.isPassthrough,
+    };
+    return av;
+}
+
+HidlDemuxFilterSectionSettings TunerHidlFilter::getHidlSectionSettings(
+        const DemuxFilterSectionSettings& settings) {
+    HidlDemuxFilterSectionSettings section{
+            .isCheckCrc = settings.isCheckCrc,
+            .isRepeat = settings.isRepeat,
+            .isRaw = settings.isRaw,
+    };
+
+    switch (settings.condition.getTag()) {
+    case DemuxFilterSectionSettingsCondition::sectionBits: {
+        const DemuxFilterSectionBits& sectionBits =
+                settings.condition.get<DemuxFilterSectionSettingsCondition::sectionBits>();
+        vector<uint8_t> filter(sectionBits.filter.begin(), sectionBits.filter.end());
+        vector<uint8_t> mask(sectionBits.mask.begin(), sectionBits.mask.end());
+        vector<uint8_t> mode(sectionBits.mode.begin(), sectionBits.mode.end());
+        section.condition.sectionBits({
+                .filter = filter,
+                .mask = mask,
+                .mode = mode,
+        });
+        break;
+    }
+    case DemuxFilterSectionSettingsCondition::tableInfo: {
+        const DemuxFilterSectionSettingsConditionTableInfo& tableInfo =
+                settings.condition.get<DemuxFilterSectionSettingsCondition::tableInfo>();
+        section.condition.tableInfo({
+                .tableId = static_cast<uint16_t>(tableInfo.tableId),
+                .version = static_cast<uint16_t>(tableInfo.version),
+        });
+        break;
+    }
+    default: {
+        break;
+    }
+    }
+    return section;
+}
+
+HidlDemuxFilterPesDataSettings TunerHidlFilter::getHidlPesDataSettings(
+        const DemuxFilterPesDataSettings& settings) {
+    HidlDemuxFilterPesDataSettings pes{
+            .streamId = static_cast<HidlDemuxStreamId>(settings.streamId),
+            .isRaw = settings.isRaw,
+    };
+    return pes;
+}
+
+HidlDemuxFilterRecordSettings TunerHidlFilter::getHidlRecordSettings(
+        const DemuxFilterRecordSettings& settings) {
+    HidlDemuxFilterRecordSettings record{
+            .tsIndexMask = static_cast<uint32_t>(settings.tsIndexMask),
+            .scIndexType = static_cast<HidlDemuxRecordScIndexType>(settings.scIndexType),
+    };
+
+    switch (settings.scIndexMask.getTag()) {
+    case DemuxFilterScIndexMask::scIndex: {
+        record.scIndexMask.sc(
+                static_cast<uint32_t>(settings.scIndexMask.get<DemuxFilterScIndexMask::scIndex>()));
+        break;
+    }
+    case DemuxFilterScIndexMask::scHevc: {
+        record.scIndexMask.scHevc(
+                static_cast<uint32_t>(settings.scIndexMask.get<DemuxFilterScIndexMask::scHevc>()));
+        break;
+    }
+    }
+    return record;
+}
+
+HidlDemuxFilterDownloadSettings TunerHidlFilter::getHidlDownloadSettings(
+        const DemuxFilterDownloadSettings& settings) {
+    HidlDemuxFilterDownloadSettings download{
+            .downloadId = static_cast<uint32_t>(settings.downloadId),
+    };
+    return download;
+}
+
+/////////////// FilterCallback ///////////////////////
+Return<void> TunerHidlFilter::FilterCallback::onFilterStatus(HidlDemuxFilterStatus status) {
+    if (mTunerFilterCallback != NULL) {
+        mTunerFilterCallback->onFilterStatus(static_cast<DemuxFilterStatus>(status));
+    }
+    return Void();
+}
+
+Return<void> TunerHidlFilter::FilterCallback::onFilterEvent(
+        const HidlDemuxFilterEvent& filterEvent) {
+    vector<HidlDemuxFilterEventExt::Event> emptyEventsExt;
+    HidlDemuxFilterEventExt emptyFilterEventExt{
+            .events = emptyEventsExt,
+    };
+    onFilterEvent_1_1(filterEvent, emptyFilterEventExt);
+    return Void();
+}
+
+Return<void> TunerHidlFilter::FilterCallback::onFilterEvent_1_1(
+        const HidlDemuxFilterEvent& filterEvent, const HidlDemuxFilterEventExt& filterEventExt) {
+    if (mTunerFilterCallback != NULL) {
+        vector<HidlDemuxFilterEvent::Event> events = filterEvent.events;
+        vector<HidlDemuxFilterEventExt::Event> eventsExt = filterEventExt.events;
+        vector<DemuxFilterEvent> tunerEvents;
+
+        getAidlFilterEvent(events, eventsExt, tunerEvents);
+        mTunerFilterCallback->onFilterEvent(tunerEvents);
+    }
+    return Void();
+}
+
+/////////////// FilterCallback Helper Methods ///////////////////////
+void TunerHidlFilter::FilterCallback::getAidlFilterEvent(
+        const vector<HidlDemuxFilterEvent::Event>& events,
+        const vector<HidlDemuxFilterEventExt::Event>& eventsExt,
+        vector<DemuxFilterEvent>& aidlEvents) {
+    if (events.empty() && !eventsExt.empty()) {
+        switch (eventsExt[0].getDiscriminator()) {
+        case HidlDemuxFilterEventExt::Event::hidl_discriminator::monitorEvent: {
+            getMonitorEvent(eventsExt, aidlEvents);
+            break;
+        }
+        case HidlDemuxFilterEventExt::Event::hidl_discriminator::startId: {
+            getRestartEvent(eventsExt, aidlEvents);
+            break;
+        }
+        default: {
+            break;
+        }
+        }
+    }
+
+    if (!events.empty()) {
+        switch (events[0].getDiscriminator()) {
+        case HidlDemuxFilterEvent::Event::hidl_discriminator::media: {
+            getMediaEvent(events, aidlEvents);
+            break;
+        }
+        case HidlDemuxFilterEvent::Event::hidl_discriminator::section: {
+            getSectionEvent(events, aidlEvents);
+            break;
+        }
+        case HidlDemuxFilterEvent::Event::hidl_discriminator::pes: {
+            getPesEvent(events, aidlEvents);
+            break;
+        }
+        case HidlDemuxFilterEvent::Event::hidl_discriminator::tsRecord: {
+            getTsRecordEvent(events, eventsExt, aidlEvents);
+            break;
+        }
+        case HidlDemuxFilterEvent::Event::hidl_discriminator::mmtpRecord: {
+            getMmtpRecordEvent(events, eventsExt, aidlEvents);
+            break;
+        }
+        case HidlDemuxFilterEvent::Event::hidl_discriminator::download: {
+            getDownloadEvent(events, aidlEvents);
+            break;
+        }
+        case HidlDemuxFilterEvent::Event::hidl_discriminator::ipPayload: {
+            getIpPayloadEvent(events, aidlEvents);
+            break;
+        }
+        case HidlDemuxFilterEvent::Event::hidl_discriminator::temi: {
+            getTemiEvent(events, aidlEvents);
+            break;
+        }
+        default: {
+            break;
+        }
+        }
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getMediaEvent(
+        const vector<HidlDemuxFilterEvent::Event>& events, vector<DemuxFilterEvent>& res) {
+    for (int i = 0; i < events.size(); i++) {
+        const HidlDemuxFilterMediaEvent& mediaEvent = events[i].media();
+        DemuxFilterMediaEvent media;
+
+        media.streamId = static_cast<int32_t>(mediaEvent.streamId);
+        media.isPtsPresent = mediaEvent.isPtsPresent;
+        media.pts = static_cast<int64_t>(mediaEvent.pts);
+        media.dataLength = static_cast<int64_t>(mediaEvent.dataLength);
+        media.offset = static_cast<int64_t>(mediaEvent.offset);
+        media.isSecureMemory = mediaEvent.isSecureMemory;
+        media.avDataId = static_cast<int64_t>(mediaEvent.avDataId);
+        media.mpuSequenceNumber = static_cast<int32_t>(mediaEvent.mpuSequenceNumber);
+        media.isPesPrivateData = mediaEvent.isPesPrivateData;
+
+        if (mediaEvent.extraMetaData.getDiscriminator() ==
+            HidlDemuxFilterMediaEvent::ExtraMetaData::hidl_discriminator::audio) {
+            AudioExtraMetaData audio;
+            audio.adFade = static_cast<int8_t>(mediaEvent.extraMetaData.audio().adFade);
+            audio.adPan = static_cast<int8_t>(mediaEvent.extraMetaData.audio().adPan);
+            audio.versionTextTag =
+                    static_cast<int16_t>(mediaEvent.extraMetaData.audio().versionTextTag);
+            audio.adGainCenter = static_cast<int8_t>(mediaEvent.extraMetaData.audio().adGainCenter);
+            audio.adGainFront = static_cast<int8_t>(mediaEvent.extraMetaData.audio().adGainFront);
+            audio.adGainSurround =
+                    static_cast<int8_t>(mediaEvent.extraMetaData.audio().adGainSurround);
+            media.extraMetaData.set<DemuxFilterMediaEventExtraMetaData::audio>(audio);
+        } else {
+            media.extraMetaData.set<DemuxFilterMediaEventExtraMetaData::noinit>(true);
+        }
+
+        if (mediaEvent.avMemory.getNativeHandle() != nullptr) {
+            media.avMemory = dupToAidl(mediaEvent.avMemory.getNativeHandle());
+        }
+
+        DemuxFilterEvent filterEvent;
+        filterEvent.set<DemuxFilterEvent::media>(move(media));
+        res.push_back(move(filterEvent));
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getSectionEvent(
+        const vector<HidlDemuxFilterEvent::Event>& events, vector<DemuxFilterEvent>& res) {
+    for (int i = 0; i < events.size(); i++) {
+        const HidlDemuxFilterSectionEvent& sectionEvent = events[i].section();
+        DemuxFilterSectionEvent section;
+
+        section.tableId = static_cast<int32_t>(sectionEvent.tableId);
+        section.version = static_cast<int32_t>(sectionEvent.version);
+        section.sectionNum = static_cast<int32_t>(sectionEvent.sectionNum);
+        section.dataLength = static_cast<int32_t>(sectionEvent.dataLength);
+
+        DemuxFilterEvent filterEvent;
+        filterEvent.set<DemuxFilterEvent::section>(move(section));
+        res.push_back(move(filterEvent));
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getPesEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                                                  vector<DemuxFilterEvent>& res) {
+    for (int i = 0; i < events.size(); i++) {
+        const HidlDemuxFilterPesEvent& pesEvent = events[i].pes();
+        DemuxFilterPesEvent pes;
+
+        pes.streamId = static_cast<int32_t>(pesEvent.streamId);
+        pes.dataLength = static_cast<int32_t>(pesEvent.dataLength);
+        pes.mpuSequenceNumber = static_cast<int32_t>(pesEvent.mpuSequenceNumber);
+
+        DemuxFilterEvent filterEvent;
+        filterEvent.set<DemuxFilterEvent::pes>(move(pes));
+        res.push_back(move(filterEvent));
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getTsRecordEvent(
+        const vector<HidlDemuxFilterEvent::Event>& events,
+        const vector<HidlDemuxFilterEventExt::Event>& eventsExt, vector<DemuxFilterEvent>& res) {
+    for (int i = 0; i < events.size(); i++) {
+        DemuxFilterTsRecordEvent tsRecord;
+        const HidlDemuxFilterTsRecordEvent& tsRecordEvent = events[i].tsRecord();
+
+        DemuxFilterScIndexMask scIndexMask;
+        if (tsRecordEvent.scIndexMask.getDiscriminator() ==
+            HidlDemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::sc) {
+            scIndexMask.set<DemuxFilterScIndexMask::scIndex>(
+                    static_cast<int32_t>(tsRecordEvent.scIndexMask.sc()));
+        } else if (tsRecordEvent.scIndexMask.getDiscriminator() ==
+                   HidlDemuxFilterTsRecordEvent::ScIndexMask::hidl_discriminator::scHevc) {
+            scIndexMask.set<DemuxFilterScIndexMask::scHevc>(
+                    static_cast<int32_t>(tsRecordEvent.scIndexMask.scHevc()));
+        }
+
+        if (tsRecordEvent.pid.getDiscriminator() == HidlDemuxPid::hidl_discriminator::tPid) {
+            DemuxPid pid;
+            pid.set<DemuxPid::tPid>(static_cast<int32_t>(tsRecordEvent.pid.tPid()));
+            tsRecord.pid = pid;
+        } else {
+            DemuxPid pid;
+            pid.set<DemuxPid::tPid>(static_cast<int32_t>(Constant::INVALID_TS_PID));
+            tsRecord.pid = pid;
+        }
+
+        tsRecord.scIndexMask = scIndexMask;
+        tsRecord.tsIndexMask = static_cast<int32_t>(tsRecordEvent.tsIndexMask);
+        tsRecord.byteNumber = static_cast<int64_t>(tsRecordEvent.byteNumber);
+
+        if (eventsExt.size() > i &&
+            eventsExt[i].getDiscriminator() ==
+                    HidlDemuxFilterEventExt::Event::hidl_discriminator::tsRecord) {
+            tsRecord.pts = static_cast<int64_t>(eventsExt[i].tsRecord().pts);
+            tsRecord.firstMbInSlice = static_cast<int32_t>(eventsExt[i].tsRecord().firstMbInSlice);
+        }
+
+        DemuxFilterEvent filterEvent;
+        filterEvent.set<DemuxFilterEvent::tsRecord>(move(tsRecord));
+        res.push_back(move(filterEvent));
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getMmtpRecordEvent(
+        const vector<HidlDemuxFilterEvent::Event>& events,
+        const vector<HidlDemuxFilterEventExt::Event>& eventsExt, vector<DemuxFilterEvent>& res) {
+    for (int i = 0; i < events.size(); i++) {
+        DemuxFilterMmtpRecordEvent mmtpRecord;
+        const HidlDemuxFilterMmtpRecordEvent& mmtpRecordEvent = events[i].mmtpRecord();
+
+        mmtpRecord.scHevcIndexMask = static_cast<int32_t>(mmtpRecordEvent.scHevcIndexMask);
+        mmtpRecord.byteNumber = static_cast<int64_t>(mmtpRecordEvent.byteNumber);
+
+        if (eventsExt.size() > i &&
+            eventsExt[i].getDiscriminator() ==
+                    HidlDemuxFilterEventExt::Event::hidl_discriminator::mmtpRecord) {
+            mmtpRecord.pts = static_cast<int64_t>(eventsExt[i].mmtpRecord().pts);
+            mmtpRecord.mpuSequenceNumber =
+                    static_cast<int32_t>(eventsExt[i].mmtpRecord().mpuSequenceNumber);
+            mmtpRecord.firstMbInSlice =
+                    static_cast<int32_t>(eventsExt[i].mmtpRecord().firstMbInSlice);
+            mmtpRecord.tsIndexMask = static_cast<int32_t>(eventsExt[i].mmtpRecord().tsIndexMask);
+        }
+
+        DemuxFilterEvent filterEvent;
+        filterEvent.set<DemuxFilterEvent::mmtpRecord>(move(mmtpRecord));
+        res.push_back(move(filterEvent));
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getDownloadEvent(
+        const vector<HidlDemuxFilterEvent::Event>& events, vector<DemuxFilterEvent>& res) {
+    for (int i = 0; i < events.size(); i++) {
+        const HidlDemuxFilterDownloadEvent& downloadEvent = events[i].download();
+        DemuxFilterDownloadEvent download;
+
+        download.itemId = static_cast<int32_t>(downloadEvent.itemId);
+        download.itemFragmentIndex = static_cast<int32_t>(downloadEvent.itemFragmentIndex);
+        download.mpuSequenceNumber = static_cast<int32_t>(downloadEvent.mpuSequenceNumber);
+        download.lastItemFragmentIndex = static_cast<int32_t>(downloadEvent.lastItemFragmentIndex);
+        download.dataLength = static_cast<int32_t>(downloadEvent.dataLength);
+
+        DemuxFilterEvent filterEvent;
+        filterEvent.set<DemuxFilterEvent::download>(move(download));
+        res.push_back(move(filterEvent));
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getIpPayloadEvent(
+        const vector<HidlDemuxFilterEvent::Event>& events, vector<DemuxFilterEvent>& res) {
+    for (int i = 0; i < events.size(); i++) {
+        const HidlDemuxFilterIpPayloadEvent& ipPayloadEvent = events[i].ipPayload();
+        DemuxFilterIpPayloadEvent ipPayload;
+
+        ipPayload.dataLength = static_cast<int32_t>(ipPayloadEvent.dataLength);
+
+        DemuxFilterEvent filterEvent;
+        filterEvent.set<DemuxFilterEvent::ipPayload>(move(ipPayload));
+        res.push_back(move(filterEvent));
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getTemiEvent(
+        const vector<HidlDemuxFilterEvent::Event>& events, vector<DemuxFilterEvent>& res) {
+    for (int i = 0; i < events.size(); i++) {
+        const HidlDemuxFilterTemiEvent& temiEvent = events[i].temi();
+        DemuxFilterTemiEvent temi;
+
+        temi.pts = static_cast<int64_t>(temiEvent.pts);
+        temi.descrTag = static_cast<int8_t>(temiEvent.descrTag);
+        vector<uint8_t> descrData = temiEvent.descrData;
+        temi.descrData.resize(descrData.size());
+        copy(descrData.begin(), descrData.end(), temi.descrData.begin());
+
+        DemuxFilterEvent filterEvent;
+        filterEvent.set<DemuxFilterEvent::temi>(move(temi));
+        res.push_back(move(filterEvent));
+    }
+}
+
+void TunerHidlFilter::FilterCallback::getMonitorEvent(
+        const vector<HidlDemuxFilterEventExt::Event>& eventsExt, vector<DemuxFilterEvent>& res) {
+    HidlDemuxFilterMonitorEvent monitorEvent = eventsExt[0].monitorEvent();
+    DemuxFilterMonitorEvent monitor;
+
+    switch (monitorEvent.getDiscriminator()) {
+    case HidlDemuxFilterMonitorEvent::hidl_discriminator::scramblingStatus: {
+        monitor.set<DemuxFilterMonitorEvent::scramblingStatus>(
+                static_cast<ScramblingStatus>(monitorEvent.scramblingStatus()));
+        break;
+    }
+    case HidlDemuxFilterMonitorEvent::hidl_discriminator::cid: {
+        monitor.set<DemuxFilterMonitorEvent::cid>(static_cast<int32_t>(monitorEvent.cid()));
+        break;
+    }
+    }
+
+    DemuxFilterEvent filterEvent;
+    filterEvent.set<DemuxFilterEvent::monitorEvent>(move(monitor));
+    res.push_back(move(filterEvent));
+}
+
+void TunerHidlFilter::FilterCallback::getRestartEvent(
+        const vector<HidlDemuxFilterEventExt::Event>& eventsExt, vector<DemuxFilterEvent>& res) {
+    DemuxFilterEvent filterEvent;
+    filterEvent.set<DemuxFilterEvent::startId>(static_cast<int32_t>(eventsExt[0].startId()));
+    res.push_back(move(filterEvent));
+}
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
diff --git a/services/tuner/hidl/TunerHidlFilter.h b/services/tuner/hidl/TunerHidlFilter.h
new file mode 100644
index 0000000..0111e00
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlFilter.h
@@ -0,0 +1,215 @@
+/**
+ * Copyright 2021, 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_MEDIA_TUNERHIDLFILTER_H
+#define ANDROID_MEDIA_TUNERHIDLFILTER_H
+
+#include <aidl/android/hardware/tv/tuner/AvStreamType.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterAvSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterDownloadSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterPesDataSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterRecordSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSectionSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterSettings.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterStatus.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterType.h>
+#include <aidl/android/media/tv/tuner/BnTunerFilter.h>
+#include <aidl/android/media/tv/tuner/ITunerFilterCallback.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.1/IFilter.h>
+#include <android/hardware/tv/tuner/1.1/IFilterCallback.h>
+#include <android/hardware/tv/tuner/1.1/types.h>
+#include <fmq/MessageQueue.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+using ::aidl::android::hardware::common::NativeHandle;
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::aidl::android::hardware::tv::tuner::AvStreamType;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterAvSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterDownloadSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterPesDataSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterRecordSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSectionSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterSettings;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterType;
+using ::aidl::android::hardware::tv::tuner::DemuxIpAddressIpAddress;
+using ::aidl::android::media::tv::tuner::BnTunerFilter;
+using ::aidl::android::media::tv::tuner::ITunerFilterCallback;
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::MQDescriptorSync;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::std::shared_ptr;
+using ::std::vector;
+
+using HidlAvStreamType = ::android::hardware::tv::tuner::V1_1::AvStreamType;
+using HidlDemuxAlpFilterSettings = ::android::hardware::tv::tuner::V1_0::DemuxAlpFilterSettings;
+using HidlDemuxFilterAvSettings = ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
+using HidlDemuxFilterDownloadEvent = ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadEvent;
+using HidlDemuxFilterDownloadSettings =
+        ::android::hardware::tv::tuner::V1_0::DemuxFilterDownloadSettings;
+using HidlDemuxFilterIpPayloadEvent =
+        ::android::hardware::tv::tuner::V1_0::DemuxFilterIpPayloadEvent;
+using HidlDemuxFilterEvent = ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using HidlDemuxFilterMediaEvent = ::android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
+using HidlDemuxFilterMmtpRecordEvent =
+        ::android::hardware::tv::tuner::V1_0::DemuxFilterMmtpRecordEvent;
+using HidlDemuxFilterPesDataSettings =
+        ::android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
+using HidlDemuxFilterPesEvent = ::android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
+using HidlDemuxFilterRecordSettings =
+        ::android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
+using HidlDemuxFilterSectionEvent = ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionEvent;
+using HidlDemuxFilterSectionSettings =
+        ::android::hardware::tv::tuner::V1_0::DemuxFilterSectionSettings;
+using HidlDemuxFilterSettings = ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
+using HidlDemuxFilterStatus = ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using HidlDemuxFilterTemiEvent = ::android::hardware::tv::tuner::V1_0::DemuxFilterTemiEvent;
+using HidlDemuxFilterTsRecordEvent = ::android::hardware::tv::tuner::V1_0::DemuxFilterTsRecordEvent;
+using HidlDemuxIpFilterSettings = ::android::hardware::tv::tuner::V1_0::DemuxIpFilterSettings;
+using HidlDemuxMmtpFilterSettings = ::android::hardware::tv::tuner::V1_0::DemuxMmtpFilterSettings;
+using HidlDemuxTlvFilterSettings = ::android::hardware::tv::tuner::V1_0::DemuxTlvFilterSettings;
+using HidlDemuxTsFilterSettings = ::android::hardware::tv::tuner::V1_0::DemuxTsFilterSettings;
+using HidlDemuxPid = ::android::hardware::tv::tuner::V1_0::DemuxPid;
+using HidlIFilter = ::android::hardware::tv::tuner::V1_0::IFilter;
+using HidlDvStreamType = ::android::hardware::tv::tuner::V1_1::AvStreamType;
+using HidlDemuxFilterEventExt = ::android::hardware::tv::tuner::V1_1::DemuxFilterEventExt;
+using HidlDemuxFilterMonitorEvent = ::android::hardware::tv::tuner::V1_1::DemuxFilterMonitorEvent;
+using HidlDemuxFilterTsRecordEventExt =
+        ::android::hardware::tv::tuner::V1_1::DemuxFilterTsRecordEventExt;
+using HidlIFilterCallback = ::android::hardware::tv::tuner::V1_1::IFilterCallback;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+using MQDesc = MQDescriptorSync<uint8_t>;
+using AidlMQDesc = MQDescriptor<int8_t, SynchronizedReadWrite>;
+
+const static int IP_V4_LENGTH = 4;
+const static int IP_V6_LENGTH = 16;
+
+class TunerHidlFilter : public BnTunerFilter {
+public:
+    TunerHidlFilter(sp<HidlIFilter> filter, DemuxFilterType type);
+    virtual ~TunerHidlFilter();
+
+    ::ndk::ScopedAStatus getId(int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getId64Bit(int64_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getQueueDesc(AidlMQDesc* _aidl_return) override;
+    ::ndk::ScopedAStatus configure(const DemuxFilterSettings& in_settings) override;
+    ::ndk::ScopedAStatus configureMonitorEvent(int32_t in_monitorEventTypes) override;
+    ::ndk::ScopedAStatus configureIpFilterContextId(int32_t in_cid) override;
+    ::ndk::ScopedAStatus configureAvStreamType(const AvStreamType& in_avStreamType) override;
+    ::ndk::ScopedAStatus getAvSharedHandle(NativeHandle* out_avMemory,
+                                           int64_t* _aidl_return) override;
+    ::ndk::ScopedAStatus releaseAvHandle(const NativeHandle& in_handle,
+                                         int64_t in_avDataId) override;
+    ::ndk::ScopedAStatus setDataSource(const shared_ptr<ITunerFilter>& in_filter) override;
+    ::ndk::ScopedAStatus start() override;
+    ::ndk::ScopedAStatus stop() override;
+    ::ndk::ScopedAStatus flush() override;
+    ::ndk::ScopedAStatus close() override;
+
+    sp<HidlIFilter> getHalFilter();
+
+    struct FilterCallback : public HidlIFilterCallback {
+        FilterCallback(const shared_ptr<ITunerFilterCallback> tunerFilterCallback)
+              : mTunerFilterCallback(tunerFilterCallback){};
+
+        virtual Return<void> onFilterEvent(const HidlDemuxFilterEvent& filterEvent);
+        virtual Return<void> onFilterEvent_1_1(const HidlDemuxFilterEvent& filterEvent,
+                                               const HidlDemuxFilterEventExt& filterEventExt);
+        virtual Return<void> onFilterStatus(HidlDemuxFilterStatus status);
+
+        void getAidlFilterEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                                const vector<HidlDemuxFilterEventExt::Event>& eventsExt,
+                                vector<DemuxFilterEvent>& aidlEvents);
+
+        void getMediaEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                           vector<DemuxFilterEvent>& res);
+        void getSectionEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                             vector<DemuxFilterEvent>& res);
+        void getPesEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                         vector<DemuxFilterEvent>& res);
+        void getTsRecordEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                              const vector<HidlDemuxFilterEventExt::Event>& eventsExt,
+                              vector<DemuxFilterEvent>& res);
+        void getMmtpRecordEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                                const vector<HidlDemuxFilterEventExt::Event>& eventsExt,
+                                vector<DemuxFilterEvent>& res);
+        void getDownloadEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                              vector<DemuxFilterEvent>& res);
+        void getIpPayloadEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                               vector<DemuxFilterEvent>& res);
+        void getTemiEvent(const vector<HidlDemuxFilterEvent::Event>& events,
+                          vector<DemuxFilterEvent>& res);
+        void getMonitorEvent(const vector<HidlDemuxFilterEventExt::Event>& eventsExt,
+                             vector<DemuxFilterEvent>& res);
+        void getRestartEvent(const vector<HidlDemuxFilterEventExt::Event>& eventsExt,
+                             vector<DemuxFilterEvent>& res);
+
+        shared_ptr<ITunerFilterCallback> mTunerFilterCallback;
+    };
+
+private:
+    bool isAudioFilter();
+    bool isVideoFilter();
+
+    HidlDemuxFilterAvSettings getHidlAvSettings(const DemuxFilterAvSettings& settings);
+    HidlDemuxFilterSectionSettings getHidlSectionSettings(
+            const DemuxFilterSectionSettings& settings);
+    HidlDemuxFilterPesDataSettings getHidlPesDataSettings(
+            const DemuxFilterPesDataSettings& settings);
+    HidlDemuxFilterRecordSettings getHidlRecordSettings(const DemuxFilterRecordSettings& settings);
+    HidlDemuxFilterDownloadSettings getHidlDownloadSettings(
+            const DemuxFilterDownloadSettings& settings);
+    bool getHidlAvStreamType(const AvStreamType avStreamType, HidlAvStreamType& type);
+    void getHidlTsSettings(const DemuxFilterSettings& settings,
+                           HidlDemuxFilterSettings& hidlSettings);
+    void getHidlMmtpSettings(const DemuxFilterSettings& settings,
+                             HidlDemuxFilterSettings& hidlSettings);
+    void getHidlIpSettings(const DemuxFilterSettings& settings,
+                           HidlDemuxFilterSettings& hidlSettings);
+    void getHidlTlvSettings(const DemuxFilterSettings& settings,
+                            HidlDemuxFilterSettings& hidlSettings);
+    void getHidlAlpSettings(const DemuxFilterSettings& settings,
+                            HidlDemuxFilterSettings& hidlSettings);
+
+    hidl_array<uint8_t, IP_V4_LENGTH> getIpV4Address(const DemuxIpAddressIpAddress& addr);
+    hidl_array<uint8_t, IP_V6_LENGTH> getIpV6Address(const DemuxIpAddressIpAddress& addr);
+
+    sp<HidlIFilter> mFilter;
+    sp<::android::hardware::tv::tuner::V1_1::IFilter> mFilter_1_1;
+    int32_t mId;
+    int64_t mId64Bit;
+    DemuxFilterType mType;
+};
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
+
+#endif  // ANDROID_MEDIA_TUNERHIDLFILTER_H
diff --git a/services/tuner/hidl/TunerHidlFrontend.cpp b/services/tuner/hidl/TunerHidlFrontend.cpp
new file mode 100644
index 0000000..bbfc90f
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlFrontend.cpp
@@ -0,0 +1,1201 @@
+/**
+ * Copyright 2021, 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_NDEBUG 0
+#define LOG_TAG "TunerHidlFrontend"
+
+#include "TunerHidlFrontend.h"
+
+#include <aidl/android/hardware/tv/tuner/Result.h>
+
+#include "TunerHidlLnb.h"
+
+using ::aidl::android::hardware::tv::tuner::FrontendAnalogSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendAnalogSifStandard;
+using ::aidl::android::hardware::tv::tuner::FrontendAnalogType;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Bandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3CodeRate;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Fec;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Modulation;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3PlpSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Settings;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3TimeInterleaveMode;
+using ::aidl::android::hardware::tv::tuner::FrontendAtscModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendAtscSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendCableTimeInterleaveMode;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbGuardInterval;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbTimeInterleaveMode;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbTransmissionMode;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcAnnex;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsRolloff;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsStandard;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtConstellation;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtGuardInterval;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtHierarchy;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtStandard;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtTransmissionMode;
+using ::aidl::android::hardware::tv::tuner::FrontendGuardInterval;
+using ::aidl::android::hardware::tv::tuner::FrontendInnerFec;
+using ::aidl::android::hardware::tv::tuner::FrontendInterleaveMode;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Modulation;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Rolloff;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Settings;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsRolloff;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtBandwidth;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtCoderate;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtGuardInterval;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtMode;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendModulation;
+using ::aidl::android::hardware::tv::tuner::FrontendModulationStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendRollOff;
+using ::aidl::android::hardware::tv::tuner::FrontendScanAtsc3PlpInfo;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessageStandard;
+using ::aidl::android::hardware::tv::tuner::FrontendSpectralInversion;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusAtsc3PlpInfo;
+using ::aidl::android::hardware::tv::tuner::FrontendTransmissionMode;
+using ::aidl::android::hardware::tv::tuner::Result;
+
+using HidlFrontendStatusAtsc3PlpInfo =
+        ::aidl::android::hardware::tv::tuner::FrontendStatusAtsc3PlpInfo;
+using HidlFrontendAnalogSifStandard =
+        ::android::hardware::tv::tuner::V1_0::FrontendAnalogSifStandard;
+using HidlFrontendAnalogType = ::android::hardware::tv::tuner::V1_0::FrontendAnalogType;
+using HidlFrontendAtscModulation = ::android::hardware::tv::tuner::V1_0::FrontendAtscModulation;
+using HidlFrontendAtsc3Bandwidth = ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Bandwidth;
+using HidlFrontendAtsc3CodeRate = ::android::hardware::tv::tuner::V1_0::FrontendAtsc3CodeRate;
+using HidlFrontendAtsc3DemodOutputFormat =
+        ::android::hardware::tv::tuner::V1_0::FrontendAtsc3DemodOutputFormat;
+using HidlFrontendAtsc3Fec = ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Fec;
+using HidlFrontendAtsc3Modulation = ::android::hardware::tv::tuner::V1_0::FrontendAtsc3Modulation;
+using HidlFrontendAtsc3TimeInterleaveMode =
+        ::android::hardware::tv::tuner::V1_0::FrontendAtsc3TimeInterleaveMode;
+using HidlFrontendDvbcAnnex = ::android::hardware::tv::tuner::V1_0::FrontendDvbcAnnex;
+using HidlFrontendDvbcModulation = ::android::hardware::tv::tuner::V1_0::FrontendDvbcModulation;
+using HidlFrontendDvbcOuterFec = ::android::hardware::tv::tuner::V1_0::FrontendDvbcOuterFec;
+using HidlFrontendDvbcSpectralInversion =
+        ::android::hardware::tv::tuner::V1_0::FrontendDvbcSpectralInversion;
+using HidlFrontendDvbsModulation = ::android::hardware::tv::tuner::V1_0::FrontendDvbsModulation;
+using HidlFrontendDvbsPilot = ::android::hardware::tv::tuner::V1_0::FrontendDvbsPilot;
+using HidlFrontendDvbsRolloff = ::android::hardware::tv::tuner::V1_0::FrontendDvbsRolloff;
+using HidlFrontendDvbsSettings = ::android::hardware::tv::tuner::V1_0::FrontendDvbsSettings;
+using HidlFrontendDvbsStandard = ::android::hardware::tv::tuner::V1_0::FrontendDvbsStandard;
+using HidlFrontendDvbsVcmMode = ::android::hardware::tv::tuner::V1_0::FrontendDvbsVcmMode;
+using HidlFrontendDvbtBandwidth = ::android::hardware::tv::tuner::V1_0::FrontendDvbtBandwidth;
+using HidlFrontendDvbtCoderate = ::android::hardware::tv::tuner::V1_0::FrontendDvbtCoderate;
+using HidlFrontendDvbtConstellation =
+        ::android::hardware::tv::tuner::V1_0::FrontendDvbtConstellation;
+using HidlFrontendDvbtGuardInterval =
+        ::android::hardware::tv::tuner::V1_0::FrontendDvbtGuardInterval;
+using HidlFrontendDvbtHierarchy = ::android::hardware::tv::tuner::V1_0::FrontendDvbtHierarchy;
+using HidlFrontendDvbtPlpMode = ::android::hardware::tv::tuner::V1_0::FrontendDvbtPlpMode;
+using HidlFrontendDvbtSettings = ::android::hardware::tv::tuner::V1_0::FrontendDvbtSettings;
+using HidlFrontendDvbtStandard = ::android::hardware::tv::tuner::V1_0::FrontendDvbtStandard;
+using HidlFrontendDvbtTransmissionMode =
+        ::android::hardware::tv::tuner::V1_0::FrontendDvbtTransmissionMode;
+using HidlFrontendInnerFec = ::android::hardware::tv::tuner::V1_0::FrontendInnerFec;
+using HidlFrontendIsdbs3Coderate = ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Coderate;
+using HidlFrontendIsdbs3Modulation = ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Modulation;
+using HidlFrontendIsdbs3Rolloff = ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Rolloff;
+using HidlFrontendIsdbs3Settings = ::android::hardware::tv::tuner::V1_0::FrontendIsdbs3Settings;
+using HidlFrontendIsdbsCoderate = ::android::hardware::tv::tuner::V1_0::FrontendIsdbsCoderate;
+using HidlFrontendIsdbsModulation = ::android::hardware::tv::tuner::V1_0::FrontendIsdbsModulation;
+using HidlFrontendIsdbsRolloff = ::android::hardware::tv::tuner::V1_0::FrontendIsdbsRolloff;
+using HidlFrontendIsdbsSettings = ::android::hardware::tv::tuner::V1_0::FrontendIsdbsSettings;
+using HidlFrontendIsdbsStreamIdType =
+        ::android::hardware::tv::tuner::V1_0::FrontendIsdbsStreamIdType;
+using HidlFrontendIsdbtBandwidth = ::android::hardware::tv::tuner::V1_0::FrontendIsdbtBandwidth;
+using HidlFrontendIsdbtCoderate = ::android::hardware::tv::tuner::V1_0::FrontendIsdbtCoderate;
+using HidlFrontendIsdbtGuardInterval =
+        ::android::hardware::tv::tuner::V1_0::FrontendIsdbtGuardInterval;
+using HidlFrontendIsdbtMode = ::android::hardware::tv::tuner::V1_0::FrontendIsdbtMode;
+using HidlFrontendIsdbtModulation = ::android::hardware::tv::tuner::V1_0::FrontendIsdbtModulation;
+using HidlFrontendIsdbtSettings = ::android::hardware::tv::tuner::V1_0::FrontendIsdbtSettings;
+using HidlFrontendModulationStatus = ::android::hardware::tv::tuner::V1_0::FrontendModulationStatus;
+using HidlFrontendScanAtsc3PlpInfo = ::android::hardware::tv::tuner::V1_0::FrontendScanAtsc3PlpInfo;
+using HidlFrontendScanType = ::android::hardware::tv::tuner::V1_0::FrontendScanType;
+using HidlFrontendStatusType = ::android::hardware::tv::tuner::V1_0::FrontendStatusType;
+using HidlResult = ::android::hardware::tv::tuner::V1_0::Result;
+using HidlFrontendAnalogAftFlag = ::android::hardware::tv::tuner::V1_1::FrontendAnalogAftFlag;
+using HidlFrontendBandwidth = ::android::hardware::tv::tuner::V1_1::FrontendBandwidth;
+using HidlFrontendCableTimeInterleaveMode =
+        ::android::hardware::tv::tuner::V1_1::FrontendCableTimeInterleaveMode;
+using HidlFrontendDvbcBandwidth = ::android::hardware::tv::tuner::V1_1::FrontendDvbcBandwidth;
+using HidlFrontendDtmbBandwidth = ::android::hardware::tv::tuner::V1_1::FrontendDtmbBandwidth;
+using HidlFrontendDtmbCodeRate = ::android::hardware::tv::tuner::V1_1::FrontendDtmbCodeRate;
+using HidlFrontendDtmbGuardInterval =
+        ::android::hardware::tv::tuner::V1_1::FrontendDtmbGuardInterval;
+using HidlFrontendDtmbModulation = ::android::hardware::tv::tuner::V1_1::FrontendDtmbModulation;
+using HidlFrontendDtmbTimeInterleaveMode =
+        ::android::hardware::tv::tuner::V1_1::FrontendDtmbTimeInterleaveMode;
+using HidlFrontendDtmbTransmissionMode =
+        ::android::hardware::tv::tuner::V1_1::FrontendDtmbTransmissionMode;
+using HidlFrontendDvbsScanType = ::android::hardware::tv::tuner::V1_1::FrontendDvbsScanType;
+using HidlFrontendGuardInterval = ::android::hardware::tv::tuner::V1_1::FrontendGuardInterval;
+using HidlFrontendInterleaveMode = ::android::hardware::tv::tuner::V1_1::FrontendInterleaveMode;
+using HidlFrontendModulation = ::android::hardware::tv::tuner::V1_1::FrontendModulation;
+using HidlFrontendRollOff = ::android::hardware::tv::tuner::V1_1::FrontendRollOff;
+using HidlFrontendTransmissionMode = ::android::hardware::tv::tuner::V1_1::FrontendTransmissionMode;
+using HidlFrontendSpectralInversion =
+        ::android::hardware::tv::tuner::V1_1::FrontendSpectralInversion;
+using HidlFrontendStatusTypeExt1_1 = ::android::hardware::tv::tuner::V1_1::FrontendStatusTypeExt1_1;
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+TunerHidlFrontend::TunerHidlFrontend(sp<HidlIFrontend> frontend, int id) {
+    mFrontend = frontend;
+    mFrontend_1_1 = ::android::hardware::tv::tuner::V1_1::IFrontend::castFrom(mFrontend);
+    mId = id;
+}
+
+TunerHidlFrontend::~TunerHidlFrontend() {
+    mFrontend = nullptr;
+    mFrontend_1_1 = nullptr;
+    mId = -1;
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::setCallback(
+        const shared_ptr<ITunerFrontendCallback>& tunerFrontendCallback) {
+    if (mFrontend == nullptr) {
+        ALOGE("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    if (tunerFrontendCallback == nullptr) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    sp<HidlIFrontendCallback> frontendCallback = new FrontendCallback(tunerFrontendCallback);
+    HidlResult status = mFrontend->setCallback(frontendCallback);
+    if (status == HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::tune(const FrontendSettings& settings) {
+    if (mFrontend == nullptr) {
+        ALOGE("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status;
+    HidlFrontendSettings frontendSettings;
+    HidlFrontendSettingsExt1_1 frontendSettingsExt;
+    getHidlFrontendSettings(settings, frontendSettings, frontendSettingsExt);
+    if (mFrontend_1_1 != nullptr) {
+        status = mFrontend_1_1->tune_1_1(frontendSettings, frontendSettingsExt);
+    } else {
+        status = mFrontend->tune(frontendSettings);
+    }
+    if (status == HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::stopTune() {
+    if (mFrontend == nullptr) {
+        ALOGD("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mFrontend->stopTune();
+    if (status == HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::scan(const FrontendSettings& settings,
+                                             FrontendScanType frontendScanType) {
+    if (mFrontend == nullptr) {
+        ALOGD("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status;
+    HidlFrontendSettings frontendSettings;
+    HidlFrontendSettingsExt1_1 frontendSettingsExt;
+    getHidlFrontendSettings(settings, frontendSettings, frontendSettingsExt);
+    if (mFrontend_1_1 != nullptr) {
+        status = mFrontend_1_1->scan_1_1(frontendSettings,
+                                         static_cast<HidlFrontendScanType>(frontendScanType),
+                                         frontendSettingsExt);
+    } else {
+        status = mFrontend->scan(frontendSettings,
+                                 static_cast<HidlFrontendScanType>(frontendScanType));
+    }
+    if (status == HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::stopScan() {
+    if (mFrontend == nullptr) {
+        ALOGD("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mFrontend->stopScan();
+    if (status == HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::setLnb(const shared_ptr<ITunerLnb>& lnb) {
+    if (mFrontend == nullptr) {
+        ALOGD("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    if (lnb == nullptr) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    HidlResult status = mFrontend->setLnb(static_cast<TunerHidlLnb*>(lnb.get())->getId());
+    if (status == HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::setLna(bool bEnable) {
+    if (mFrontend == nullptr) {
+        ALOGD("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mFrontend->setLna(bEnable);
+    if (status == HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::linkCiCamToFrontend(int32_t ciCamId,
+                                                            int32_t* _aidl_return) {
+    if (mFrontend_1_1 == nullptr) {
+        ALOGD("IFrontend_1_1 is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    int ltsId;
+    HidlResult status;
+    mFrontend_1_1->linkCiCam(static_cast<uint32_t>(ciCamId), [&](HidlResult r, uint32_t id) {
+        status = r;
+        ltsId = id;
+    });
+
+    if (status == HidlResult::SUCCESS) {
+        *_aidl_return = ltsId;
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::unlinkCiCamToFrontend(int32_t ciCamId) {
+    if (mFrontend_1_1 == nullptr) {
+        ALOGD("IFrontend_1_1 is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mFrontend_1_1->unlinkCiCam(ciCamId);
+    if (status == HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::close() {
+    if (mFrontend == nullptr) {
+        ALOGD("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mFrontend->close();
+    mFrontend = nullptr;
+    mFrontend_1_1 = nullptr;
+
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::getStatus(const vector<FrontendStatusType>& in_statusTypes,
+                                                  vector<FrontendStatus>* _aidl_return) {
+    if (mFrontend == nullptr) {
+        ALOGD("IFrontend is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res;
+    vector<HidlFrontendStatus> status;
+    vector<HidlFrontendStatusExt1_1> statusExt;
+    vector<HidlFrontendStatusType> types;
+    vector<HidlFrontendStatusTypeExt1_1> typesExt;
+    for (auto s : in_statusTypes) {
+        if (static_cast<int32_t>(s) <=
+            static_cast<int32_t>(HidlFrontendStatusType::ATSC3_PLP_INFO)) {
+            types.push_back(static_cast<HidlFrontendStatusType>(s));
+        } else {
+            typesExt.push_back(static_cast<HidlFrontendStatusTypeExt1_1>(s));
+        }
+    }
+
+    mFrontend->getStatus(types, [&](HidlResult r, const hidl_vec<HidlFrontendStatus>& ss) {
+        res = r;
+        for (auto s : ss) {
+            status.push_back(s);
+        }
+    });
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    if (mFrontend_1_1 != nullptr) {
+        mFrontend_1_1->getStatusExt1_1(
+                typesExt, [&](HidlResult r, const hidl_vec<HidlFrontendStatusExt1_1>& ss) {
+                    res = r;
+                    for (auto s : ss) {
+                        statusExt.push_back(s);
+                    }
+                });
+        if (res != HidlResult::SUCCESS) {
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+        }
+    }
+
+    getAidlFrontendStatus(status, statusExt, *_aidl_return);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlFrontend::getFrontendId(int32_t* _aidl_return) {
+    *_aidl_return = mId;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+/////////////// FrontendCallback ///////////////////////
+Return<void> TunerHidlFrontend::FrontendCallback::onEvent(HidlFrontendEventType frontendEventType) {
+    ALOGV("FrontendCallback::onEvent, type=%d", frontendEventType);
+    mTunerFrontendCallback->onEvent(static_cast<FrontendEventType>(frontendEventType));
+    return Void();
+}
+
+Return<void> TunerHidlFrontend::FrontendCallback::onScanMessage(
+        HidlFrontendScanMessageType type, const HidlFrontendScanMessage& message) {
+    ALOGV("FrontendCallback::onScanMessage, type=%d", type);
+    FrontendScanMessage scanMessage;
+    switch (type) {
+    case HidlFrontendScanMessageType::LOCKED: {
+        scanMessage.set<FrontendScanMessage::isLocked>(message.isLocked());
+        break;
+    }
+    case HidlFrontendScanMessageType::END: {
+        scanMessage.set<FrontendScanMessage::isEnd>(message.isEnd());
+        break;
+    }
+    case HidlFrontendScanMessageType::PROGRESS_PERCENT: {
+        scanMessage.set<FrontendScanMessage::progressPercent>(message.progressPercent());
+        break;
+    }
+    case HidlFrontendScanMessageType::FREQUENCY: {
+        const vector<uint32_t>& f = message.frequencies();
+        vector<int64_t> lf(begin(f), end(f));
+        scanMessage.set<FrontendScanMessage::frequencies>(lf);
+        break;
+    }
+    case HidlFrontendScanMessageType::SYMBOL_RATE: {
+        const vector<uint32_t>& s = message.symbolRates();
+        vector<int32_t> symbolRates(begin(s), end(s));
+        scanMessage.set<FrontendScanMessage::symbolRates>(symbolRates);
+        break;
+    }
+    case HidlFrontendScanMessageType::HIERARCHY: {
+        scanMessage.set<FrontendScanMessage::hierarchy>(
+                static_cast<FrontendDvbtHierarchy>(message.hierarchy()));
+        break;
+    }
+    case HidlFrontendScanMessageType::ANALOG_TYPE: {
+        scanMessage.set<FrontendScanMessage::analogType>(
+                static_cast<FrontendAnalogType>(message.analogType()));
+        break;
+    }
+    case HidlFrontendScanMessageType::PLP_IDS: {
+        const vector<uint8_t>& p = message.plpIds();
+        vector<int32_t> plpIds(begin(p), end(p));
+        scanMessage.set<FrontendScanMessage::plpIds>(plpIds);
+        break;
+    }
+    case HidlFrontendScanMessageType::GROUP_IDS: {
+        const vector<uint8_t>& g = message.groupIds();
+        vector<int32_t> groupIds(begin(g), end(g));
+        scanMessage.set<FrontendScanMessage::groupIds>(groupIds);
+        break;
+    }
+    case HidlFrontendScanMessageType::INPUT_STREAM_IDS: {
+        const vector<uint16_t>& i = message.inputStreamIds();
+        vector<int32_t> streamIds(begin(i), end(i));
+        scanMessage.set<FrontendScanMessage::inputStreamIds>(streamIds);
+        break;
+    }
+    case HidlFrontendScanMessageType::STANDARD: {
+        const HidlFrontendScanMessage::Standard& std = message.std();
+        FrontendScanMessageStandard standard;
+        if (std.getDiscriminator() == HidlFrontendScanMessage::Standard::hidl_discriminator::sStd) {
+            standard.set<FrontendScanMessageStandard::sStd>(
+                    static_cast<FrontendDvbsStandard>(std.sStd()));
+        } else if (std.getDiscriminator() ==
+                   HidlFrontendScanMessage::Standard::hidl_discriminator::tStd) {
+            standard.set<FrontendScanMessageStandard::tStd>(
+                    static_cast<FrontendDvbtStandard>(std.tStd()));
+        } else if (std.getDiscriminator() ==
+                   HidlFrontendScanMessage::Standard::hidl_discriminator::sifStd) {
+            standard.set<FrontendScanMessageStandard::sifStd>(
+                    static_cast<FrontendAnalogSifStandard>(std.sifStd()));
+        }
+        scanMessage.set<FrontendScanMessage::std>(standard);
+        break;
+    }
+    case HidlFrontendScanMessageType::ATSC3_PLP_INFO: {
+        const vector<HidlFrontendScanAtsc3PlpInfo>& plpInfos = message.atsc3PlpInfos();
+        vector<FrontendScanAtsc3PlpInfo> tunerPlpInfos;
+        for (int i = 0; i < plpInfos.size(); i++) {
+            FrontendScanAtsc3PlpInfo plpInfo{
+                    .plpId = static_cast<int32_t>(plpInfos[i].plpId),
+                    .bLlsFlag = plpInfos[i].bLlsFlag,
+            };
+            tunerPlpInfos.push_back(plpInfo);
+        }
+        scanMessage.set<FrontendScanMessage::atsc3PlpInfos>(tunerPlpInfos);
+        break;
+    }
+    default:
+        break;
+    }
+    mTunerFrontendCallback->onScanMessage(static_cast<FrontendScanMessageType>(type), scanMessage);
+    return Void();
+}
+
+Return<void> TunerHidlFrontend::FrontendCallback::onScanMessageExt1_1(
+        HidlFrontendScanMessageTypeExt1_1 type, const HidlFrontendScanMessageExt1_1& message) {
+    ALOGV("onScanMessageExt1_1::onScanMessage, type=%d", type);
+    FrontendScanMessage scanMessage;
+    switch (type) {
+    case HidlFrontendScanMessageTypeExt1_1::MODULATION: {
+        HidlFrontendModulation m = message.modulation();
+        FrontendModulation modulation;
+        switch (m.getDiscriminator()) {
+        case HidlFrontendModulation::hidl_discriminator::dvbc: {
+            modulation.set<FrontendModulation::dvbc>(static_cast<FrontendDvbcModulation>(m.dvbc()));
+            break;
+        }
+        case HidlFrontendModulation::hidl_discriminator::dvbt: {
+            modulation.set<FrontendModulation::dvbt>(
+                    static_cast<FrontendDvbtConstellation>(m.dvbt()));
+            break;
+        }
+        case HidlFrontendModulation::hidl_discriminator::dvbs: {
+            modulation.set<FrontendModulation::dvbs>(static_cast<FrontendDvbsModulation>(m.dvbs()));
+            break;
+        }
+        case HidlFrontendModulation::hidl_discriminator::isdbs: {
+            modulation.set<FrontendModulation::isdbs>(
+                    static_cast<FrontendIsdbsModulation>(m.isdbs()));
+            break;
+        }
+        case HidlFrontendModulation::hidl_discriminator::isdbs3: {
+            modulation.set<FrontendModulation::isdbs3>(
+                    static_cast<FrontendIsdbs3Modulation>(m.isdbs3()));
+            break;
+        }
+        case HidlFrontendModulation::hidl_discriminator::isdbt: {
+            modulation.set<FrontendModulation::isdbt>(
+                    static_cast<FrontendIsdbtModulation>(m.isdbt()));
+            break;
+        }
+        case HidlFrontendModulation::hidl_discriminator::atsc: {
+            modulation.set<FrontendModulation::atsc>(static_cast<FrontendAtscModulation>(m.atsc()));
+            break;
+        }
+        case HidlFrontendModulation::hidl_discriminator::atsc3: {
+            modulation.set<FrontendModulation::atsc3>(
+                    static_cast<FrontendAtsc3Modulation>(m.atsc3()));
+            break;
+        }
+        case HidlFrontendModulation::hidl_discriminator::dtmb: {
+            modulation.set<FrontendModulation::dtmb>(static_cast<FrontendDtmbModulation>(m.dtmb()));
+            break;
+        }
+        }
+        scanMessage.set<FrontendScanMessage::modulation>(modulation);
+        break;
+    }
+    case HidlFrontendScanMessageTypeExt1_1::DVBC_ANNEX: {
+        scanMessage.set<FrontendScanMessage::annex>(
+                static_cast<FrontendDvbcAnnex>(message.annex()));
+        break;
+    }
+    case HidlFrontendScanMessageTypeExt1_1::HIGH_PRIORITY: {
+        scanMessage.set<FrontendScanMessage::isHighPriority>(message.isHighPriority());
+        break;
+    }
+    default: {
+        break;
+    }
+    }
+    mTunerFrontendCallback->onScanMessage(static_cast<FrontendScanMessageType>(type), scanMessage);
+    return Void();
+}
+
+/////////////// TunerHidlFrontend Helper Methods ///////////////////////
+void TunerHidlFrontend::getAidlFrontendStatus(const vector<HidlFrontendStatus>& hidlStatus,
+                                              const vector<HidlFrontendStatusExt1_1>& hidlStatusExt,
+                                              vector<FrontendStatus>& aidlStatus) {
+    for (HidlFrontendStatus s : hidlStatus) {
+        FrontendStatus status;
+        switch (s.getDiscriminator()) {
+        case HidlFrontendStatus::hidl_discriminator::isDemodLocked: {
+            status.set<FrontendStatus::isDemodLocked>(s.isDemodLocked());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::snr: {
+            status.set<FrontendStatus::snr>((int)s.snr());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::ber: {
+            status.set<FrontendStatus::ber>((int)s.ber());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::per: {
+            status.set<FrontendStatus::per>((int)s.per());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::preBer: {
+            status.set<FrontendStatus::preBer>((int)s.preBer());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::signalQuality: {
+            status.set<FrontendStatus::signalQuality>((int)s.signalQuality());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::signalStrength: {
+            status.set<FrontendStatus::signalStrength>((int)s.signalStrength());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::symbolRate: {
+            status.set<FrontendStatus::symbolRate>((int)s.symbolRate());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::innerFec: {
+            status.set<FrontendStatus::innerFec>(static_cast<FrontendInnerFec>(s.innerFec()));
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::modulation: {
+            FrontendModulationStatus modulationStatus;
+            switch (s.modulation().getDiscriminator()) {
+            case HidlFrontendModulationStatus::hidl_discriminator::dvbc:
+                modulationStatus.set<FrontendModulationStatus::dvbc>(
+                        static_cast<FrontendDvbcModulation>(s.modulation().dvbc()));
+                break;
+            case HidlFrontendModulationStatus::hidl_discriminator::dvbs:
+                modulationStatus.set<FrontendModulationStatus::dvbs>(
+                        static_cast<FrontendDvbsModulation>(s.modulation().dvbs()));
+                break;
+            case HidlFrontendModulationStatus::hidl_discriminator::isdbs:
+                modulationStatus.set<FrontendModulationStatus::isdbs>(
+                        static_cast<FrontendIsdbsModulation>(s.modulation().isdbs()));
+                break;
+            case HidlFrontendModulationStatus::hidl_discriminator::isdbs3:
+                modulationStatus.set<FrontendModulationStatus::isdbs3>(
+                        static_cast<FrontendIsdbs3Modulation>(s.modulation().isdbs3()));
+                break;
+            case HidlFrontendModulationStatus::hidl_discriminator::isdbt:
+                modulationStatus.set<FrontendModulationStatus::isdbt>(
+                        static_cast<FrontendIsdbtModulation>(s.modulation().isdbt()));
+                break;
+            }
+            status.set<FrontendStatus::modulationStatus>(modulationStatus);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::inversion: {
+            status.set<FrontendStatus::inversion>(
+                    static_cast<FrontendSpectralInversion>(s.inversion()));
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::lnbVoltage: {
+            status.set<FrontendStatus::lnbVoltage>(static_cast<LnbVoltage>(s.lnbVoltage()));
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::plpId: {
+            status.set<FrontendStatus::plpId>((int32_t)s.plpId());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::isEWBS: {
+            status.set<FrontendStatus::isEWBS>(s.isEWBS());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::agc: {
+            status.set<FrontendStatus::agc>((int32_t)s.agc());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::isLnaOn: {
+            status.set<FrontendStatus::isLnaOn>(s.isLnaOn());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::isLayerError: {
+            vector<bool> e(s.isLayerError().begin(), s.isLayerError().end());
+            status.set<FrontendStatus::isLayerError>(e);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::mer: {
+            status.set<FrontendStatus::mer>(static_cast<int32_t>(s.mer()));
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::freqOffset: {
+            status.set<FrontendStatus::freqOffset>(static_cast<int64_t>(s.freqOffset()));
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::hierarchy: {
+            status.set<FrontendStatus::hierarchy>(
+                    static_cast<FrontendDvbtHierarchy>(s.hierarchy()));
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::isRfLocked: {
+            status.set<FrontendStatus::isRfLocked>(s.isRfLocked());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatus::hidl_discriminator::plpInfo: {
+            vector<FrontendStatusAtsc3PlpInfo> info;
+            for (auto i : s.plpInfo()) {
+                info.push_back({
+                        .plpId = static_cast<int32_t>(i.plpId),
+                        .isLocked = i.isLocked,
+                        .uec = static_cast<int32_t>(i.uec),
+                });
+            }
+            status.set<FrontendStatus::plpInfo>(info);
+            aidlStatus.push_back(status);
+            break;
+        }
+        }
+    }
+
+    for (HidlFrontendStatusExt1_1 s : hidlStatusExt) {
+        FrontendStatus status;
+        switch (s.getDiscriminator()) {
+        case HidlFrontendStatusExt1_1::hidl_discriminator::modulations: {
+            vector<FrontendModulation> aidlMod;
+            for (auto m : s.modulations()) {
+                switch (m.getDiscriminator()) {
+                case HidlFrontendModulation::hidl_discriminator::dvbc:
+                    aidlMod.push_back(static_cast<FrontendDvbcModulation>(m.dvbc()));
+                    break;
+                case HidlFrontendModulation::hidl_discriminator::dvbs:
+                    aidlMod.push_back(static_cast<FrontendDvbsModulation>(m.dvbs()));
+                    break;
+                case HidlFrontendModulation::hidl_discriminator::dvbt:
+                    aidlMod.push_back(static_cast<FrontendDvbtConstellation>(m.dvbt()));
+                    break;
+                case HidlFrontendModulation::hidl_discriminator::isdbs:
+                    aidlMod.push_back(static_cast<FrontendIsdbsModulation>(m.isdbs()));
+                    break;
+                case HidlFrontendModulation::hidl_discriminator::isdbs3:
+                    aidlMod.push_back(static_cast<FrontendIsdbs3Modulation>(m.isdbs3()));
+                    break;
+                case HidlFrontendModulation::hidl_discriminator::isdbt:
+                    aidlMod.push_back(static_cast<FrontendIsdbtModulation>(m.isdbt()));
+                    break;
+                case HidlFrontendModulation::hidl_discriminator::atsc:
+                    aidlMod.push_back(static_cast<FrontendAtscModulation>(m.atsc()));
+                    break;
+                case HidlFrontendModulation::hidl_discriminator::atsc3:
+                    aidlMod.push_back(static_cast<FrontendAtsc3Modulation>(m.atsc3()));
+                    break;
+                case HidlFrontendModulation::hidl_discriminator::dtmb:
+                    aidlMod.push_back(static_cast<FrontendDtmbModulation>(m.dtmb()));
+                    break;
+                }
+            }
+            status.set<FrontendStatus::modulations>(aidlMod);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::bers: {
+            vector<int> b(s.bers().begin(), s.bers().end());
+            status.set<FrontendStatus::bers>(b);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::codeRates: {
+            vector<FrontendInnerFec> codeRates;
+            for (auto c : s.codeRates()) {
+                codeRates.push_back(static_cast<FrontendInnerFec>(c));
+            }
+            status.set<FrontendStatus::codeRates>(codeRates);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::bandwidth: {
+            FrontendBandwidth bandwidth;
+            switch (s.bandwidth().getDiscriminator()) {
+            case HidlFrontendBandwidth::hidl_discriminator::atsc3:
+                bandwidth.set<FrontendBandwidth::atsc3>(
+                        static_cast<FrontendAtsc3Bandwidth>(s.bandwidth().atsc3()));
+                break;
+            case HidlFrontendBandwidth::hidl_discriminator::dvbc:
+                bandwidth.set<FrontendBandwidth::dvbc>(
+                        static_cast<FrontendDvbcBandwidth>(s.bandwidth().dvbc()));
+                break;
+            case HidlFrontendBandwidth::hidl_discriminator::dvbt:
+                bandwidth.set<FrontendBandwidth::dvbt>(
+                        static_cast<FrontendDvbtBandwidth>(s.bandwidth().dvbt()));
+                break;
+            case HidlFrontendBandwidth::hidl_discriminator::isdbt:
+                bandwidth.set<FrontendBandwidth::isdbt>(
+                        static_cast<FrontendIsdbtBandwidth>(s.bandwidth().isdbt()));
+                break;
+            case HidlFrontendBandwidth::hidl_discriminator::dtmb:
+                bandwidth.set<FrontendBandwidth::dtmb>(
+                        static_cast<FrontendDtmbBandwidth>(s.bandwidth().dtmb()));
+                break;
+            }
+            status.set<FrontendStatus::bandwidth>(bandwidth);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::interval: {
+            FrontendGuardInterval interval;
+            switch (s.interval().getDiscriminator()) {
+            case HidlFrontendGuardInterval::hidl_discriminator::dvbt:
+                interval.set<FrontendGuardInterval::dvbt>(
+                        static_cast<FrontendDvbtGuardInterval>(s.interval().dvbt()));
+                break;
+            case HidlFrontendGuardInterval::hidl_discriminator::isdbt:
+                interval.set<FrontendGuardInterval::isdbt>(
+                        static_cast<FrontendIsdbtGuardInterval>(s.interval().isdbt()));
+                break;
+            case HidlFrontendGuardInterval::hidl_discriminator::dtmb:
+                interval.set<FrontendGuardInterval::dtmb>(
+                        static_cast<FrontendDtmbGuardInterval>(s.interval().dtmb()));
+                break;
+            }
+            status.set<FrontendStatus::interval>(interval);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::transmissionMode: {
+            FrontendTransmissionMode transmissionMode;
+            switch (s.transmissionMode().getDiscriminator()) {
+            case HidlFrontendTransmissionMode::hidl_discriminator::dvbt:
+                transmissionMode.set<FrontendTransmissionMode::dvbt>(
+                        static_cast<FrontendDvbtTransmissionMode>(s.transmissionMode().dvbt()));
+                break;
+            case HidlFrontendTransmissionMode::hidl_discriminator::isdbt:
+                transmissionMode.set<FrontendTransmissionMode::isdbt>(
+                        static_cast<FrontendIsdbtMode>(s.transmissionMode().isdbt()));
+                break;
+            case HidlFrontendTransmissionMode::hidl_discriminator::dtmb:
+                transmissionMode.set<FrontendTransmissionMode::dtmb>(
+                        static_cast<FrontendDtmbTransmissionMode>(s.transmissionMode().dtmb()));
+                break;
+            }
+            status.set<FrontendStatus::transmissionMode>(transmissionMode);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::uec: {
+            status.set<FrontendStatus::uec>(static_cast<int32_t>(s.uec()));
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::systemId: {
+            status.set<FrontendStatus::systemId>(static_cast<int32_t>(s.systemId()));
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::interleaving: {
+            vector<FrontendInterleaveMode> aidlInter;
+            for (auto i : s.interleaving()) {
+                FrontendInterleaveMode leaveMode;
+                switch (i.getDiscriminator()) {
+                case HidlFrontendInterleaveMode::hidl_discriminator::atsc3:
+                    leaveMode.set<FrontendInterleaveMode::atsc3>(
+                            static_cast<FrontendAtsc3TimeInterleaveMode>(i.atsc3()));
+                    break;
+                case HidlFrontendInterleaveMode::hidl_discriminator::dvbc:
+                    leaveMode.set<FrontendInterleaveMode::dvbc>(
+                            static_cast<FrontendCableTimeInterleaveMode>(i.dvbc()));
+                    break;
+                case HidlFrontendInterleaveMode::hidl_discriminator::dtmb:
+                    leaveMode.set<FrontendInterleaveMode::dtmb>(
+                            static_cast<FrontendDtmbTimeInterleaveMode>(i.dtmb()));
+                    break;
+                }
+                aidlInter.push_back(leaveMode);
+            }
+            status.set<FrontendStatus::interleaving>(aidlInter);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::isdbtSegment: {
+            const vector<uint8_t>& seg = s.isdbtSegment();
+            vector<int32_t> i(seg.begin(), seg.end());
+            status.set<FrontendStatus::isdbtSegment>(i);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::tsDataRate: {
+            vector<int32_t> ts(s.tsDataRate().begin(), s.tsDataRate().end());
+            status.set<FrontendStatus::tsDataRate>(ts);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::rollOff: {
+            FrontendRollOff rollOff;
+            switch (s.rollOff().getDiscriminator()) {
+            case HidlFrontendRollOff::hidl_discriminator::dvbs:
+                rollOff.set<FrontendRollOff::dvbs>(
+                        static_cast<FrontendDvbsRolloff>(s.rollOff().dvbs()));
+                break;
+            case HidlFrontendRollOff::hidl_discriminator::isdbs:
+                rollOff.set<FrontendRollOff::isdbs>(
+                        static_cast<FrontendIsdbsRolloff>(s.rollOff().isdbs()));
+                break;
+            case HidlFrontendRollOff::hidl_discriminator::isdbs3:
+                rollOff.set<FrontendRollOff::isdbs3>(
+                        static_cast<FrontendIsdbs3Rolloff>(s.rollOff().isdbs3()));
+                break;
+            }
+            status.set<FrontendStatus::rollOff>(rollOff);
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::isMiso: {
+            status.set<FrontendStatus::isMiso>(s.isMiso());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::isLinear: {
+            status.set<FrontendStatus::isLinear>(s.isLinear());
+            aidlStatus.push_back(status);
+            break;
+        }
+        case HidlFrontendStatusExt1_1::hidl_discriminator::isShortFrames: {
+            status.set<FrontendStatus::isShortFrames>(s.isShortFrames());
+            aidlStatus.push_back(status);
+            break;
+        }
+        }
+    }
+}
+
+hidl_vec<HidlFrontendAtsc3PlpSettings> TunerHidlFrontend::getAtsc3PlpSettings(
+        const FrontendAtsc3Settings& settings) {
+    int len = settings.plpSettings.size();
+    hidl_vec<HidlFrontendAtsc3PlpSettings> plps = hidl_vec<HidlFrontendAtsc3PlpSettings>(len);
+    // parse PLP settings
+    for (int i = 0; i < len; i++) {
+        uint8_t plpId = static_cast<uint8_t>(settings.plpSettings[i].plpId);
+        HidlFrontendAtsc3Modulation modulation =
+                static_cast<HidlFrontendAtsc3Modulation>(settings.plpSettings[i].modulation);
+        HidlFrontendAtsc3TimeInterleaveMode interleaveMode =
+                static_cast<HidlFrontendAtsc3TimeInterleaveMode>(
+                        settings.plpSettings[i].interleaveMode);
+        HidlFrontendAtsc3CodeRate codeRate =
+                static_cast<HidlFrontendAtsc3CodeRate>(settings.plpSettings[i].codeRate);
+        HidlFrontendAtsc3Fec fec = static_cast<HidlFrontendAtsc3Fec>(settings.plpSettings[i].fec);
+        HidlFrontendAtsc3PlpSettings frontendAtsc3PlpSettings{
+                .plpId = plpId,
+                .modulation = modulation,
+                .interleaveMode = interleaveMode,
+                .codeRate = codeRate,
+                .fec = fec,
+        };
+        plps[i] = frontendAtsc3PlpSettings;
+    }
+    return plps;
+}
+
+HidlFrontendDvbsCodeRate TunerHidlFrontend::getDvbsCodeRate(const FrontendDvbsCodeRate& codeRate) {
+    HidlFrontendInnerFec innerFec = static_cast<HidlFrontendInnerFec>(codeRate.fec);
+    bool isLinear = codeRate.isLinear;
+    bool isShortFrames = codeRate.isShortFrames;
+    uint32_t bitsPer1000Symbol = static_cast<uint32_t>(codeRate.bitsPer1000Symbol);
+    HidlFrontendDvbsCodeRate coderate{
+            .fec = innerFec,
+            .isLinear = isLinear,
+            .isShortFrames = isShortFrames,
+            .bitsPer1000Symbol = bitsPer1000Symbol,
+    };
+    return coderate;
+}
+
+void TunerHidlFrontend::getHidlFrontendSettings(const FrontendSettings& aidlSettings,
+                                                HidlFrontendSettings& settings,
+                                                HidlFrontendSettingsExt1_1& settingsExt) {
+    switch (aidlSettings.getTag()) {
+    case FrontendSettings::analog: {
+        const FrontendAnalogSettings& analog = aidlSettings.get<FrontendSettings::analog>();
+        settings.analog({
+                .frequency = static_cast<uint32_t>(analog.frequency),
+                .type = static_cast<HidlFrontendAnalogType>(analog.type),
+                .sifStandard = static_cast<HidlFrontendAnalogSifStandard>(analog.sifStandard),
+        });
+        settingsExt.settingExt.analog({
+                .aftFlag = static_cast<HidlFrontendAnalogAftFlag>(analog.aftFlag),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(analog.endFrequency);
+        settingsExt.inversion = static_cast<HidlFrontendSpectralInversion>(analog.inversion);
+        break;
+    }
+    case FrontendSettings::atsc: {
+        const FrontendAtscSettings& atsc = aidlSettings.get<FrontendSettings::atsc>();
+        settings.atsc({
+                .frequency = static_cast<uint32_t>(atsc.frequency),
+                .modulation = static_cast<HidlFrontendAtscModulation>(atsc.modulation),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(atsc.endFrequency);
+        settingsExt.inversion = static_cast<HidlFrontendSpectralInversion>(atsc.inversion);
+        settingsExt.settingExt.noinit();
+        break;
+    }
+    case FrontendSettings::atsc3: {
+        const FrontendAtsc3Settings& atsc3 = aidlSettings.get<FrontendSettings::atsc3>();
+        settings.atsc3({
+                .frequency = static_cast<uint32_t>(atsc3.frequency),
+                .bandwidth = static_cast<HidlFrontendAtsc3Bandwidth>(atsc3.bandwidth),
+                .demodOutputFormat =
+                        static_cast<HidlFrontendAtsc3DemodOutputFormat>(atsc3.demodOutputFormat),
+                .plpSettings = getAtsc3PlpSettings(atsc3),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(atsc3.endFrequency);
+        settingsExt.inversion = static_cast<HidlFrontendSpectralInversion>(atsc3.inversion);
+        settingsExt.settingExt.noinit();
+        break;
+    }
+    case FrontendSettings::dvbc: {
+        const FrontendDvbcSettings& dvbc = aidlSettings.get<FrontendSettings::dvbc>();
+        settings.dvbc({
+                .frequency = static_cast<uint32_t>(dvbc.frequency),
+                .modulation = static_cast<HidlFrontendDvbcModulation>(dvbc.modulation),
+                .fec = static_cast<HidlFrontendInnerFec>(dvbc.fec),
+                .symbolRate = static_cast<uint32_t>(dvbc.symbolRate),
+                .outerFec = static_cast<HidlFrontendDvbcOuterFec>(dvbc.outerFec),
+                .annex = static_cast<HidlFrontendDvbcAnnex>(dvbc.annex),
+                .spectralInversion = static_cast<HidlFrontendDvbcSpectralInversion>(dvbc.inversion),
+        });
+        settingsExt.settingExt.dvbc({
+                .interleaveMode =
+                        static_cast<HidlFrontendCableTimeInterleaveMode>(dvbc.interleaveMode),
+                .bandwidth = static_cast<HidlFrontendDvbcBandwidth>(dvbc.bandwidth),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(dvbc.endFrequency);
+        settingsExt.inversion = static_cast<HidlFrontendSpectralInversion>(dvbc.inversion);
+        break;
+    }
+    case FrontendSettings::dvbs: {
+        const FrontendDvbsSettings& dvbs = aidlSettings.get<FrontendSettings::dvbs>();
+        settings.dvbs({
+                .frequency = static_cast<uint32_t>(dvbs.frequency),
+                .modulation = static_cast<HidlFrontendDvbsModulation>(dvbs.modulation),
+                .coderate = getDvbsCodeRate(dvbs.coderate),
+                .symbolRate = static_cast<uint32_t>(dvbs.symbolRate),
+                .rolloff = static_cast<HidlFrontendDvbsRolloff>(dvbs.rolloff),
+                .pilot = static_cast<HidlFrontendDvbsPilot>(dvbs.pilot),
+                .inputStreamId = static_cast<uint32_t>(dvbs.inputStreamId),
+                .standard = static_cast<HidlFrontendDvbsStandard>(dvbs.standard),
+                .vcmMode = static_cast<HidlFrontendDvbsVcmMode>(dvbs.vcmMode),
+        });
+        settingsExt.settingExt.dvbs({
+                .scanType = static_cast<HidlFrontendDvbsScanType>(dvbs.scanType),
+                .isDiseqcRxMessage = dvbs.isDiseqcRxMessage,
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(dvbs.endFrequency);
+        settingsExt.inversion = static_cast<HidlFrontendSpectralInversion>(dvbs.inversion);
+        break;
+    }
+    case FrontendSettings::dvbt: {
+        const FrontendDvbtSettings& dvbt = aidlSettings.get<FrontendSettings::dvbt>();
+        settings.dvbt({
+                .frequency = static_cast<uint32_t>(dvbt.frequency),
+                .transmissionMode =
+                        static_cast<HidlFrontendDvbtTransmissionMode>(dvbt.transmissionMode),
+                .bandwidth = static_cast<HidlFrontendDvbtBandwidth>(dvbt.bandwidth),
+                .constellation = static_cast<HidlFrontendDvbtConstellation>(dvbt.constellation),
+                .hierarchy = static_cast<HidlFrontendDvbtHierarchy>(dvbt.hierarchy),
+                .hpCoderate = static_cast<HidlFrontendDvbtCoderate>(dvbt.hpCoderate),
+                .lpCoderate = static_cast<HidlFrontendDvbtCoderate>(dvbt.lpCoderate),
+                .guardInterval = static_cast<HidlFrontendDvbtGuardInterval>(dvbt.guardInterval),
+                .isHighPriority = dvbt.isHighPriority,
+                .standard = static_cast<HidlFrontendDvbtStandard>(dvbt.standard),
+                .isMiso = dvbt.isMiso,
+                .plpMode = static_cast<HidlFrontendDvbtPlpMode>(dvbt.plpMode),
+                .plpId = static_cast<uint8_t>(dvbt.plpId),
+                .plpGroupId = static_cast<uint8_t>(dvbt.plpGroupId),
+        });
+        settingsExt.settingExt.dvbt({
+                .constellation = static_cast<
+                        ::android::hardware::tv::tuner::V1_1::FrontendDvbtConstellation>(
+                        dvbt.constellation),
+                .transmissionMode = static_cast<
+                        ::android::hardware::tv::tuner::V1_1::FrontendDvbtTransmissionMode>(
+                        dvbt.transmissionMode),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(dvbt.endFrequency);
+        settingsExt.inversion = static_cast<HidlFrontendSpectralInversion>(dvbt.inversion);
+        break;
+    }
+    case FrontendSettings::isdbs: {
+        const FrontendIsdbsSettings& isdbs = aidlSettings.get<FrontendSettings::isdbs>();
+        settings.isdbs({
+                .frequency = static_cast<uint32_t>(isdbs.frequency),
+                .streamId = static_cast<uint16_t>(isdbs.streamId),
+                .streamIdType = static_cast<HidlFrontendIsdbsStreamIdType>(isdbs.streamIdType),
+                .modulation = static_cast<HidlFrontendIsdbsModulation>(isdbs.modulation),
+                .coderate = static_cast<HidlFrontendIsdbsCoderate>(isdbs.coderate),
+                .symbolRate = static_cast<uint32_t>(isdbs.symbolRate),
+                .rolloff = static_cast<HidlFrontendIsdbsRolloff>(isdbs.rolloff),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(isdbs.endFrequency);
+        settingsExt.settingExt.noinit();
+        break;
+    }
+    case FrontendSettings::isdbs3: {
+        const FrontendIsdbs3Settings& isdbs3 = aidlSettings.get<FrontendSettings::isdbs3>();
+        settings.isdbs3({
+                .frequency = static_cast<uint32_t>(isdbs3.frequency),
+                .streamId = static_cast<uint16_t>(isdbs3.streamId),
+                .streamIdType = static_cast<HidlFrontendIsdbsStreamIdType>(isdbs3.streamIdType),
+                .modulation = static_cast<HidlFrontendIsdbs3Modulation>(isdbs3.modulation),
+                .coderate = static_cast<HidlFrontendIsdbs3Coderate>(isdbs3.coderate),
+                .symbolRate = static_cast<uint32_t>(isdbs3.symbolRate),
+                .rolloff = static_cast<HidlFrontendIsdbs3Rolloff>(isdbs3.rolloff),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(isdbs3.endFrequency);
+        settingsExt.settingExt.noinit();
+        break;
+    }
+    case FrontendSettings::isdbt: {
+        const FrontendIsdbtSettings& isdbt = aidlSettings.get<FrontendSettings::isdbt>();
+        settings.isdbt({
+                .frequency = static_cast<uint32_t>(isdbt.frequency),
+                .modulation = static_cast<HidlFrontendIsdbtModulation>(isdbt.modulation),
+                .bandwidth = static_cast<HidlFrontendIsdbtBandwidth>(isdbt.bandwidth),
+                .mode = static_cast<HidlFrontendIsdbtMode>(isdbt.mode),
+                .coderate = static_cast<HidlFrontendIsdbtCoderate>(isdbt.coderate),
+                .guardInterval = static_cast<HidlFrontendIsdbtGuardInterval>(isdbt.guardInterval),
+                .serviceAreaId = static_cast<uint32_t>(isdbt.serviceAreaId),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(isdbt.endFrequency);
+        settingsExt.inversion = static_cast<HidlFrontendSpectralInversion>(isdbt.inversion);
+        settingsExt.settingExt.noinit();
+        break;
+    }
+    case FrontendSettings::dtmb: {
+        const FrontendDtmbSettings& dtmb = aidlSettings.get<FrontendSettings::dtmb>();
+        settingsExt.settingExt.dtmb({
+                .frequency = static_cast<uint32_t>(dtmb.frequency),
+                .transmissionMode =
+                        static_cast<HidlFrontendDtmbTransmissionMode>(dtmb.transmissionMode),
+                .bandwidth = static_cast<HidlFrontendDtmbBandwidth>(dtmb.bandwidth),
+                .modulation = static_cast<HidlFrontendDtmbModulation>(dtmb.modulation),
+                .codeRate = static_cast<HidlFrontendDtmbCodeRate>(dtmb.codeRate),
+                .guardInterval = static_cast<HidlFrontendDtmbGuardInterval>(dtmb.guardInterval),
+                .interleaveMode =
+                        static_cast<HidlFrontendDtmbTimeInterleaveMode>(dtmb.interleaveMode),
+        });
+        settingsExt.endFrequency = static_cast<uint32_t>(dtmb.endFrequency);
+        settingsExt.inversion = static_cast<HidlFrontendSpectralInversion>(dtmb.inversion);
+        break;
+    }
+    default:
+        break;
+    }
+}
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
diff --git a/services/tuner/hidl/TunerHidlFrontend.h b/services/tuner/hidl/TunerHidlFrontend.h
new file mode 100644
index 0000000..0abd80b
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlFrontend.h
@@ -0,0 +1,123 @@
+/**
+ * Copyright 2021, 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_MEDIA_TUNERHIDLFRONTEND_H
+#define ANDROID_MEDIA_TUNERHIDLFRONTEND_H
+
+#include <aidl/android/hardware/tv/tuner/IFrontendCallback.h>
+#include <aidl/android/media/tv/tuner/BnTunerFrontend.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+#include <android/hardware/tv/tuner/1.1/IFrontend.h>
+#include <android/hardware/tv/tuner/1.1/IFrontendCallback.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Log.h>
+
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Settings;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsCodeRate;
+using ::aidl::android::hardware::tv::tuner::FrontendEventType;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessage;
+using ::aidl::android::hardware::tv::tuner::FrontendScanMessageType;
+using ::aidl::android::hardware::tv::tuner::FrontendScanType;
+using ::aidl::android::hardware::tv::tuner::FrontendSettings;
+using ::aidl::android::hardware::tv::tuner::FrontendStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendStatusType;
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::std::shared_ptr;
+using ::std::vector;
+
+using HidlFrontendAtsc3PlpSettings = ::android::hardware::tv::tuner::V1_0::FrontendAtsc3PlpSettings;
+using HidlFrontendDvbsCodeRate = ::android::hardware::tv::tuner::V1_0::FrontendDvbsCodeRate;
+using HidlFrontendEventType = ::android::hardware::tv::tuner::V1_0::FrontendEventType;
+using HidlFrontendId = ::android::hardware::tv::tuner::V1_0::FrontendId;
+using HidlFrontendScanMessage = ::android::hardware::tv::tuner::V1_0::FrontendScanMessage;
+using HidlFrontendScanMessageType = ::android::hardware::tv::tuner::V1_0::FrontendScanMessageType;
+using HidlFrontendSettings = ::android::hardware::tv::tuner::V1_0::FrontendSettings;
+using HidlFrontendStatus = ::android::hardware::tv::tuner::V1_0::FrontendStatus;
+using HidlIFrontend = ::android::hardware::tv::tuner::V1_0::IFrontend;
+using HidlIFrontendCallback = ::android::hardware::tv::tuner::V1_1::IFrontendCallback;
+using HidlFrontendScanMessageExt1_1 =
+        ::android::hardware::tv::tuner::V1_1::FrontendScanMessageExt1_1;
+using HidlFrontendScanMessageTypeExt1_1 =
+        ::android::hardware::tv::tuner::V1_1::FrontendScanMessageTypeExt1_1;
+using HidlFrontendSettingsExt1_1 = ::android::hardware::tv::tuner::V1_1::FrontendSettingsExt1_1;
+using HidlFrontendStatusExt1_1 = ::android::hardware::tv::tuner::V1_1::FrontendStatusExt1_1;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+class TunerHidlFrontend : public BnTunerFrontend {
+public:
+    TunerHidlFrontend(sp<HidlIFrontend> frontend, int id);
+    virtual ~TunerHidlFrontend();
+
+    ::ndk::ScopedAStatus setCallback(
+            const shared_ptr<ITunerFrontendCallback>& in_tunerFrontendCallback) override;
+    ::ndk::ScopedAStatus tune(const FrontendSettings& in_settings) override;
+    ::ndk::ScopedAStatus stopTune() override;
+    ::ndk::ScopedAStatus scan(const FrontendSettings& in_settings,
+                              FrontendScanType in_frontendScanType) override;
+    ::ndk::ScopedAStatus stopScan() override;
+    ::ndk::ScopedAStatus setLnb(const shared_ptr<ITunerLnb>& in_lnb) override;
+    ::ndk::ScopedAStatus setLna(bool in_bEnable) override;
+    ::ndk::ScopedAStatus linkCiCamToFrontend(int32_t in_ciCamId, int32_t* _aidl_return) override;
+    ::ndk::ScopedAStatus unlinkCiCamToFrontend(int32_t in_ciCamId) override;
+    ::ndk::ScopedAStatus close() override;
+    ::ndk::ScopedAStatus getStatus(const vector<FrontendStatusType>& in_statusTypes,
+                                   vector<FrontendStatus>* _aidl_return) override;
+    ::ndk::ScopedAStatus getFrontendId(int32_t* _aidl_return) override;
+
+    struct FrontendCallback : public HidlIFrontendCallback {
+        FrontendCallback(const shared_ptr<ITunerFrontendCallback> tunerFrontendCallback)
+              : mTunerFrontendCallback(tunerFrontendCallback){};
+
+        virtual Return<void> onEvent(HidlFrontendEventType frontendEventType);
+        virtual Return<void> onScanMessage(HidlFrontendScanMessageType type,
+                                           const HidlFrontendScanMessage& message);
+        virtual Return<void> onScanMessageExt1_1(HidlFrontendScanMessageTypeExt1_1 type,
+                                                 const HidlFrontendScanMessageExt1_1& message);
+
+        shared_ptr<ITunerFrontendCallback> mTunerFrontendCallback;
+    };
+
+private:
+    hidl_vec<HidlFrontendAtsc3PlpSettings> getAtsc3PlpSettings(
+            const FrontendAtsc3Settings& settings);
+    HidlFrontendDvbsCodeRate getDvbsCodeRate(const FrontendDvbsCodeRate& codeRate);
+    void getHidlFrontendSettings(const FrontendSettings& aidlSettings,
+                                 HidlFrontendSettings& settings,
+                                 HidlFrontendSettingsExt1_1& settingsExt);
+    void getAidlFrontendStatus(const vector<HidlFrontendStatus>& hidlStatus,
+                               const vector<HidlFrontendStatusExt1_1>& hidlStatusExt,
+                               vector<FrontendStatus>& aidlStatus);
+
+    int mId;
+    sp<HidlIFrontend> mFrontend;
+    sp<::android::hardware::tv::tuner::V1_1::IFrontend> mFrontend_1_1;
+};
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
+
+#endif  // ANDROID_MEDIA_TUNERHIDLFRONTEND_H
diff --git a/services/tuner/hidl/TunerHidlLnb.cpp b/services/tuner/hidl/TunerHidlLnb.cpp
new file mode 100644
index 0000000..a7e20bb
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlLnb.cpp
@@ -0,0 +1,160 @@
+/**
+ * Copyright 2021, 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 "TunerHidlLnb"
+
+#include "TunerHidlLnb.h"
+
+#include <aidl/android/hardware/tv/tuner/Result.h>
+
+using ::aidl::android::hardware::tv::tuner::Result;
+using HidlLnbPosition = ::android::hardware::tv::tuner::V1_0::LnbPosition;
+using HidlLnbTone = ::android::hardware::tv::tuner::V1_0::LnbTone;
+using HidlLnbVoltage = ::android::hardware::tv::tuner::V1_0::LnbVoltage;
+using HidlResult = ::android::hardware::tv::tuner::V1_0::Result;
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+TunerHidlLnb::TunerHidlLnb(sp<HidlILnb> lnb, int id) {
+    mLnb = lnb;
+    mId = id;
+}
+
+TunerHidlLnb::~TunerHidlLnb() {
+    mLnb = nullptr;
+    mId = -1;
+}
+
+::ndk::ScopedAStatus TunerHidlLnb::setCallback(
+        const shared_ptr<ITunerLnbCallback>& in_tunerLnbCallback) {
+    if (mLnb == nullptr) {
+        ALOGE("ILnb is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    if (in_tunerLnbCallback == nullptr) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::INVALID_ARGUMENT));
+    }
+
+    sp<HidlILnbCallback> lnbCallback = new LnbCallback(in_tunerLnbCallback);
+    HidlResult status = mLnb->setCallback(lnbCallback);
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlLnb::setVoltage(LnbVoltage in_voltage) {
+    if (mLnb == nullptr) {
+        ALOGE("ILnb is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mLnb->setVoltage(static_cast<HidlLnbVoltage>(in_voltage));
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlLnb::setTone(LnbTone in_tone) {
+    if (mLnb == nullptr) {
+        ALOGE("ILnb is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mLnb->setTone(static_cast<HidlLnbTone>(in_tone));
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlLnb::setSatellitePosition(LnbPosition in_position) {
+    if (mLnb == nullptr) {
+        ALOGE("ILnb is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mLnb->setSatellitePosition(static_cast<HidlLnbPosition>(in_position));
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlLnb::sendDiseqcMessage(const vector<uint8_t>& in_diseqcMessage) {
+    if (mLnb == nullptr) {
+        ALOGE("ILnb is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mLnb->sendDiseqcMessage(in_diseqcMessage);
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlLnb::close() {
+    if (mLnb == nullptr) {
+        ALOGE("ILnb is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mLnb->close();
+    mLnb = nullptr;
+
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+/////////////// ILnbCallback ///////////////////////
+Return<void> TunerHidlLnb::LnbCallback::onEvent(const HidlLnbEventType lnbEventType) {
+    if (mTunerLnbCallback != nullptr) {
+        mTunerLnbCallback->onEvent(static_cast<LnbEventType>(lnbEventType));
+    }
+    return Void();
+}
+
+Return<void> TunerHidlLnb::LnbCallback::onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage) {
+    if (mTunerLnbCallback != nullptr) {
+        vector<uint8_t> msg(begin(diseqcMessage), end(diseqcMessage));
+        mTunerLnbCallback->onDiseqcMessage(msg);
+    }
+    return Void();
+}
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
diff --git a/services/tuner/hidl/TunerHidlLnb.h b/services/tuner/hidl/TunerHidlLnb.h
new file mode 100644
index 0000000..c496f48
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlLnb.h
@@ -0,0 +1,84 @@
+/**
+ * Copyright 2021, 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_MEDIA_TUNERHIDLLNB_H
+#define ANDROID_MEDIA_TUNERHIDLLNB_H
+
+#include <aidl/android/hardware/tv/tuner/ILnb.h>
+#include <aidl/android/media/tv/tuner/BnTunerLnb.h>
+#include <android/hardware/tv/tuner/1.0/ILnb.h>
+#include <android/hardware/tv/tuner/1.0/ILnbCallback.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Log.h>
+
+using ::aidl::android::hardware::tv::tuner::LnbEventType;
+using ::aidl::android::hardware::tv::tuner::LnbPosition;
+using ::aidl::android::hardware::tv::tuner::LnbTone;
+using ::aidl::android::hardware::tv::tuner::LnbVoltage;
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::std::shared_ptr;
+using ::std::vector;
+
+using HidlILnb = ::android::hardware::tv::tuner::V1_0::ILnb;
+using HidlILnbCallback = ::android::hardware::tv::tuner::V1_0::ILnbCallback;
+using HidlLnbEventType = ::android::hardware::tv::tuner::V1_0::LnbEventType;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+class TunerHidlLnb : public BnTunerLnb {
+public:
+    TunerHidlLnb(sp<HidlILnb> lnb, int id);
+    virtual ~TunerHidlLnb();
+
+    ::ndk::ScopedAStatus setCallback(
+            const shared_ptr<ITunerLnbCallback>& in_tunerLnbCallback) override;
+    ::ndk::ScopedAStatus setVoltage(LnbVoltage in_voltage) override;
+    ::ndk::ScopedAStatus setTone(LnbTone in_tone) override;
+    ::ndk::ScopedAStatus setSatellitePosition(LnbPosition in_position) override;
+    ::ndk::ScopedAStatus sendDiseqcMessage(const vector<uint8_t>& in_diseqcMessage) override;
+    ::ndk::ScopedAStatus close() override;
+
+    int getId() { return mId; }
+
+    struct LnbCallback : public HidlILnbCallback {
+        LnbCallback(const shared_ptr<ITunerLnbCallback> tunerLnbCallback)
+              : mTunerLnbCallback(tunerLnbCallback){};
+
+        virtual Return<void> onEvent(const HidlLnbEventType lnbEventType);
+        virtual Return<void> onDiseqcMessage(const hidl_vec<uint8_t>& diseqcMessage);
+
+        shared_ptr<ITunerLnbCallback> mTunerLnbCallback;
+    };
+
+private:
+    int mId;
+    sp<HidlILnb> mLnb;
+};
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
+
+#endif  // ANDROID_MEDIA_TUNERHIDLLNB_H
diff --git a/services/tuner/hidl/TunerHidlService.cpp b/services/tuner/hidl/TunerHidlService.cpp
new file mode 100644
index 0000000..9d9bc7e
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlService.cpp
@@ -0,0 +1,584 @@
+/**
+ * Copyright (c) 2021, 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_NDEBUG 0
+#define LOG_TAG "TunerHidlService"
+
+#include "TunerHidlService.h"
+
+#include <aidl/android/hardware/tv/tuner/Result.h>
+#include <android/binder_manager.h>
+#include <utils/Log.h>
+
+#include "TunerHelper.h"
+#include "TunerHidlDemux.h"
+#include "TunerHidlDescrambler.h"
+#include "TunerHidlFrontend.h"
+#include "TunerHidlLnb.h"
+
+using ::aidl::android::hardware::tv::tuner::FrontendAnalogCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Capabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendAtscCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendDtmbCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbcCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbsCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendDvbtCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Capabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbsCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendIsdbtCapabilities;
+using ::aidl::android::hardware::tv::tuner::FrontendType;
+using ::aidl::android::hardware::tv::tuner::Result;
+using ::aidl::android::media::tv::tunerresourcemanager::TunerFrontendInfo;
+using ::android::hardware::hidl_vec;
+
+using HidlFrontendId = ::android::hardware::tv::tuner::V1_0::FrontendId;
+using HidlLnbId = ::android::hardware::tv::tuner::V1_0::LnbId;
+using HidlFrontendType = ::android::hardware::tv::tuner::V1_1::FrontendType;
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+TunerHidlService::TunerHidlService() {
+    if (!TunerHelper::checkTunerFeature()) {
+        ALOGD("Device doesn't have tuner hardware.");
+        return;
+    }
+
+    updateTunerResources();
+}
+
+TunerHidlService::~TunerHidlService() {}
+
+binder_status_t TunerHidlService::instantiate() {
+    if (HidlITuner::getService() == nullptr) {
+        ALOGD("Failed to get ITuner HIDL HAL");
+        return STATUS_NAME_NOT_FOUND;
+    }
+
+    shared_ptr<TunerHidlService> service = ::ndk::SharedRefBase::make<TunerHidlService>();
+    return AServiceManager_addService(service->asBinder().get(), getServiceName());
+}
+
+bool TunerHidlService::hasITuner() {
+    ALOGV("hasITuner");
+    if (mTuner != nullptr) {
+        return true;
+    }
+
+    mTuner = HidlITuner::getService();
+    if (mTuner == nullptr) {
+        ALOGE("Failed to get ITuner service");
+        return false;
+    }
+    mTunerVersion = TUNER_HAL_VERSION_1_0;
+
+    mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::castFrom(mTuner);
+    if (mTuner_1_1 != nullptr) {
+        mTunerVersion = TUNER_HAL_VERSION_1_1;
+    } else {
+        ALOGD("Failed to get ITuner_1_1 service");
+    }
+
+    return true;
+}
+
+bool TunerHidlService::hasITuner_1_1() {
+    ALOGV("hasITuner_1_1");
+    hasITuner();
+    return (mTunerVersion == TUNER_HAL_VERSION_1_1);
+}
+
+::ndk::ScopedAStatus TunerHidlService::openDemux(int32_t /* in_demuxHandle */,
+                                                 shared_ptr<ITunerDemux>* _aidl_return) {
+    ALOGV("openDemux");
+    if (!hasITuner()) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res;
+    uint32_t id;
+    sp<IDemux> demuxSp = nullptr;
+    mTuner->openDemux([&](HidlResult r, uint32_t demuxId, const sp<IDemux>& demux) {
+        demuxSp = demux;
+        id = demuxId;
+        res = r;
+        ALOGD("open demux, id = %d", demuxId);
+    });
+    if (res == HidlResult::SUCCESS) {
+        *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlDemux>(demuxSp, id);
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    ALOGW("open demux failed, res = %d", res);
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+}
+
+::ndk::ScopedAStatus TunerHidlService::getDemuxCaps(DemuxCapabilities* _aidl_return) {
+    ALOGV("getDemuxCaps");
+    if (!hasITuner()) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res;
+    HidlDemuxCapabilities caps;
+    mTuner->getDemuxCaps([&](HidlResult r, const HidlDemuxCapabilities& demuxCaps) {
+        caps = demuxCaps;
+        res = r;
+    });
+    if (res == HidlResult::SUCCESS) {
+        *_aidl_return = getAidlDemuxCaps(caps);
+        return ::ndk::ScopedAStatus::ok();
+    }
+
+    ALOGW("Get demux caps failed, res = %d", res);
+    return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+}
+
+::ndk::ScopedAStatus TunerHidlService::getFrontendIds(vector<int32_t>* ids) {
+    if (!hasITuner()) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    hidl_vec<HidlFrontendId> feIds;
+    HidlResult res = getHidlFrontendIds(feIds);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    ids->resize(feIds.size());
+    copy(feIds.begin(), feIds.end(), ids->begin());
+
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlService::getFrontendInfo(int32_t id, FrontendInfo* _aidl_return) {
+    if (!hasITuner()) {
+        ALOGE("ITuner service is not init.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlFrontendInfo info;
+    HidlResult res = getHidlFrontendInfo(id, info);
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+
+    HidlFrontendDtmbCapabilities dtmbCaps;
+    if (static_cast<HidlFrontendType>(info.type) == HidlFrontendType::DTMB) {
+        if (!hasITuner_1_1()) {
+            ALOGE("ITuner_1_1 service is not init.");
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                    static_cast<int32_t>(Result::UNAVAILABLE));
+        }
+
+        mTuner_1_1->getFrontendDtmbCapabilities(
+                id, [&](HidlResult r, const HidlFrontendDtmbCapabilities& caps) {
+                    dtmbCaps = caps;
+                    res = r;
+                });
+        if (res != HidlResult::SUCCESS) {
+            return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+        }
+    }
+
+    *_aidl_return = getAidlFrontendInfo(info, dtmbCaps);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlService::openFrontend(int32_t frontendHandle,
+                                                    shared_ptr<ITunerFrontend>* _aidl_return) {
+    if (!hasITuner()) {
+        ALOGE("ITuner service is not init.");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status;
+    sp<HidlIFrontend> frontend;
+    int id = TunerHelper::getResourceIdFromHandle(frontendHandle, FRONTEND);
+    mTuner->openFrontendById(id, [&](HidlResult result, const sp<HidlIFrontend>& fe) {
+        frontend = fe;
+        status = result;
+    });
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlFrontend>(frontend, id);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlService::openLnb(int lnbHandle, shared_ptr<ITunerLnb>* _aidl_return) {
+    if (!hasITuner()) {
+        ALOGD("get ITuner failed");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status;
+    sp<HidlILnb> lnb;
+    int id = TunerHelper::getResourceIdFromHandle(lnbHandle, LNB);
+    mTuner->openLnbById(id, [&](HidlResult result, const sp<HidlILnb>& lnbSp) {
+        lnb = lnbSp;
+        status = result;
+    });
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+
+    *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlLnb>(lnb, id);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlService::openLnbByName(const string& lnbName,
+                                                     shared_ptr<ITunerLnb>* _aidl_return) {
+    if (!hasITuner()) {
+        ALOGE("get ITuner failed");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    int lnbId;
+    HidlResult status;
+    sp<HidlILnb> lnb;
+    mTuner->openLnbByName(lnbName, [&](HidlResult r, HidlLnbId id, const sp<HidlILnb>& lnbSp) {
+        status = r;
+        lnb = lnbSp;
+        lnbId = static_cast<int32_t>(id);
+    });
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+
+    *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlLnb>(lnb, lnbId);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlService::openDescrambler(
+        int32_t /*descramblerHandle*/, shared_ptr<ITunerDescrambler>* _aidl_return) {
+    if (!hasITuner()) {
+        ALOGD("get ITuner failed");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status;
+    sp<HidlIDescrambler> descrambler;
+    //int id = TunerHelper::getResourceIdFromHandle(descramblerHandle, DESCRAMBLER);
+    mTuner->openDescrambler([&](HidlResult r, const sp<HidlIDescrambler>& descramblerSp) {
+        status = r;
+        descrambler = descramblerSp;
+    });
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+
+    *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlDescrambler>(descrambler);
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlService::getTunerHalVersion(int* _aidl_return) {
+    hasITuner();
+    *_aidl_return = mTunerVersion;
+    return ::ndk::ScopedAStatus::ok();
+}
+
+void TunerHidlService::updateTunerResources() {
+    if (!hasITuner()) {
+        ALOGE("Failed to updateTunerResources");
+        return;
+    }
+
+    TunerHelper::updateTunerResources(getTRMFrontendInfos(), getTRMLnbHandles());
+}
+
+vector<TunerFrontendInfo> TunerHidlService::getTRMFrontendInfos() {
+    vector<TunerFrontendInfo> infos;
+    hidl_vec<HidlFrontendId> ids;
+    HidlResult res = getHidlFrontendIds(ids);
+    if (res != HidlResult::SUCCESS) {
+        return infos;
+    }
+
+    for (int i = 0; i < ids.size(); i++) {
+        HidlFrontendInfo frontendInfo;
+        HidlResult res = getHidlFrontendInfo(static_cast<int32_t>(ids[i]), frontendInfo);
+        if (res != HidlResult::SUCCESS) {
+            continue;
+        }
+        TunerFrontendInfo tunerFrontendInfo{
+                .handle = TunerHelper::getResourceHandleFromId(static_cast<int32_t>(ids[i]),
+                                                               FRONTEND),
+                .type = static_cast<int32_t>(frontendInfo.type),
+                .exclusiveGroupId = static_cast<int32_t>(frontendInfo.exclusiveGroupId),
+        };
+        infos.push_back(tunerFrontendInfo);
+    }
+
+    return infos;
+}
+
+vector<int32_t> TunerHidlService::getTRMLnbHandles() {
+    vector<int32_t> lnbHandles;
+    if (mTuner != nullptr) {
+        HidlResult res;
+        vector<HidlLnbId> lnbIds;
+        mTuner->getLnbIds([&](HidlResult r, const hidl_vec<HidlLnbId>& ids) {
+            lnbIds = ids;
+            res = r;
+        });
+        if (res == HidlResult::SUCCESS && lnbIds.size() > 0) {
+            for (int i = 0; i < lnbIds.size(); i++) {
+                lnbHandles.push_back(
+                        TunerHelper::getResourceHandleFromId(static_cast<int32_t>(lnbIds[i]), LNB));
+            }
+        }
+    }
+
+    return lnbHandles;
+}
+
+HidlResult TunerHidlService::getHidlFrontendIds(hidl_vec<HidlFrontendId>& ids) {
+    if (mTuner == nullptr) {
+        return HidlResult::NOT_INITIALIZED;
+    }
+    HidlResult res;
+    mTuner->getFrontendIds([&](HidlResult r, const hidl_vec<HidlFrontendId>& frontendIds) {
+        ids = frontendIds;
+        res = r;
+    });
+    return res;
+}
+
+HidlResult TunerHidlService::getHidlFrontendInfo(const int id, HidlFrontendInfo& info) {
+    if (mTuner == nullptr) {
+        return HidlResult::NOT_INITIALIZED;
+    }
+    HidlResult res;
+    mTuner->getFrontendInfo(id, [&](HidlResult r, const HidlFrontendInfo& feInfo) {
+        info = feInfo;
+        res = r;
+    });
+    return res;
+}
+
+DemuxCapabilities TunerHidlService::getAidlDemuxCaps(const HidlDemuxCapabilities& caps) {
+    DemuxCapabilities aidlCaps{
+            .numDemux = static_cast<int32_t>(caps.numDemux),
+            .numRecord = static_cast<int32_t>(caps.numRecord),
+            .numPlayback = static_cast<int32_t>(caps.numPlayback),
+            .numTsFilter = static_cast<int32_t>(caps.numTsFilter),
+            .numSectionFilter = static_cast<int32_t>(caps.numSectionFilter),
+            .numAudioFilter = static_cast<int32_t>(caps.numAudioFilter),
+            .numVideoFilter = static_cast<int32_t>(caps.numVideoFilter),
+            .numPesFilter = static_cast<int32_t>(caps.numPesFilter),
+            .numPcrFilter = static_cast<int32_t>(caps.numPcrFilter),
+            .numBytesInSectionFilter = static_cast<int64_t>(caps.numBytesInSectionFilter),
+            .filterCaps = static_cast<int32_t>(caps.filterCaps),
+            .bTimeFilter = caps.bTimeFilter,
+    };
+    aidlCaps.linkCaps.resize(caps.linkCaps.size());
+    copy(caps.linkCaps.begin(), caps.linkCaps.end(), aidlCaps.linkCaps.begin());
+    return aidlCaps;
+}
+
+FrontendInfo TunerHidlService::getAidlFrontendInfo(
+        const HidlFrontendInfo& halInfo, const HidlFrontendDtmbCapabilities& halDtmbCaps) {
+    FrontendInfo info{
+            .type = static_cast<FrontendType>(halInfo.type),
+            .minFrequency = static_cast<int64_t>(halInfo.minFrequency),
+            .maxFrequency = static_cast<int64_t>(halInfo.maxFrequency),
+            .minSymbolRate = static_cast<int32_t>(halInfo.minSymbolRate),
+            .maxSymbolRate = static_cast<int32_t>(halInfo.maxSymbolRate),
+            .acquireRange = static_cast<int64_t>(halInfo.acquireRange),
+            .exclusiveGroupId = static_cast<int32_t>(halInfo.exclusiveGroupId),
+    };
+    for (int i = 0; i < halInfo.statusCaps.size(); i++) {
+        info.statusCaps.push_back(static_cast<FrontendStatusType>(halInfo.statusCaps[i]));
+    }
+
+    FrontendCapabilities caps;
+    switch (halInfo.type) {
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::ANALOG: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::analogCaps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendAnalogCapabilities analogCaps{
+                    .typeCap = static_cast<int32_t>(halInfo.frontendCaps.analogCaps().typeCap),
+                    .sifStandardCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.analogCaps().sifStandardCap),
+            };
+            caps.set<FrontendCapabilities::analogCaps>(analogCaps);
+        }
+        break;
+    }
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::ATSC: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::atscCaps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendAtscCapabilities atscCaps{
+                    .modulationCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.atscCaps().modulationCap),
+            };
+            caps.set<FrontendCapabilities::atscCaps>(atscCaps);
+        }
+        break;
+    }
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::ATSC3: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::atsc3Caps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendAtsc3Capabilities atsc3Caps{
+                    .bandwidthCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.atsc3Caps().bandwidthCap),
+                    .modulationCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.atsc3Caps().modulationCap),
+                    .timeInterleaveModeCap = static_cast<int32_t>(
+                            halInfo.frontendCaps.atsc3Caps().timeInterleaveModeCap),
+                    .codeRateCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.atsc3Caps().codeRateCap),
+                    .demodOutputFormatCap = static_cast<int8_t>(
+                            halInfo.frontendCaps.atsc3Caps().demodOutputFormatCap),
+                    .fecCap = static_cast<int32_t>(halInfo.frontendCaps.atsc3Caps().fecCap),
+            };
+            caps.set<FrontendCapabilities::atsc3Caps>(atsc3Caps);
+        }
+        break;
+    }
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::DVBC: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::dvbcCaps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendDvbcCapabilities dvbcCaps{
+                    .modulationCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.dvbcCaps().modulationCap),
+                    .fecCap = static_cast<int64_t>(halInfo.frontendCaps.dvbcCaps().fecCap),
+                    .annexCap = static_cast<int8_t>(halInfo.frontendCaps.dvbcCaps().annexCap),
+            };
+            caps.set<FrontendCapabilities::dvbcCaps>(dvbcCaps);
+        }
+        break;
+    }
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::DVBS: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::dvbsCaps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendDvbsCapabilities dvbsCaps{
+                    .modulationCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.dvbsCaps().modulationCap),
+                    .innerfecCap =
+                            static_cast<int64_t>(halInfo.frontendCaps.dvbsCaps().innerfecCap),
+                    .standard = static_cast<int8_t>(halInfo.frontendCaps.dvbsCaps().standard),
+            };
+            caps.set<FrontendCapabilities::dvbsCaps>(dvbsCaps);
+        }
+        break;
+    }
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::DVBT: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::dvbtCaps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendDvbtCapabilities dvbtCaps{
+                    .transmissionModeCap = static_cast<int32_t>(
+                            halInfo.frontendCaps.dvbtCaps().transmissionModeCap),
+                    .bandwidthCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().bandwidthCap),
+                    .constellationCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().constellationCap),
+                    .coderateCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().coderateCap),
+                    .hierarchyCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().hierarchyCap),
+                    .guardIntervalCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().guardIntervalCap),
+                    .isT2Supported = halInfo.frontendCaps.dvbtCaps().isT2Supported,
+                    .isMisoSupported = halInfo.frontendCaps.dvbtCaps().isMisoSupported,
+            };
+            caps.set<FrontendCapabilities::dvbtCaps>(dvbtCaps);
+        }
+        break;
+    }
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::ISDBS: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::isdbsCaps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendIsdbsCapabilities isdbsCaps{
+                    .modulationCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.isdbsCaps().modulationCap),
+                    .coderateCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.isdbsCaps().coderateCap),
+            };
+            caps.set<FrontendCapabilities::isdbsCaps>(isdbsCaps);
+        }
+        break;
+    }
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::ISDBS3: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::isdbs3Caps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendIsdbs3Capabilities isdbs3Caps{
+                    .modulationCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.isdbs3Caps().modulationCap),
+                    .coderateCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.isdbs3Caps().coderateCap),
+            };
+            caps.set<FrontendCapabilities::isdbs3Caps>(isdbs3Caps);
+        }
+        break;
+    }
+    case ::android::hardware::tv::tuner::V1_0::FrontendType::ISDBT: {
+        if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::isdbtCaps ==
+            halInfo.frontendCaps.getDiscriminator()) {
+            FrontendIsdbtCapabilities isdbtCaps{
+                    .modeCap = static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().modeCap),
+                    .bandwidthCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().bandwidthCap),
+                    .modulationCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().modulationCap),
+                    .coderateCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().coderateCap),
+                    .guardIntervalCap =
+                            static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().guardIntervalCap),
+            };
+            caps.set<FrontendCapabilities::isdbtCaps>(isdbtCaps);
+        }
+        break;
+    }
+    default: {
+        if (static_cast<HidlFrontendType>(info.type) == HidlFrontendType::DTMB) {
+            FrontendDtmbCapabilities dtmbCaps{
+                    .transmissionModeCap = static_cast<int32_t>(halDtmbCaps.transmissionModeCap),
+                    .bandwidthCap = static_cast<int32_t>(halDtmbCaps.bandwidthCap),
+                    .modulationCap = static_cast<int32_t>(halDtmbCaps.modulationCap),
+                    .codeRateCap = static_cast<int32_t>(halDtmbCaps.codeRateCap),
+                    .guardIntervalCap = static_cast<int32_t>(halDtmbCaps.guardIntervalCap),
+                    .interleaveModeCap = static_cast<int32_t>(halDtmbCaps.interleaveModeCap),
+            };
+            caps.set<FrontendCapabilities::dtmbCaps>(dtmbCaps);
+        }
+        break;
+    }
+    }
+
+    info.frontendCaps = caps;
+    return info;
+}
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
diff --git a/services/tuner/hidl/TunerHidlService.h b/services/tuner/hidl/TunerHidlService.h
new file mode 100644
index 0000000..9f5f371
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlService.h
@@ -0,0 +1,105 @@
+/**
+ * Copyright (c) 2021, 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_MEDIA_TUNERHIDLSERVICE_H
+#define ANDROID_MEDIA_TUNERHIDLSERVICE_H
+
+#include <aidl/android/hardware/tv/tuner/DemuxFilterEvent.h>
+#include <aidl/android/hardware/tv/tuner/DemuxFilterStatus.h>
+#include <aidl/android/media/tv/tuner/BnTunerService.h>
+#include <aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.h>
+#include <android/hardware/tv/tuner/1.1/ITuner.h>
+
+#include "TunerHelper.h"
+
+using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
+using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
+using ::aidl::android::hardware::tv::tuner::FrontendInfo;
+using ::aidl::android::media::tv::tuner::ITunerDemux;
+using ::aidl::android::media::tv::tuner::ITunerDescrambler;
+using ::aidl::android::media::tv::tuner::ITunerFrontend;
+using ::aidl::android::media::tv::tuner::ITunerLnb;
+using ::aidl::android::media::tv::tunerresourcemanager::TunerFrontendInfo;
+using ::android::sp;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::std::shared_ptr;
+using ::std::vector;
+
+using HidlFrontendDtmbCapabilities = ::android::hardware::tv::tuner::V1_1::FrontendDtmbCapabilities;
+using HidlDemuxFilterEvent = ::android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
+using HidlDemuxFilterStatus = ::android::hardware::tv::tuner::V1_0::DemuxFilterStatus;
+using HidlDemuxCapabilities = ::android::hardware::tv::tuner::V1_0::DemuxCapabilities;
+using HidlFrontendInfo = ::android::hardware::tv::tuner::V1_0::FrontendInfo;
+using HidlITuner = ::android::hardware::tv::tuner::V1_0::ITuner;
+using HidlResult = ::android::hardware::tv::tuner::V1_0::Result;
+using HidlFrontendId = ::android::hardware::tv::tuner::V1_0::FrontendId;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+class TunerHidlService : public BnTunerService {
+public:
+    static char const* getServiceName() { return "media.tuner"; }
+    static binder_status_t instantiate();
+    TunerHidlService();
+    virtual ~TunerHidlService();
+
+    ::ndk::ScopedAStatus getFrontendIds(vector<int32_t>* out_ids) override;
+    ::ndk::ScopedAStatus getFrontendInfo(int32_t in_frontendHandle,
+                                         FrontendInfo* _aidl_return) override;
+    ::ndk::ScopedAStatus openFrontend(int32_t in_frontendHandle,
+                                      shared_ptr<ITunerFrontend>* _aidl_return) override;
+    ::ndk::ScopedAStatus openLnb(int32_t in_lnbHandle,
+                                 shared_ptr<ITunerLnb>* _aidl_return) override;
+    ::ndk::ScopedAStatus openLnbByName(const std::string& in_lnbName,
+                                       shared_ptr<ITunerLnb>* _aidl_return) override;
+    ::ndk::ScopedAStatus openDemux(int32_t in_demuxHandle,
+                                   shared_ptr<ITunerDemux>* _aidl_return) override;
+    ::ndk::ScopedAStatus getDemuxCaps(DemuxCapabilities* _aidl_return) override;
+    ::ndk::ScopedAStatus openDescrambler(int32_t in_descramblerHandle,
+                                         shared_ptr<ITunerDescrambler>* _aidl_return) override;
+    ::ndk::ScopedAStatus getTunerHalVersion(int32_t* _aidl_return) override;
+
+private:
+    bool hasITuner();
+    bool hasITuner_1_1();
+    void updateTunerResources();
+    vector<TunerFrontendInfo> getTRMFrontendInfos();
+    vector<int32_t> getTRMLnbHandles();
+    HidlResult getHidlFrontendIds(hidl_vec<HidlFrontendId>& ids);
+    HidlResult getHidlFrontendInfo(const int id, HidlFrontendInfo& info);
+    DemuxCapabilities getAidlDemuxCaps(const HidlDemuxCapabilities& caps);
+    FrontendInfo getAidlFrontendInfo(const HidlFrontendInfo& halInfo,
+                                     const HidlFrontendDtmbCapabilities& dtmbCaps);
+
+    sp<HidlITuner> mTuner;
+    sp<::android::hardware::tv::tuner::V1_1::ITuner> mTuner_1_1;
+    int mTunerVersion = TUNER_HAL_VERSION_UNKNOWN;
+};
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
+
+#endif  // ANDROID_MEDIA_TUNERHIDLSERVICE_H
diff --git a/services/tuner/hidl/TunerHidlTimeFilter.cpp b/services/tuner/hidl/TunerHidlTimeFilter.cpp
new file mode 100644
index 0000000..d0606d6
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlTimeFilter.cpp
@@ -0,0 +1,133 @@
+/**
+ * Copyright 2021, 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 "TunerHidlTimeFilter"
+
+#include "TunerHidlTimeFilter.h"
+
+#include <aidl/android/hardware/tv/tuner/Constant64Bit.h>
+#include <aidl/android/hardware/tv/tuner/Result.h>
+
+using ::aidl::android::hardware::tv::tuner::Constant64Bit;
+using ::aidl::android::hardware::tv::tuner::Result;
+
+using HidlResult = ::android::hardware::tv::tuner::V1_0::Result;
+
+using namespace std;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+TunerHidlTimeFilter::TunerHidlTimeFilter(sp<HidlITimeFilter> timeFilter) {
+    mTimeFilter = timeFilter;
+}
+
+TunerHidlTimeFilter::~TunerHidlTimeFilter() {
+    mTimeFilter = nullptr;
+}
+
+::ndk::ScopedAStatus TunerHidlTimeFilter::setTimeStamp(int64_t timeStamp) {
+    if (mTimeFilter == nullptr) {
+        ALOGE("ITimeFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mTimeFilter->setTimeStamp(static_cast<uint64_t>(timeStamp));
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlTimeFilter::clearTimeStamp() {
+    if (mTimeFilter == nullptr) {
+        ALOGE("ITimeFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status = mTimeFilter->clearTimeStamp();
+    if (status != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlTimeFilter::getSourceTime(int64_t* _aidl_return) {
+    if (mTimeFilter == nullptr) {
+        *_aidl_return = (int64_t)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+        ALOGE("ITimeFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status;
+    mTimeFilter->getSourceTime([&](HidlResult r, uint64_t t) {
+        status = r;
+        *_aidl_return = static_cast<int64_t>(t);
+    });
+    if (status != HidlResult::SUCCESS) {
+        *_aidl_return = static_cast<int64_t>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlTimeFilter::getTimeStamp(int64_t* _aidl_return) {
+    if (mTimeFilter == nullptr) {
+        *_aidl_return = (int64_t)Constant64Bit::INVALID_PRESENTATION_TIME_STAMP;
+        ALOGE("ITimeFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult status;
+    mTimeFilter->getTimeStamp([&](HidlResult r, uint64_t t) {
+        status = r;
+        *_aidl_return = static_cast<int64_t>(t);
+    });
+    if (status != HidlResult::SUCCESS) {
+        *_aidl_return = static_cast<int64_t>(Constant64Bit::INVALID_PRESENTATION_TIME_STAMP);
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus TunerHidlTimeFilter::close() {
+    if (mTimeFilter == nullptr) {
+        ALOGE("ITimeFilter is not initialized");
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(
+                static_cast<int32_t>(Result::UNAVAILABLE));
+    }
+
+    HidlResult res = mTimeFilter->close();
+    mTimeFilter = nullptr;
+
+    if (res != HidlResult::SUCCESS) {
+        return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+    }
+    return ::ndk::ScopedAStatus::ok();
+}
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
diff --git a/services/tuner/hidl/TunerHidlTimeFilter.h b/services/tuner/hidl/TunerHidlTimeFilter.h
new file mode 100644
index 0000000..97d59dc
--- /dev/null
+++ b/services/tuner/hidl/TunerHidlTimeFilter.h
@@ -0,0 +1,58 @@
+/**
+ * Copyright 2021, 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_MEDIA_TUNERHIDLTIMEFILTER_H
+#define ANDROID_MEDIA_TUNERHIDLTIMEFILTER_H
+
+#include <aidl/android/media/tv/tuner/BnTunerTimeFilter.h>
+#include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <utils/Log.h>
+
+using ::android::sp;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using HidlITimeFilter = ::android::hardware::tv::tuner::V1_0::ITimeFilter;
+
+namespace aidl {
+namespace android {
+namespace media {
+namespace tv {
+namespace tuner {
+
+class TunerHidlTimeFilter : public BnTunerTimeFilter {
+public:
+    TunerHidlTimeFilter(sp<HidlITimeFilter> timeFilter);
+    virtual ~TunerHidlTimeFilter();
+
+    ::ndk::ScopedAStatus setTimeStamp(int64_t in_timeStamp) override;
+    ::ndk::ScopedAStatus clearTimeStamp() override;
+    ::ndk::ScopedAStatus getSourceTime(int64_t* _aidl_return) override;
+    ::ndk::ScopedAStatus getTimeStamp(int64_t* _aidl_return) override;
+    ::ndk::ScopedAStatus close() override;
+
+private:
+    sp<HidlITimeFilter> mTimeFilter;
+};
+
+}  // namespace tuner
+}  // namespace tv
+}  // namespace media
+}  // namespace android
+}  // namespace aidl
+
+#endif  // ANDROID_MEDIA_TUNERHIDLTIMEFILTER_H