Merge changes from topics "ion", "scan" into rvc-dev

* changes:
  Align Tuner VTS scan tests with the latest scan mechanism
  Copy filtered av data to ion buffer to test on cuttlefish
diff --git a/tv/tuner/1.0/default/Android.bp b/tv/tuner/1.0/default/Android.bp
index 989e25c..5711889 100644
--- a/tv/tuner/1.0/default/Android.bp
+++ b/tv/tuner/1.0/default/Android.bp
@@ -24,6 +24,7 @@
         "libfmq",
         "libhidlbase",
         "libhidlmemory",
+        "libion",
         "liblog",
         "libstagefright_foundation",
         "libutils",
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index 54d0952..f610c60 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -60,6 +60,8 @@
 Return<void> Filter::getQueueDesc(getQueueDesc_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
+    mIsUsingFMQ = true;
+
     _hidl_cb(Result::SUCCESS, *mFilterMQ->getDesc());
     return Void();
 }
@@ -120,9 +122,13 @@
     return Result::SUCCESS;
 }
 
-Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t /*avDataId*/) {
+Return<Result> Filter::releaseAvHandle(const hidl_handle& /*avMemory*/, uint64_t avDataId) {
     ALOGV("%s", __FUNCTION__);
+    if (mDataId2Avfd.find(avDataId) == mDataId2Avfd.end()) {
+        return Result::INVALID_ARGUMENT;
+    }
 
+    ::close(mDataId2Avfd[avDataId]);
     return Result::SUCCESS;
 }
 
@@ -174,14 +180,21 @@
     // Event Callback without waiting for the DATA_CONSUMED to init the process.
     while (mFilterThreadRunning) {
         if (mFilterEvent.events.size() == 0) {
-            ALOGD("[Filter] wait for filter data output.");
+            if (DEBUG_FILTER) {
+                ALOGD("[Filter] wait for filter data output.");
+            }
             usleep(1000 * 1000);
             continue;
         }
         // After successfully write, send a callback and wait for the read to be done
         mCallback->onFilterEvent(mFilterEvent);
+        freeAvHandle();
         mFilterEvent.events.resize(0);
         mFilterStatus = DemuxFilterStatus::DATA_READY;
+        if (mCallback == nullptr) {
+            ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId);
+            break;
+        }
         mCallback->onFilterStatus(mFilterStatus);
         break;
     }
@@ -191,7 +204,7 @@
         // We do not wait for the last round of written data to be read to finish the thread
         // because the VTS can verify the reading itself.
         for (int i = 0; i < SECTION_WRITE_COUNT; i++) {
-            while (mFilterThreadRunning) {
+            while (mFilterThreadRunning && mIsUsingFMQ) {
                 status_t status = mFilterEventFlag->wait(
                         static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED), &efState,
                         WAIT_TIMEOUT, true /* retry on spurious wake */);
@@ -202,11 +215,6 @@
                 break;
             }
 
-            if (mCallback == nullptr) {
-                ALOGD("[Filter] filter %d does not hava callback. Ending thread", mFilterId);
-                break;
-            }
-
             maySendFilterStatusCallback();
 
             while (mFilterThreadRunning) {
@@ -232,7 +240,22 @@
     ALOGD("[Filter] filter thread ended.");
 }
 
+void Filter::freeAvHandle() {
+    if (mType.mainType != DemuxFilterMainType::TS ||
+        (mType.subType.tsFilterType() == DemuxTsFilterType::AUDIO &&
+         mType.subType.tsFilterType() == DemuxTsFilterType::VIDEO)) {
+        return;
+    }
+    for (int i = 0; i < mFilterEvent.events.size(); i++) {
+        ::close(mFilterEvent.events[i].media().avMemory.getNativeHandle()->data[0]);
+        native_handle_close(mFilterEvent.events[i].media().avMemory.getNativeHandle());
+    }
+}
+
 void Filter::maySendFilterStatusCallback() {
+    if (!mIsUsingFMQ) {
+        return;
+    }
     std::lock_guard<std::mutex> lock(mFilterStatusLock);
     int availableToRead = mFilterMQ->availableToRead();
     int availableToWrite = mFilterMQ->availableToWrite();
@@ -409,19 +432,88 @@
 }
 
 Result Filter::startMediaFilterHandler() {
-    DemuxFilterMediaEvent mediaEvent;
-    mediaEvent = {
-            // temp dump meta data
-            .pts = 0,
-            .dataLength = 530,
-            .avMemory = nullptr,
-            .isSecureMemory = false,
-    };
-    mFilterEvent.events.resize(1);
-    mFilterEvent.events[0].media(mediaEvent);
+    std::lock_guard<std::mutex> lock(mFilterEventLock);
+    if (mFilterOutput.empty()) {
+        return Result::SUCCESS;
+    }
+
+    for (int i = 0; i < mFilterOutput.size(); i += 188) {
+        if (mPesSizeLeft == 0) {
+            uint32_t prefix = (mFilterOutput[i + 4] << 16) | (mFilterOutput[i + 5] << 8) |
+                              mFilterOutput[i + 6];
+            if (DEBUG_FILTER) {
+                ALOGD("[Filter] prefix %d", prefix);
+            }
+            if (prefix == 0x000001) {
+                // TODO handle mulptiple Pes filters
+                mPesSizeLeft = (mFilterOutput[i + 8] << 8) | mFilterOutput[i + 9];
+                mPesSizeLeft += 6;
+                if (DEBUG_FILTER) {
+                    ALOGD("[Filter] pes data length %d", mPesSizeLeft);
+                }
+            } else {
+                continue;
+            }
+        }
+
+        int endPoint = min(184, mPesSizeLeft);
+        // append data and check size
+        vector<uint8_t>::const_iterator first = mFilterOutput.begin() + i + 4;
+        vector<uint8_t>::const_iterator last = mFilterOutput.begin() + i + 4 + endPoint;
+        mPesOutput.insert(mPesOutput.end(), first, last);
+        // size does not match then continue
+        mPesSizeLeft -= endPoint;
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] pes data left %d", mPesSizeLeft);
+        }
+        if (mPesSizeLeft > 0 || mAvBufferCopyCount++ < 10) {
+            continue;
+        }
+
+        int av_fd = createAvIonFd(mPesOutput.size());
+        if (av_fd == -1) {
+            return Result::UNKNOWN_ERROR;
+        }
+        // copy the filtered data to the buffer
+        uint8_t* avBuffer = getIonBuffer(av_fd, mPesOutput.size());
+        if (avBuffer == NULL) {
+            return Result::UNKNOWN_ERROR;
+        }
+        memcpy(avBuffer, mPesOutput.data(), mPesOutput.size() * sizeof(uint8_t));
+
+        native_handle_t* nativeHandle = createNativeHandle(av_fd);
+        if (nativeHandle == NULL) {
+            return Result::UNKNOWN_ERROR;
+        }
+        hidl_handle handle;
+        handle.setTo(nativeHandle, /*shouldOwn=*/true);
+
+        // Create a dataId and add a <dataId, av_fd> pair into the dataId2Avfd map
+        uint64_t dataId = mLastUsedDataId++ /*createdUID*/;
+        mDataId2Avfd[dataId] = dup(av_fd);
+
+        // Create mediaEvent and send callback
+        DemuxFilterMediaEvent mediaEvent;
+        mediaEvent = {
+                .avMemory = std::move(handle),
+                .dataLength = static_cast<uint32_t>(mPesOutput.size()),
+                .avDataId = dataId,
+        };
+        int size = mFilterEvent.events.size();
+        mFilterEvent.events.resize(size + 1);
+        mFilterEvent.events[size].media(mediaEvent);
+
+        // Clear and log
+        mPesOutput.clear();
+        mAvBufferCopyCount = 0;
+        ::close(av_fd);
+        if (DEBUG_FILTER) {
+            ALOGD("[Filter] assembled av data length %d", mediaEvent.dataLength);
+        }
+    }
 
     mFilterOutput.clear();
-    // TODO handle write FQM for media stream
+
     return Result::SUCCESS;
 }
 
@@ -493,6 +585,42 @@
     mDvr = nullptr;
 }
 
+int Filter::createAvIonFd(int size) {
+    // Create an ion fd and allocate an av fd mapped to a buffer to it.
+    int ion_fd = ion_open();
+    if (ion_fd == -1) {
+        ALOGE("[Filter] Failed to open ion fd %d", errno);
+        return -1;
+    }
+    int av_fd = -1;
+    ion_alloc_fd(dup(ion_fd), size, 0 /*align*/, ION_HEAP_SYSTEM_MASK, 0 /*flags*/, &av_fd);
+    if (av_fd == -1) {
+        ALOGE("[Filter] Failed to create av fd %d", errno);
+        return -1;
+    }
+    return av_fd;
+}
+
+uint8_t* Filter::getIonBuffer(int fd, int size) {
+    uint8_t* avBuf = static_cast<uint8_t*>(
+            mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 /*offset*/));
+    if (avBuf == MAP_FAILED) {
+        ALOGE("[Filter] fail to allocate buffer %d", errno);
+        return NULL;
+    }
+    return avBuf;
+}
+
+native_handle_t* Filter::createNativeHandle(int fd) {
+    // Create a native handle to pass the av fd via the callback event.
+    native_handle_t* nativeHandle = native_handle_create(/*numFd*/ 1, 0);
+    if (nativeHandle == NULL) {
+        ALOGE("[Filter] Failed to create native_handle %d", errno);
+        return NULL;
+    }
+    nativeHandle->data[0] = dup(fd);
+    return nativeHandle;
+}
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index 0dc992a..afed98e 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/tv/tuner/1.0/IFilter.h>
 #include <fmq/MessageQueue.h>
+#include <ion/ion.h>
 #include <math.h>
 #include <set>
 #include "Demux.h"
@@ -87,6 +88,7 @@
     Result startRecordFilterHandler();
     void attachFilterToRecord(const sp<Dvr> dvr);
     void detachFilterFromRecord();
+    void freeAvHandle();
 
   private:
     // Tuner service
@@ -109,6 +111,7 @@
     vector<uint8_t> mFilterOutput;
     vector<uint8_t> mRecordFilterOutput;
     unique_ptr<FilterMQ> mFilterMQ;
+    bool mIsUsingFMQ = false;
     EventFlag* mFilterEventFlag;
     DemuxFilterEvent mFilterEvent;
 
@@ -160,6 +163,10 @@
     static void* __threadLoopFilter(void* user);
     void filterThreadLoop();
 
+    int createAvIonFd(int size);
+    uint8_t* getIonBuffer(int fd, int size);
+    native_handle_t* createNativeHandle(int fd);
+
     /**
      * Lock to protect writes to the FMQs
      */
@@ -181,6 +188,11 @@
     // TODO handle mulptiple Pes filters
     int mPesSizeLeft = 0;
     vector<uint8_t> mPesOutput;
+
+    // A map from data id to ion handle
+    std::map<uint64_t, int> mDataId2Avfd;
+    uint64_t mLastUsedDataId = 1;
+    int mAvBufferCopyCount = 0;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 7e206a7..bb0d8dc 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -63,9 +63,6 @@
         return Result::INVALID_STATE;
     }
 
-    // TODO dynamically allocate file to the source file
-    mSourceStreamFile = FRONTEND_STREAM_FILE;
-
     mCallback->onEvent(FrontendEventType::LOCKED);
     return Result::SUCCESS;
 }
@@ -180,7 +177,7 @@
 }
 
 string Frontend::getSourceFile() {
-    return mSourceStreamFile;
+    return FRONTEND_STREAM_FILE;
 }
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
index eab43a3..b954639 100644
--- a/tv/tuner/1.0/default/Frontend.h
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -76,7 +76,6 @@
     FrontendId mId = 0;
 
     const string FRONTEND_STREAM_FILE = "/vendor/etc/dumpTs3.ts";
-    string mSourceStreamFile;
     std::ifstream mFrontendData;
 };
 
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index 4fd3355..8fb5061 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -106,7 +106,7 @@
     return Void();
 }
 
-Return<void> Tuner::getFrontendInfo(FrontendId /* frontendId */, getFrontendInfo_cb _hidl_cb) {
+Return<void> Tuner::getFrontendInfo(FrontendId /*frontendId*/, getFrontendInfo_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
     vector<FrontendStatusType> statusCaps = {
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index f693e7c..8b0413c 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -47,7 +47,6 @@
 #include "VtsHalTvTunerV1_0TestConfigurations.h"
 
 #define WAIT_TIMEOUT 3000000000
-#define WAIT_TIMEOUT_data_ready 3000000000 * 4
 
 using android::Condition;
 using android::IMemory;
@@ -57,6 +56,7 @@
 using android::sp;
 using android::hardware::EventFlag;
 using android::hardware::fromHeap;
+using android::hardware::hidl_handle;
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
 using android::hardware::HidlMemory;
@@ -68,6 +68,7 @@
 using android::hardware::tv::tuner::V1_0::DataFormat;
 using android::hardware::tv::tuner::V1_0::DemuxFilterEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
+using android::hardware::tv::tuner::V1_0::DemuxFilterMediaEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterPesDataSettings;
 using android::hardware::tv::tuner::V1_0::DemuxFilterPesEvent;
 using android::hardware::tv::tuner::V1_0::DemuxFilterRecordSettings;
@@ -156,7 +157,6 @@
 // const uint16_t FMQ_SIZE_4K = 0x1000;
 const uint32_t FMQ_SIZE_1M = 0x100000;
 const uint32_t FMQ_SIZE_16M = 0x1000000;
-const uint8_t FRONTEND_EVENT_CALLBACK_WAIT_COUNT = 4;
 
 enum FilterEventType : uint8_t {
     UNDEFINED,
@@ -179,52 +179,65 @@
   public:
     virtual Return<void> onEvent(FrontendEventType frontendEventType) override {
         android::Mutex::Autolock autoLock(mMsgLock);
+        ALOGD("[vts] frontend event received. Type: %d", frontendEventType);
         mEventReceived = true;
-        mEventType = frontendEventType;
         mMsgCondition.signal();
-        return Void();
+        switch (frontendEventType) {
+            case FrontendEventType::LOCKED:
+                mLockMsgReceived = true;
+                mLockMsgCondition.signal();
+                return Void();
+            default:
+                // do nothing
+                return Void();
+        }
     }
 
     virtual Return<void> onScanMessage(FrontendScanMessageType type,
                                        const FrontendScanMessage& message) override {
         android::Mutex::Autolock autoLock(mMsgLock);
-        ALOGD("[vts] scan message. Type: %d", mScanMessageType);
+        while (!mScanMsgProcessed) {
+            mMsgCondition.wait(mMsgLock);
+        }
+        ALOGD("[vts] frontend scan message. Type: %d", type);
         mScanMessageReceived = true;
+        mScanMsgProcessed = false;
         mScanMessageType = type;
-        mScanLockMessageReceived =
-                mScanLockMessageReceived | (type == FrontendScanMessageType::LOCKED);
         mScanMessage = message;
         mMsgCondition.signal();
         return Void();
-    };
+    }
 
     void tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings);
     void tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings);
-    void scanTestOnMessageLock(sp<IFrontend>& frontend, FrontendSettings settings,
-                               FrontendScanType type);
+    void scanTest(sp<IFrontend>& frontend, FrontendConfig config, FrontendScanType type);
+
+    // Helper methods
+    uint32_t getTargetFrequency(FrontendSettings settings, FrontendType type);
+    void resetBlindScanStartingFrequency(FrontendConfig config, uint32_t resetingFreq);
 
   private:
     bool mEventReceived = false;
     bool mScanMessageReceived = false;
-    bool mScanLockMessageReceived = false;
-    FrontendEventType mEventType;
+    bool mLockMsgReceived = false;
+    bool mScanMsgProcessed = true;
     FrontendScanMessageType mScanMessageType;
     FrontendScanMessage mScanMessage;
     hidl_vec<uint8_t> mEventMessage;
     android::Mutex mMsgLock;
     android::Condition mMsgCondition;
-    uint8_t mOnEvenRetry = 0;
+    android::Condition mLockMsgCondition;
 };
 
 void FrontendCallback::tuneTestOnEventReceive(sp<IFrontend>& frontend, FrontendSettings settings) {
     Result result = frontend->tune(settings);
-
     EXPECT_TRUE(result == Result::SUCCESS);
 
     android::Mutex::Autolock autoLock(mMsgLock);
     while (!mEventReceived) {
         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "event not received within timeout";
+            EXPECT_TRUE(false) << "Event not received within timeout";
+            mLockMsgReceived = false;
             return;
         }
     }
@@ -233,61 +246,134 @@
 
 void FrontendCallback::tuneTestOnLock(sp<IFrontend>& frontend, FrontendSettings settings) {
     Result result = frontend->tune(settings);
-
     EXPECT_TRUE(result == Result::SUCCESS);
 
     android::Mutex::Autolock autoLock(mMsgLock);
-wait:
-    while (!mEventReceived) {
-        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            EXPECT_TRUE(false) << "event not received within timeout";
+    while (!mLockMsgReceived) {
+        if (-ETIMEDOUT == mLockMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "Event LOCKED not received within timeout";
+            mLockMsgReceived = false;
             return;
         }
     }
-    if (mEventType != FrontendEventType::LOCKED) {
-        ALOGD("[vts] frontend callback event received. Type: %d", mEventType);
-        mEventReceived = false;
-        if (mOnEvenRetry++ < FRONTEND_EVENT_CALLBACK_WAIT_COUNT) {
-            goto wait;
-        }
-    }
-    EXPECT_TRUE(mEventType == FrontendEventType::LOCKED) << "LOCK event not received";
-    mEventReceived = false;
-    mOnEvenRetry = 0;
+    mLockMsgReceived = false;
 }
 
-void FrontendCallback::scanTestOnMessageLock(sp<IFrontend>& frontend, FrontendSettings settings,
-                                             FrontendScanType type) {
-    Result result = frontend->scan(settings, type);
-    EXPECT_TRUE(result == Result::SUCCESS);
-    android::Mutex::Autolock autoLock(mMsgLock);
-    int messagesCount = 0;
+void FrontendCallback::scanTest(sp<IFrontend>& frontend, FrontendConfig config,
+                                FrontendScanType type) {
+    uint32_t targetFrequency = getTargetFrequency(config.settings, config.type);
+    if (type == FrontendScanType::SCAN_BLIND) {
+        // reset the frequency in the scan configuration to test blind scan. The settings param of
+        // passed in means the real input config on the transponder connected to the DUT.
+        // We want the blind the test to start from lower frequency than this to check the blind
+        // scan implementation.
+        resetBlindScanStartingFrequency(config, targetFrequency - 100);
+    }
 
+    Result result = frontend->scan(config.settings, type);
+    EXPECT_TRUE(result == Result::SUCCESS);
+
+    bool scanMsgLockedReceived = false;
+    bool targetFrequencyReceived = false;
+
+    android::Mutex::Autolock autoLock(mMsgLock);
 wait:
-    int count = 0;
     while (!mScanMessageReceived) {
         if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
-            ALOGD("[vts] waiting for scan message callback...");
-            if (count++ > 10) {
-                EXPECT_TRUE(false) << "WAITING TOO LONG!!";
-                return;
-            }
+            EXPECT_TRUE(false) << "Scan message not received within timeout";
+            mScanMessageReceived = false;
+            mScanMsgProcessed = true;
+            return;
         }
     }
 
     if (mScanMessageType != FrontendScanMessageType::END) {
-        ALOGD("[vts] frontend scan message received. Type: %d", mScanMessageType);
-        mScanMessageReceived = false;
-        if (messagesCount++ > 3) {
-            EXPECT_TRUE(false) << "WAITING ON TOO MANY MSGS!!";
-            return;
+        if (mScanMessageType == FrontendScanMessageType::LOCKED) {
+            scanMsgLockedReceived = true;
+            Result result = frontend->scan(config.settings, type);
+            EXPECT_TRUE(result == Result::SUCCESS);
         }
+
+        if (mScanMessageType == FrontendScanMessageType::FREQUENCY) {
+            targetFrequencyReceived = mScanMessage.frequencies().size() > 0 &&
+                                      mScanMessage.frequencies()[0] == targetFrequency;
+        }
+
+        if (mScanMessageType == FrontendScanMessageType::PROGRESS_PERCENT) {
+            ALOGD("[vts] Scan in progress...[%d%%]", mScanMessage.progressPercent());
+        }
+
+        mScanMessageReceived = false;
+        mScanMsgProcessed = true;
+        mMsgCondition.signal();
         goto wait;
     }
 
-    EXPECT_TRUE(mScanLockMessageReceived) << "scan lock message not received before scan ended";
+    EXPECT_TRUE(scanMsgLockedReceived) << "Scan message LOCKED not received before END";
+    EXPECT_TRUE(targetFrequencyReceived) << "frequency not received before LOCKED on blindScan";
     mScanMessageReceived = false;
-    mScanLockMessageReceived = false;
+    mScanMsgProcessed = true;
+}
+
+uint32_t FrontendCallback::getTargetFrequency(FrontendSettings settings, FrontendType type) {
+    switch (type) {
+        case FrontendType::ANALOG:
+            return settings.analog().frequency;
+        case FrontendType::ATSC:
+            return settings.atsc().frequency;
+        case FrontendType::ATSC3:
+            return settings.atsc3().frequency;
+        case FrontendType::DVBC:
+            return settings.dvbc().frequency;
+        case FrontendType::DVBS:
+            return settings.dvbs().frequency;
+        case FrontendType::DVBT:
+            return settings.dvbt().frequency;
+        case FrontendType::ISDBS:
+            return settings.isdbs().frequency;
+        case FrontendType::ISDBS3:
+            return settings.isdbs3().frequency;
+        case FrontendType::ISDBT:
+            return settings.isdbt().frequency;
+        default:
+            return 0;
+    }
+}
+
+void FrontendCallback::resetBlindScanStartingFrequency(FrontendConfig config,
+                                                       uint32_t resetingFreq) {
+    switch (config.type) {
+        case FrontendType::ANALOG:
+            config.settings.analog().frequency = resetingFreq;
+            break;
+        case FrontendType::ATSC:
+            config.settings.atsc().frequency = resetingFreq;
+            break;
+        case FrontendType::ATSC3:
+            config.settings.atsc3().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBC:
+            config.settings.dvbc().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBS:
+            config.settings.dvbs().frequency = resetingFreq;
+            break;
+        case FrontendType::DVBT:
+            config.settings.dvbt().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBS:
+            config.settings.isdbs().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBS3:
+            config.settings.isdbs3().frequency = resetingFreq;
+            break;
+        case FrontendType::ISDBT:
+            config.settings.isdbt().frequency = resetingFreq;
+            break;
+        default:
+            // do nothing
+            return;
+    }
 }
 /******************************** End FrontendCallback **********************************/
 
@@ -313,6 +399,7 @@
     }
 
     void setFilterId(uint32_t filterId) { mFilterId = filterId; }
+    void setFilterInterface(sp<IFilter> filter) { mFilter = filter; }
     void setFilterEventType(FilterEventType type) { mFilterEventType = type; }
 
     void testFilterDataOutput();
@@ -324,6 +411,7 @@
     void updateFilterMQ(MQDesc& filterMQDescriptor);
     void updateGoldenOutputMap(string goldenOutputFile);
     bool readFilterEventData();
+    bool dumpAvData(DemuxFilterMediaEvent event);
 
   private:
     struct FilterThreadArgs {
@@ -336,6 +424,7 @@
     string mFilterIdToGoldenOutput;
 
     uint32_t mFilterId;
+    sp<IFilter> mFilter;
     FilterEventType mFilterEventType;
     std::unique_ptr<FilterMQ> mFilterMQ;
     EventFlag* mFilterMQEventFlag;
@@ -407,7 +496,7 @@
 bool FilterCallback::readFilterEventData() {
     bool result = false;
     DemuxFilterEvent filterEvent = mFilterEvent;
-    ALOGW("[vts] reading from filter FMQ %d", mFilterId);
+    ALOGW("[vts] reading from filter FMQ or buffer %d", mFilterId);
     // todo separate filter handlers
     for (int i = 0; i < filterEvent.events.size(); i++) {
         switch (mFilterEventType) {
@@ -418,8 +507,7 @@
                 mDataLength = filterEvent.events[i].pes().dataLength;
                 break;
             case FilterEventType::MEDIA:
-                mDataLength = filterEvent.events[i].media().dataLength;
-                break;
+                return dumpAvData(filterEvent.events[i].media());
             case FilterEventType::RECORD:
                 break;
             case FilterEventType::MMTPRECORD:
@@ -443,6 +531,26 @@
     mFilterMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED));
     return result;
 }
+
+bool FilterCallback::dumpAvData(DemuxFilterMediaEvent event) {
+    uint32_t length = event.dataLength;
+    uint64_t dataId = event.avDataId;
+    // read data from buffer pointed by a handle
+    hidl_handle handle = event.avMemory;
+
+    int av_fd = handle.getNativeHandle()->data[0];
+    uint8_t* buffer = static_cast<uint8_t*>(
+            mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0 /*offset*/));
+    if (buffer == MAP_FAILED) {
+        ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
+        return false;
+    }
+    uint8_t output[length + 1];
+    memcpy(output, buffer, length);
+    // print buffer and check with golden output.
+    EXPECT_TRUE(mFilter->releaseAvHandle(handle, dataId) == Result::SUCCESS);
+    return true;
+}
 /******************************** End FilterCallback **********************************/
 
 /******************************** Start DvrCallback **********************************/
@@ -731,6 +839,7 @@
     sp<IFilter> mFilter;
     std::map<uint32_t, sp<IFilter>> mFilters;
     std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks;
+
     sp<FilterCallback> mFilterCallback;
     sp<DvrCallback> mDvrCallback;
     MQDesc mFilterMQDescriptor;
@@ -826,7 +935,7 @@
     EXPECT_TRUE(mFrontendInfo.type == config.type)
             << "FrontendConfig does not match the frontend info of the given id.";
 
-    mFrontendCallback->scanTestOnMessageLock(mFrontend, config.settings, type);
+    mFrontendCallback->scanTest(mFrontend, config, type);
     return AssertionResult(true);
 }
 
@@ -926,13 +1035,14 @@
 
     if (status == Result::SUCCESS) {
         mFilterCallback->setFilterId(mFilterId);
+        mFilterCallback->setFilterInterface(mFilter);
         mUsedFilterIds.insert(mUsedFilterIds.end(), mFilterId);
         mFilters[mFilterId] = mFilter;
         mFilterCallbacks[mFilterId] = mFilterCallback;
         filterId = mFilterId;
     }
 
-    return AssertionResult(status == Result::SUCCESS || status == Result::UNAVAILABLE);
+    return AssertionResult(status == Result::SUCCESS);
 }
 
 AssertionResult TunerHidlTest::configFilter(DemuxFilterSettings setting, uint32_t filterId) {
@@ -1300,7 +1410,6 @@
         }
         ASSERT_TRUE(openFrontend(mFeIds[i]));
         ASSERT_TRUE(setFrontendCallback());
-        ASSERT_TRUE(stopTuneFrontend());
         ASSERT_TRUE(tuneFrontend(frontendArray[0]));
         ASSERT_TRUE(stopTuneFrontend());
         ASSERT_TRUE(closeFrontend());
@@ -1320,13 +1429,31 @@
         }
         ASSERT_TRUE(openFrontend(mFeIds[i]));
         ASSERT_TRUE(setFrontendCallback());
-        ASSERT_TRUE(stopScanFrontend());
         ASSERT_TRUE(scanFrontend(frontendScanArray[0], FrontendScanType::SCAN_AUTO));
         ASSERT_TRUE(stopScanFrontend());
         ASSERT_TRUE(closeFrontend());
         break;
     }
 }
+
+TEST_P(TunerHidlTest, BlindScanFrontend) {
+    description("Run an blind frontend scan with specific setting and check lock scanMessage");
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
+
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        if (mFrontendInfo.type != frontendArray[0].type) {
+            continue;
+        }
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(setFrontendCallback());
+        ASSERT_TRUE(scanFrontend(frontendScanArray[0], FrontendScanType::SCAN_BLIND));
+        ASSERT_TRUE(stopScanFrontend());
+        ASSERT_TRUE(closeFrontend());
+        break;
+    }
+}
 /*=============================== End Frontend Tests ===============================*/
 
 /*============================ Start Demux/Filter Tests ============================*/
@@ -1535,6 +1662,39 @@
 
     ASSERT_TRUE(recordDataFlowTest(filterConf, recordSetting, goldenOutputFiles));
 }*/
+
+TEST_P(TunerHidlTest, AvBufferTest) {
+    description("Test the av filter data bufferring.");
+
+    ASSERT_TRUE(getFrontendIds());
+    ASSERT_TRUE(mFeIds.size() > 0);
+
+    for (size_t i = 0; i < mFeIds.size(); i++) {
+        ASSERT_TRUE(getFrontendInfo(mFeIds[i]));
+        if (mFrontendInfo.type != frontendArray[1].type) {
+            continue;
+        }
+        ASSERT_TRUE(openFrontend(mFeIds[i]));
+        ASSERT_TRUE(setFrontendCallback());
+        ASSERT_TRUE(openDemux());
+        ASSERT_TRUE(openFilterInDemux(filterArray[0].type));
+        uint32_t filterId;
+        ASSERT_TRUE(getNewlyOpenedFilterId(filterId));
+        ASSERT_TRUE(configFilter(filterArray[0].setting, filterId));
+        ASSERT_TRUE(startFilter(filterId));
+        ASSERT_TRUE(setDemuxFrontendDataSource(mFeIds[i]));
+        // tune test
+        ASSERT_TRUE(tuneFrontend(frontendArray[1]));
+        // broadcast data flow test
+        ASSERT_TRUE(broadcastDataFlowTest(goldenOutputFiles));
+        ASSERT_TRUE(stopTuneFrontend());
+        ASSERT_TRUE(stopFilter(filterId));
+        ASSERT_TRUE(closeFilter(filterId));
+        ASSERT_TRUE(closeDemux());
+        ASSERT_TRUE(closeFrontend());
+        break;
+    }
+}
 /*============================== End Data Flow Tests ==============================*/
 /******************************** End Test Entry **********************************/
 }  // namespace
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
index 55ca857..31e3b51 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -64,7 +64,7 @@
 
 namespace {
 
-#define frontend_transponders_count 1
+#define frontend_transponders_count 2
 #define channels_count 1
 #define frontend_scan_count 1
 #define filter_count 2
@@ -108,13 +108,24 @@
             .standard = FrontendDvbtStandard::T,
     };
     frontendArray[0].type = FrontendType::DVBT, frontendArray[0].settings.dvbt(dvbtSettings);
+    frontendArray[1].type = FrontendType::DVBS;
 };
 
 /** Configuration array for the frontend scan test */
 inline void initFrontendScanConfig() {
-    frontendScanArray[0].type = FrontendType::DVBT, frontendScanArray[0].settings.dvbt({
-                                                            .frequency = 577000,
-                                                    });
+    frontendScanArray[0].type = FrontendType::DVBT;
+    frontendScanArray[0].settings.dvbt({
+            .frequency = 578000,
+            .transmissionMode = FrontendDvbtTransmissionMode::MODE_8K,
+            .bandwidth = FrontendDvbtBandwidth::BANDWIDTH_8MHZ,
+            .constellation = FrontendDvbtConstellation::AUTO,
+            .hierarchy = FrontendDvbtHierarchy::AUTO,
+            .hpCoderate = FrontendDvbtCoderate::AUTO,
+            .lpCoderate = FrontendDvbtCoderate::AUTO,
+            .guardInterval = FrontendDvbtGuardInterval::AUTO,
+            .isHighPriority = true,
+            .standard = FrontendDvbtStandard::T,
+    });
 };
 
 /** Configuration array for the filter test */
@@ -122,7 +133,7 @@
     // TS Video filter setting
     filterArray[0].type.mainType = DemuxFilterMainType::TS;
     filterArray[0].type.subType.tsFilterType(DemuxTsFilterType::VIDEO);
-    filterArray[0].setting.ts().tpid = 49;
+    filterArray[0].setting.ts().tpid = 119;
     filterArray[0].setting.ts().filterSettings.av({.isPassthrough = false});
     // TS PES filter setting
     filterArray[1].type.mainType = DemuxFilterMainType::TS;
@@ -134,4 +145,4 @@
     });
 };
 
-}  // namespace
\ No newline at end of file
+}  // namespace