Add startId in Filter Event to work with filter reconfiguration

Test: atest VtsHalTvTunerV1_1TargetTest
Bug: 172593389
Change-Id: I77e45366b737068aa0aa20c2b384f2e3160c7398
diff --git a/tv/tuner/1.1/IFilter.hal b/tv/tuner/1.1/IFilter.hal
index df736aa..1c6c33f 100644
--- a/tv/tuner/1.1/IFilter.hal
+++ b/tv/tuner/1.1/IFilter.hal
@@ -26,6 +26,8 @@
  * To access the v1.1 IFilter APIs, the implementation can cast the IFilter
  * interface returned from the @1.0::IDemux openFilter into a v1.1 IFiler
  * using V1_1::IFilter::castFrom(V1_0::IFilter).
+ *
+ * Note that reconfiguring Filter must happen after the Filter is stopped.
  */
 interface IFilter extends @1.0::IFilter {
     /**
diff --git a/tv/tuner/1.1/IFilterCallback.hal b/tv/tuner/1.1/IFilterCallback.hal
index 9960a23..23ae844 100644
--- a/tv/tuner/1.1/IFilterCallback.hal
+++ b/tv/tuner/1.1/IFilterCallback.hal
@@ -25,7 +25,8 @@
      * Notify the client that a new filter event happened.
      *
      * @param filterEvent a v1_0 filter event.
-     * @param filterEventExt a v1_1 extended filter event.
+     * @param filterEventExt a v1_1 extended filter event. Send an empty filterEvent along with
+     *                       startId or scramblingStatus filterEventExt
      */
     oneway onFilterEvent_1_1(DemuxFilterEvent filterEvent, DemuxFilterEventExt filterEventExt);
 };
diff --git a/tv/tuner/1.1/default/Filter.cpp b/tv/tuner/1.1/default/Filter.cpp
index 139e98a..e766a8a 100644
--- a/tv/tuner/1.1/default/Filter.cpp
+++ b/tv/tuner/1.1/default/Filter.cpp
@@ -131,6 +131,7 @@
             break;
     }
 
+    mConfigured = true;
     return Result::SUCCESS;
 }
 
@@ -145,8 +146,6 @@
 
     mFilterThreadRunning = false;
 
-    std::lock_guard<std::mutex> lock(mFilterThreadLock);
-
     return Result::SUCCESS;
 }
 
@@ -321,8 +320,17 @@
             usleep(1000 * 1000);
             continue;
         }
+
         // After successfully write, send a callback and wait for the read to be done
         if (mCallback_1_1 != nullptr) {
+            if (mConfigured) {
+                DemuxFilterEvent emptyEvent;
+                V1_1::DemuxFilterEventExt startEvent;
+                startEvent.events.resize(1);
+                startEvent.events[0].startId(mStartId++);
+                mCallback_1_1->onFilterEvent_1_1(emptyEvent, startEvent);
+                mConfigured = false;
+            }
             mCallback_1_1->onFilterEvent_1_1(mFilterEvent, mFilterEventExt);
             mFilterEventExt.events.resize(0);
         } else if (mCallback != nullptr) {
diff --git a/tv/tuner/1.1/default/Filter.h b/tv/tuner/1.1/default/Filter.h
index a7b3fd2..1ebc135 100644
--- a/tv/tuner/1.1/default/Filter.h
+++ b/tv/tuner/1.1/default/Filter.h
@@ -235,6 +235,9 @@
 
     // Scrambling status to be monitored
     uint32_t mStatuses = 0;
+
+    bool mConfigured = false;
+    int mStartId = 0;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.1/types.hal b/tv/tuner/1.1/types.hal
index 006e597..09b87f2 100644
--- a/tv/tuner/1.1/types.hal
+++ b/tv/tuner/1.1/types.hal
@@ -161,6 +161,14 @@
         DemuxFilterMmtpRecordEventExt mmtpRecord;
 
         ScramblingStatus scramblingStatus;
+
+        /**
+         * An unique ID to mark the start point of receiving the valid filter events after
+         * reconfiguring the filter. It must be sent at least once in the first event after the
+         * filter is restarted. 0 is reserved for the newly opened filter's first start, which is
+         * optional for HAL to send.
+         */
+        uint32_t startId;
     };
 
     /**
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.cpp b/tv/tuner/1.1/vts/functional/FilterTests.cpp
index d2535e5..cdf3b69 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.cpp
+++ b/tv/tuner/1.1/vts/functional/FilterTests.cpp
@@ -40,6 +40,18 @@
     ALOGW("[vts] pass and stop");
 }
 
+void FilterCallback::testStartIdAfterReconfigure() {
+    android::Mutex::Autolock autoLock(mMsgLock);
+    while (!mStartIdReceived) {
+        if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
+            EXPECT_TRUE(false) << "does not receive start id within timeout";
+            return;
+        }
+    }
+    mStartIdReceived = false;
+    ALOGW("[vts] pass and stop");
+}
+
 void FilterCallback::readFilterEventData() {
     ALOGW("[vts] reading filter event");
     // todo separate filter handlers
@@ -71,6 +83,10 @@
             case DemuxFilterEventExt::Event::hidl_discriminator::scramblingStatus:
                 mScramblingStatusEvent++;
                 break;
+            case DemuxFilterEventExt::Event::hidl_discriminator::startId:
+                ALOGD("[vts] Extended restart filter event, startId=%d", eventExt.startId());
+                mStartIdReceived = true;
+                break;
             default:
                 break;
         }
@@ -90,8 +106,8 @@
     }
 
     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));
+    uint8_t* buffer = static_cast<uint8_t*>(
+            mmap(NULL, length + offset, PROT_READ | PROT_WRITE, MAP_SHARED, av_fd, 0));
     if (buffer == MAP_FAILED) {
         ALOGE("[vts] fail to allocate av buffer, errno=%d", errno);
         return false;
@@ -271,3 +287,9 @@
     }
     return AssertionResult(status == Result::SUCCESS);
 }
+
+AssertionResult FilterTests::startIdTest(uint64_t filterId) {
+    EXPECT_TRUE(mFilterCallbacks[filterId]) << "Test with getNewlyOpenedFilterId first.";
+    mFilterCallbacks[filterId]->testStartIdAfterReconfigure();
+    return AssertionResult(true);
+}
diff --git a/tv/tuner/1.1/vts/functional/FilterTests.h b/tv/tuner/1.1/vts/functional/FilterTests.h
index d88f171..ae57659 100644
--- a/tv/tuner/1.1/vts/functional/FilterTests.h
+++ b/tv/tuner/1.1/vts/functional/FilterTests.h
@@ -118,6 +118,7 @@
 
     void testFilterDataOutput();
     void testFilterScramblingEvent();
+    void testStartIdAfterReconfigure();
 
     void readFilterEventData();
     bool dumpAvData(DemuxFilterMediaEvent event);
@@ -138,6 +139,7 @@
 
     int mPidFilterOutputCount = 0;
     int mScramblingStatusEvent = 0;
+    bool mStartIdReceived = false;
 };
 
 class FilterTests {
@@ -160,6 +162,7 @@
     AssertionResult startFilter(uint64_t filterId);
     AssertionResult stopFilter(uint64_t filterId);
     AssertionResult closeFilter(uint64_t filterId);
+    AssertionResult startIdTest(uint64_t filterId);
 
     FilterEventType getFilterEventType(DemuxFilterType type) {
         FilterEventType eventType = FilterEventType::UNDEFINED;
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
index 17abf49..dda8b60 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.cpp
@@ -57,6 +57,39 @@
     ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
 
+void TunerFilterHidlTest::reconfigSingleFilterInDemuxTest(FilterConfig filterConf,
+                                                          FilterConfig filterReconf,
+                                                          FrontendConfig frontendConf) {
+    uint32_t feId;
+    uint32_t demuxId;
+    sp<IDemux> demux;
+    uint64_t filterId;
+
+    mFrontendTests.getFrontendIdByType(frontendConf.type, feId);
+    ASSERT_TRUE(feId != INVALID_ID);
+    ASSERT_TRUE(mFrontendTests.openFrontendById(feId));
+    ASSERT_TRUE(mFrontendTests.setFrontendCallback());
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
+    mFrontendTests.setDemux(demux);
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
+    ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId_64bit(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mFilterTests.configFilter(filterReconf.settings, filterId));
+    ASSERT_TRUE(mFilterTests.startFilter(filterId));
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
+    ASSERT_TRUE(mFilterTests.startIdTest(filterId));
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
+    ASSERT_TRUE(mFilterTests.stopFilter(filterId));
+    ASSERT_TRUE(mFilterTests.closeFilter(filterId));
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+    ASSERT_TRUE(mFrontendTests.closeFrontend());
+}
+
 void TunerBroadcastHidlTest::mediaFilterUsingSharedMemoryTest(FilterConfig filterConf,
                                                               FrontendConfig frontendConf) {
     uint32_t feId;
@@ -146,6 +179,13 @@
     configSingleFilterInDemuxTest(filterArray[IP_IP0], frontendArray[DVBT]);
 }
 
+TEST_P(TunerFilterHidlTest, ReonfigFilterToReceiveStartId) {
+    description("Recofigure and restart a filter to test start id.");
+    // TODO use parameterized tests
+    reconfigSingleFilterInDemuxTest(filterArray[TS_VIDEO0], filterArray[TS_VIDEO1],
+                                    frontendArray[DVBT]);
+}
+
 TEST_P(TunerRecordHidlTest, RecordDataFlowWithTsRecordFilterTest) {
     description("Feed ts data from frontend to recording and test with ts record filter");
     recordSingleFilterTest(filterArray[TS_RECORD0], frontendArray[DVBT], dvrArray[DVR_RECORD0]);
diff --git a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
index 773224e..d14a2e8 100644
--- a/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
+++ b/tv/tuner/1.1/vts/functional/VtsHalTvTunerV1_1TargetTest.h
@@ -58,7 +58,8 @@
     }
 
     void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf);
-
+    void reconfigSingleFilterInDemuxTest(FilterConfig filterConf, FilterConfig filterReconf,
+                                         FrontendConfig frontendConf);
     sp<ITuner> mService;
     FrontendTests mFrontendTests;
     DemuxTests mDemuxTests;