Merge "Log NNAPI VTS test case to logcat" into rvc-dev
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
index f712ea2..2c2f23c 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/EmulatedUserHal.cpp
@@ -158,6 +158,20 @@
         return sendUserHalResponse(std::move(mSwitchUserResponseFromCmd), requestId);
     }
 
+    if (value.value.int32Values.size() > 1) {
+        auto messageType = static_cast<SwitchUserMessageType>(value.value.int32Values[1]);
+        switch (messageType) {
+            case SwitchUserMessageType::LEGACY_ANDROID_SWITCH:
+                ALOGI("request is LEGACY_ANDROID_SWITCH; ignoring it");
+                return {};
+            case SwitchUserMessageType::ANDROID_POST_SWITCH:
+                ALOGI("request is ANDROID_POST_SWITCH; ignoring it");
+                return {};
+            default:
+                break;
+        }
+    }
+
     // Returns default response
     auto updatedValue = std::unique_ptr<VehiclePropValue>(new VehiclePropValue);
     updatedValue->prop = SWITCH_USER;
diff --git a/automotive/vehicle/2.0/types.hal b/automotive/vehicle/2.0/types.hal
index 341aae7..acdea8a 100644
--- a/automotive/vehicle/2.0/types.hal
+++ b/automotive/vehicle/2.0/types.hal
@@ -2546,9 +2546,8 @@
      * NOTE: if the HAL doesn't support user management, then it should not define this property,
      * which in turn would disable the other user-related properties (for example, the Android
      * system would never issue them and user-related requests from the HAL layer would be ignored
-     * by the Android System). But if it supports user management, then it must support all
-     * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, REMOVE_USER,
-     *       and USER_IDENTIFICATION_ASSOCIATION).
+     * by the Android System). But if it supports user management, then it must support all core
+     * user-related properties (INITIAL_USER_INFO, SWITCH_USER, CREATE_USER, and REMOVE_USER).
      *
      * @change_mode VehiclePropertyChangeMode:ON_CHANGE
      * @access VehiclePropertyAccess:READ_WRITE
@@ -2818,6 +2817,10 @@
      * Property used to associate (or query the association) the current user with vehicle-specific
      * identification mechanisms (such as key FOB).
      *
+     * This is an optional user management property - the OEM could still support user management
+     * without defining it. In fact, this property could be used without supporting the core
+     * user-related functions described on INITIAL_USER_INFO.
+     *
      * To query the association, the Android system gets the property, passing a VehiclePropValue
      * containing the types of associations are being queried, as defined by
      * UserIdentificationGetRequest. The HAL must return right away, returning a VehiclePropValue
diff --git a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
index 7ac44a4..78f93af 100644
--- a/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
+++ b/biometrics/face/1.0/vts/functional/VtsHalBiometricsFaceV1_0TargetTest.cpp
@@ -28,6 +28,7 @@
 #include <chrono>
 #include <cstdint>
 #include <random>
+#include <thread>
 
 using android::sp;
 using android::hardware::hidl_vec;
@@ -144,7 +145,10 @@
         ASSERT_EQ(Status::OK, static_cast<Status>(ret2));
     }
 
-    void TearDown() override {}
+    void TearDown() override {
+        // Hack to allow the asynchronous operations to finish on time.
+        std::this_thread::sleep_for(std::chrono::milliseconds(250));
+    }
 
     sp<IBiometricsFace> mService;
     sp<FaceCallback> mCallback;
diff --git a/camera/device/3.2/ICameraDeviceCallback.hal b/camera/device/3.2/ICameraDeviceCallback.hal
index dec3bd8..607502e 100644
--- a/camera/device/3.2/ICameraDeviceCallback.hal
+++ b/camera/device/3.2/ICameraDeviceCallback.hal
@@ -95,7 +95,8 @@
      * statuses must be STATUS_ERROR, and the result metadata must be an
      * empty buffer. In addition, notify() must be called with a ERROR_REQUEST
      * message. In this case, individual ERROR_RESULT/ERROR_BUFFER messages
-     * must not be sent.
+     * must not be sent. Note that valid partial results are still allowed
+     * as long as the final result metadata fails to be generated.
      *
      * Performance requirements:
      *
diff --git a/camera/provider/2.4/vts/functional/AndroidTest.xml b/camera/provider/2.4/vts/functional/AndroidTest.xml
new file mode 100644
index 0000000..05e1639
--- /dev/null
+++ b/camera/provider/2.4/vts/functional/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Runs VtsHalCameraProviderV2_4TargetTest.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+    </target_preparer>
+
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="VtsHalCameraProviderV2_4TargetTest->/data/local/tmp/VtsHalCameraProviderV2_4TargetTest" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="VtsHalCameraProviderV2_4TargetTest" />
+        <option name="native-test-timeout" value="180000"/>
+    </test>
+</configuration>
diff --git a/camera/provider/2.6/ICameraProvider.hal b/camera/provider/2.6/ICameraProvider.hal
index ed1d31d..b8873a6 100644
--- a/camera/provider/2.6/ICameraProvider.hal
+++ b/camera/provider/2.6/ICameraProvider.hal
@@ -76,12 +76,16 @@
      * configuration settings exposed through camera metadata), should the sum
      * of resource costs for the combination be <= 100.
      *
-     * The lists of camera id combinations returned by this method may contain
-     * hidden physical camera ids. If a combination does contain hidden physical
-     * camera ids, the camera framework must be able to open any logical cameras
-     * that contain these hidden physical camera ids in their
-     * ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS list, in addition to the other
-     * camera ids advertised in the combination, for concurrent operation.
+     * For guaranteed concurrent camera operation, the camera framework must call
+     * ICameraDevice.open() on all devices (intended for concurrent operation), before configuring
+     * any streams on them. This gives the camera HAL process an opportunity to potentially
+     * distribute hardware resources better before stream configuration.
+     *
+     * Due to potential hardware constraints around internal switching of physical camera devices,
+     * a device's complete ZOOM_RATIO_RANGE(if supported), may not apply during concurrent
+     * operation. If ZOOM_RATIO is supported, camera HALs must ensure ZOOM_RATIO_RANGE of
+     * [1.0, ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM] is supported by that device, during
+     * concurrent operation.
      *
      * @return status Status code for the operation
      * @return cameraIds a list of camera id combinations that support
diff --git a/current.txt b/current.txt
index e2d1408..2608b54 100644
--- a/current.txt
+++ b/current.txt
@@ -588,6 +588,7 @@
 578f640c653726d58f99c84a7e1bb63862e21ef7cbb4f7d95c3cc62de00dca35 android.hardware.automotive.evs@1.0::IEvsDisplay
 f5bc6aa840db933cb9fd36668b06d3e2021cf5384bb70e459f22e2f2f921fba5 android.hardware.automotive.evs@1.0::IEvsEnumerator
 d3a344b7bd4c0d2658ae7209f55a979b8f53f361fd00f4fca29d5baa56d11fd2 android.hardware.automotive.evs@1.0::types
+d123013165a19b6353cdc46a57b2ff4a17179619d36dbd595dfcf15dcd099af6 android.hardware.camera.device@3.2::ICameraDeviceCallback # b/155353799
 2410dd02d67786a732d36e80b0f8ccf55086604ef37f9838e2013ff2c571e404 android.hardware.camera.device@3.5::types
 cd06a7911b9acd4a653bbf7133888878fbcb3f84be177c7a3f1becaae3d8618f android.hardware.camera.metadata@3.2::types
 5cf81b1001296fbb3c5b3d275a859244f61cec5fa858d7be9cca46c5b7dfa733 android.hardware.camera.metadata@3.2::types # b/150331548
@@ -676,7 +677,7 @@
 a718c8a3acaa938de5a57923e8c4625ed7ca051e05a1d930ba6998557d7b57c8 android.hardware.camera.device@3.6::ICameraOfflineSession
 a35d5151b48505f06a775b38c0e2e265f80a845d92802324c643565807f81c53 android.hardware.camera.device@3.6::types
 02bdf82dba7dce273a554b4474468a8fb1fb4f61ab65da95eb16e080df63fff6 android.hardware.camera.metadata@3.5::types
-21086e1c7a2acc0ebe0ff8561b11f3c2009be687a92d79b608a5f00b16c5f598 android.hardware.camera.provider@2.6::ICameraProvider
+7d6b362681f4a4fd0be95535d8913d8de9a26f0765c1bdda4bd837dea8c25db6 android.hardware.camera.provider@2.6::ICameraProvider
 8f8d9463508ff9cae88eb35c429fd0e2dbca0ca8f5de7fdf836cc0c4370becb6 android.hardware.camera.provider@2.6::ICameraProviderCallback
 1edf7aef68ef3bd577a1175b1462fb82e3e39f01c6915dda61fba121028df283 android.hardware.camera.provider@2.6::types
 c1aa508d00b66ed5feefea398fd5edf28fa651ac89773adad7dfda4e0a73a952 android.hardware.cas@1.2::ICas
diff --git a/gnss/1.1/vts/functional/Android.bp b/gnss/1.1/vts/functional/Android.bp
index 0d540b7..94bfb89 100644
--- a/gnss/1.1/vts/functional/Android.bp
+++ b/gnss/1.1/vts/functional/Android.bp
@@ -25,6 +25,7 @@
     static_libs: [
         "android.hardware.gnss@1.0",
         "android.hardware.gnss@1.1",
+        "android.hardware.gnss@2.0",
         "android.hardware.gnss@common-vts-lib",
     ],
     shared_libs: [
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.cpp b/gnss/2.0/vts/functional/gnss_hal_test.cpp
index 59e18f3..1cb44c5 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test.cpp
@@ -247,3 +247,46 @@
     capabilities_cbq_.store(capabilities);
     return Void();
 }
+
+GnssConstellationType_1_0 GnssHalTest::startLocationAndGetNonGpsConstellation() {
+    const int kLocationsToAwait = 3;
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+    const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
+          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+
+    // Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0
+    // as blacklisting of this constellation is not supported in gnss@2.0.
+    const int kGnssSvStatusTimeout = 2;
+    GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN;
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+        for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+            if ((sv_info.v1_0.svFlag & IGnssCallback_2_0::GnssSvFlags::USED_IN_FIX) &&
+                (sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) &&
+                (sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
+                (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
+                // found a non-GPS V1_0 constellation
+                constellation_to_blacklist = Utils::mapConstellationType(sv_info.constellation);
+                break;
+            }
+        }
+        if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) {
+            break;
+        }
+    }
+
+    if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) {
+        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
+        // Proceed functionally to blacklist something.
+        constellation_to_blacklist = GnssConstellationType_1_0::GLONASS;
+    }
+    return constellation_to_blacklist;
+}
diff --git a/gnss/2.0/vts/functional/gnss_hal_test.h b/gnss/2.0/vts/functional/gnss_hal_test.h
index a02a9ff..7fbd735 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test.h
+++ b/gnss/2.0/vts/functional/gnss_hal_test.h
@@ -31,6 +31,9 @@
 using android::hardware::gnss::V1_0::GnssLocationFlags;
 using android::hardware::gnss::V2_0::IGnss;
 
+using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
+using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
+
 using GnssLocation_1_0 = android::hardware::gnss::V1_0::GnssLocation;
 using GnssLocation_2_0 = android::hardware::gnss::V2_0::GnssLocation;
 
@@ -194,6 +197,16 @@
      */
     void SetPositionMode(const int min_interval_msec, const bool low_power_mode);
 
+    /*
+     * startLocationAndGetNonGpsConstellation:
+     * 1. Start location
+     * 2. Find and return first non-GPS constellation
+     *
+     * Note that location is not stopped in this method. The client should call
+     * StopAndClearLocations() after the call.
+     */
+    GnssConstellationType_1_0 startLocationAndGetNonGpsConstellation();
+
     sp<IGnss> gnss_hal_;         // GNSS HAL to call into
     sp<GnssCallback> gnss_cb_;   // Primary callback interface
 };
diff --git a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
index 094c7c1..51dcf0d 100644
--- a/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.0/vts/functional/gnss_hal_test_cases.cpp
@@ -24,8 +24,6 @@
 using android::hardware::hidl_string;
 using android::hardware::hidl_vec;
 
-using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
-using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
 using IGnssConfiguration_2_0 = android::hardware::gnss::V2_0::IGnssConfiguration;
 using IGnssConfiguration_1_1 = android::hardware::gnss::V1_1::IGnssConfiguration;
 using IAGnssRil_2_0 = android::hardware::gnss::V2_0::IAGnssRil;
@@ -492,31 +490,6 @@
 }
 
 /*
- * MapConstellationType:
- * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
- * GnssConstellationType_1_0 type constellation. For constellations that do not have
- * an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN
- */
-GnssConstellationType_1_0 MapConstellationType(GnssConstellationType_2_0 constellation) {
-    switch (constellation) {
-        case GnssConstellationType_2_0::GPS:
-            return GnssConstellationType_1_0::GPS;
-        case GnssConstellationType_2_0::SBAS:
-            return GnssConstellationType_1_0::SBAS;
-        case GnssConstellationType_2_0::GLONASS:
-            return GnssConstellationType_1_0::GLONASS;
-        case GnssConstellationType_2_0::QZSS:
-            return GnssConstellationType_1_0::QZSS;
-        case GnssConstellationType_2_0::BEIDOU:
-            return GnssConstellationType_1_0::BEIDOU;
-        case GnssConstellationType_2_0::GALILEO:
-            return GnssConstellationType_1_0::GALILEO;
-        default:
-            return GnssConstellationType_1_0::UNKNOWN;
-    }
-}
-
-/*
  * FindStrongFrequentNonGpsSource:
  *
  * Search through a GnssSvStatus list for the strongest non-GPS satellite observed enough times
@@ -555,7 +528,7 @@
                 (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
                 ComparableBlacklistedSource source;
                 source.id.svid = sv_info.v1_0.svid;
-                source.id.constellation = MapConstellationType(sv_info.constellation);
+                source.id.constellation = Utils::mapConstellationType(sv_info.constellation);
 
                 const auto& itSignal = mapSignals.find(source);
                 if (itSignal == mapSignals.end()) {
@@ -694,7 +667,7 @@
         hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
         gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
         for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
-            auto constellation = MapConstellationType(sv_info.constellation);
+            auto constellation = Utils::mapConstellationType(sv_info.constellation);
             EXPECT_FALSE((sv_info.v1_0.svid == source_to_blacklist.svid) &&
                          (constellation == source_to_blacklist.constellation) &&
                          (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
@@ -736,7 +709,7 @@
             hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
             gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
             for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
-                auto constellation = MapConstellationType(sv_info.constellation);
+                auto constellation = Utils::mapConstellationType(sv_info.constellation);
                 if ((sv_info.v1_0.svid == source_to_blacklist.svid) &&
                     (constellation == source_to_blacklist.constellation) &&
                     (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX)) {
@@ -752,7 +725,7 @@
 }
 
 /*
- * BlacklistConstellation:
+ * BlacklistConstellationWithLocationOff:
  *
  * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
  * GnssStatus for any non-GPS constellations.
@@ -761,12 +734,11 @@
  * GnssStatus does not use any constellation but GPS.
  * 4a & b) Clean up by turning off location, and send in empty blacklist.
  */
-TEST_P(GnssHalTest, BlacklistConstellation) {
+TEST_P(GnssHalTest, BlacklistConstellationWithLocationOff) {
     if (!IsGnssHalVersion_2_0()) {
         ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0.");
         return;
     }
-
     if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
         ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
         return;
@@ -774,43 +746,12 @@
 
     const int kLocationsToAwait = 3;
 
-    gnss_cb_->location_cbq_.reset();
-    StartAndCheckLocations(kLocationsToAwait);
-    const int location_called_count = gnss_cb_->location_cbq_.calledCount();
+    // Find first non-GPS constellation to blacklist
+    GnssConstellationType_1_0 constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
 
-    // Tolerate 1 less sv status to handle edge cases in reporting.
-    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
-    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
-    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations (%d received)",
-          sv_info_list_cbq_size, kLocationsToAwait, location_called_count);
+    // Turns off location
+    StopAndClearLocations();
 
-    // Find first non-GPS constellation to blacklist. Exclude IRNSS in GnssConstellationType_2_0
-    // as blacklisting of this constellation is not supported in gnss@2.0.
-    const int kGnssSvStatusTimeout = 2;
-    GnssConstellationType_1_0 constellation_to_blacklist = GnssConstellationType_1_0::UNKNOWN;
-    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
-        hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
-        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
-        for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
-            if ((sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX) &&
-                (sv_info.constellation != GnssConstellationType_2_0::UNKNOWN) &&
-                (sv_info.constellation != GnssConstellationType_2_0::IRNSS) &&
-                (sv_info.constellation != GnssConstellationType_2_0::GPS)) {
-                // found a non-GPS V1_0 constellation
-                constellation_to_blacklist = MapConstellationType(sv_info.constellation);
-                break;
-            }
-        }
-        if (constellation_to_blacklist != GnssConstellationType_1_0::UNKNOWN) {
-            break;
-        }
-    }
-
-    if (constellation_to_blacklist == GnssConstellationType_1_0::UNKNOWN) {
-        ALOGI("No non-GPS constellations found, constellation blacklist test less effective.");
-        // Proceed functionally to blacklist something.
-        constellation_to_blacklist = GnssConstellationType_1_0::GLONASS;
-    }
     IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist;
     source_to_blacklist.constellation = constellation_to_blacklist;
     source_to_blacklist.svid = 0;  // documented wildcard for all satellites in this constellation
@@ -824,6 +765,7 @@
     sources.resize(1);
     sources[0] = source_to_blacklist;
 
+    // setBlacklist when location is off.
     auto result = gnss_configuration_hal->setBlacklist(sources);
     ASSERT_TRUE(result.isOk());
     EXPECT_TRUE(result);
@@ -835,15 +777,93 @@
     StartAndCheckLocations(kLocationsToAwait);
 
     // Tolerate 1 less sv status to handle edge cases in reporting.
-    sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
     EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
     ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size,
           kLocationsToAwait);
+    const int kGnssSvStatusTimeout = 2;
     for (int i = 0; i < sv_info_list_cbq_size; ++i) {
         hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
         gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
         for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
-            auto constellation = MapConstellationType(sv_info.constellation);
+            auto constellation = Utils::mapConstellationType(sv_info.constellation);
+            EXPECT_FALSE((constellation == source_to_blacklist.constellation) &&
+                         (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
+        }
+    }
+
+    // clean up
+    StopAndClearLocations();
+    sources.resize(0);
+    result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+}
+
+/*
+ * BlacklistConstellationWithLocationOn:
+ *
+ * 1) Turns on location, waits for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus for any non-GPS constellations.
+ * 2a & b) Blacklist first non-GPS constellations, and turns off location.
+ * 3) Restart location, wait for 3 locations, ensuring they are valid, and checks corresponding
+ * GnssStatus does not use any constellation but GPS.
+ * 4a & b) Clean up by turning off location, and send in empty blacklist.
+ */
+TEST_P(GnssHalTest, BlacklistConstellationWithLocationOn) {
+    if (!IsGnssHalVersion_2_0()) {
+        ALOGI("Test BlacklistConstellation skipped. GNSS HAL version is greater than 2.0.");
+        return;
+    }
+
+    if (!(gnss_cb_->last_capabilities_ & IGnssCallback::Capabilities::SATELLITE_BLACKLIST)) {
+        ALOGI("Test BlacklistConstellation skipped. SATELLITE_BLACKLIST capability not supported.");
+        return;
+    }
+
+    const int kLocationsToAwait = 3;
+
+    // Find first non-GPS constellation to blacklist
+    GnssConstellationType_1_0 constellation_to_blacklist = startLocationAndGetNonGpsConstellation();
+
+    IGnssConfiguration_1_1::BlacklistedSource source_to_blacklist;
+    source_to_blacklist.constellation = constellation_to_blacklist;
+    source_to_blacklist.svid = 0;  // documented wildcard for all satellites in this constellation
+
+    auto gnss_configuration_hal_return = gnss_hal_->getExtensionGnssConfiguration_1_1();
+    ASSERT_TRUE(gnss_configuration_hal_return.isOk());
+    sp<IGnssConfiguration_1_1> gnss_configuration_hal = gnss_configuration_hal_return;
+    ASSERT_NE(gnss_configuration_hal, nullptr);
+
+    hidl_vec<IGnssConfiguration_1_1::BlacklistedSource> sources;
+    sources.resize(1);
+    sources[0] = source_to_blacklist;
+
+    // setBlacklist when location is on.
+    auto result = gnss_configuration_hal->setBlacklist(sources);
+    ASSERT_TRUE(result.isOk());
+    EXPECT_TRUE(result);
+
+    // Turns off location
+    StopAndClearLocations();
+
+    // retry and ensure constellation not used
+    gnss_cb_->sv_info_list_cbq_.reset();
+
+    gnss_cb_->location_cbq_.reset();
+    StartAndCheckLocations(kLocationsToAwait);
+
+    // Tolerate 1 less sv status to handle edge cases in reporting.
+    int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
+    EXPECT_GE(sv_info_list_cbq_size + 1, kLocationsToAwait);
+    ALOGD("Observed %d GnssSvStatus, while awaiting %d Locations", sv_info_list_cbq_size,
+          kLocationsToAwait);
+    const int kGnssSvStatusTimeout = 2;
+    for (int i = 0; i < sv_info_list_cbq_size; ++i) {
+        hidl_vec<IGnssCallback_2_0::GnssSvInfo> sv_info_list;
+        gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_list, kGnssSvStatusTimeout);
+        for (IGnssCallback_2_0::GnssSvInfo sv_info : sv_info_list) {
+            auto constellation = Utils::mapConstellationType(sv_info.constellation);
             EXPECT_FALSE((constellation == source_to_blacklist.constellation) &&
                          (sv_info.v1_0.svFlag & IGnssCallback::GnssSvFlags::USED_IN_FIX));
         }
diff --git a/gnss/common/utils/vts/Android.bp b/gnss/common/utils/vts/Android.bp
index fd9613b..4c6d443 100644
--- a/gnss/common/utils/vts/Android.bp
+++ b/gnss/common/utils/vts/Android.bp
@@ -29,6 +29,7 @@
     export_include_dirs: ["include"],
     shared_libs: [
         "android.hardware.gnss@1.0",
+        "android.hardware.gnss@2.0",
         "android.hardware.gnss.measurement_corrections@1.0",
         "android.hardware.gnss.measurement_corrections@1.1",
     ],
diff --git a/gnss/common/utils/vts/Utils.cpp b/gnss/common/utils/vts/Utils.cpp
index 4b5a50f..9bf68e6 100644
--- a/gnss/common/utils/vts/Utils.cpp
+++ b/gnss/common/utils/vts/Utils.cpp
@@ -169,6 +169,31 @@
     return mockCorrections_1_1;
 }
 
+/*
+ * MapConstellationType:
+ * Given a GnssConstellationType_2_0 type constellation, maps to its equivalent
+ * GnssConstellationType_1_0 type constellation. For constellations that do not have
+ * an equivalent value, maps to GnssConstellationType_1_0::UNKNOWN
+ */
+GnssConstellationType_1_0 Utils::mapConstellationType(GnssConstellationType_2_0 constellation) {
+    switch (constellation) {
+        case GnssConstellationType_2_0::GPS:
+            return GnssConstellationType_1_0::GPS;
+        case GnssConstellationType_2_0::SBAS:
+            return GnssConstellationType_1_0::SBAS;
+        case GnssConstellationType_2_0::GLONASS:
+            return GnssConstellationType_1_0::GLONASS;
+        case GnssConstellationType_2_0::QZSS:
+            return GnssConstellationType_1_0::QZSS;
+        case GnssConstellationType_2_0::BEIDOU:
+            return GnssConstellationType_1_0::BEIDOU;
+        case GnssConstellationType_2_0::GALILEO:
+            return GnssConstellationType_1_0::GALILEO;
+        default:
+            return GnssConstellationType_1_0::UNKNOWN;
+    }
+}
+
 }  // namespace common
 }  // namespace gnss
 }  // namespace hardware
diff --git a/gnss/common/utils/vts/include/Utils.h b/gnss/common/utils/vts/include/Utils.h
index c3cdd18..9c838b2 100644
--- a/gnss/common/utils/vts/include/Utils.h
+++ b/gnss/common/utils/vts/include/Utils.h
@@ -18,9 +18,12 @@
 #define android_hardware_gnss_common_vts_Utils_H_
 
 #include <android/hardware/gnss/1.0/IGnss.h>
+#include <android/hardware/gnss/2.0/IGnss.h>
 #include <android/hardware/gnss/measurement_corrections/1.0/IMeasurementCorrections.h>
 #include <android/hardware/gnss/measurement_corrections/1.1/IMeasurementCorrections.h>
 
+using GnssConstellationType_1_0 = android::hardware::gnss::V1_0::GnssConstellationType;
+using GnssConstellationType_2_0 = android::hardware::gnss::V2_0::GnssConstellationType;
 using GnssLocation = ::android::hardware::gnss::V1_0::GnssLocation;
 using namespace android::hardware::gnss::measurement_corrections::V1_0;
 
@@ -44,6 +47,8 @@
                               bool check_more_accuracies);
     static const MeasurementCorrections_1_0 getMockMeasurementCorrections();
     static const MeasurementCorrections_1_1 getMockMeasurementCorrections_1_1();
+
+    static GnssConstellationType_1_0 mapConstellationType(GnssConstellationType_2_0 constellation);
 };
 
 }  // namespace common
diff --git a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
index ccb0690..b329cb2 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/PlaneLayout.aidl
@@ -100,10 +100,11 @@
     long totalSizeInBytes;
 
     /**
-     * Horizontal and vertical subsampling. Must be a positive power of 2.
+     * Horizontal and vertical subsampling. Must be a positive power of 2. A value of 1
+     * indicates no subsampling.
      *
      * These fields indicate the number of horizontally or vertically adjacent pixels that use
-     * the same pixel data. A value of 1 indicates no subsampling.
+     * the same pixel data.
      */
     long horizontalSubsampling;
     long verticalSubsampling;
diff --git a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
index 529fb18..6df7f8d 100644
--- a/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
+++ b/graphics/mapper/4.0/vts/functional/VtsHalGraphicsMapperV4_0TargetTest.cpp
@@ -605,6 +605,9 @@
     ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
 }
 
+/**
+ *  Test multiple operations associated with different color formats
+ */
 TEST_P(GraphicsMapperHidlTest, Lock_YCRCB_420_SP) {
     auto info = mDummyDescriptorInfo;
     info.format = PixelFormat::YCRCB_420_SP;
@@ -751,6 +754,90 @@
     ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
 }
 
+TEST_P(GraphicsMapperHidlTest, Lock_RAW10) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::RAW10;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(
+                                    info, true, Tolerance::kToleranceUnSupported, &stride));
+    if (bufferHandle == nullptr) {
+        GTEST_SUCCEED() << "RAW10 format is unsupported";
+        return;
+    }
+
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.get()));
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+    std::vector<PlaneLayout> planeLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+    ASSERT_EQ(1, planeLayouts.size());
+    auto planeLayout = planeLayouts[0];
+
+    EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+    EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+    EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+    ASSERT_EQ(1, planeLayout.components.size());
+    auto planeLayoutComponent = planeLayout.components[0];
+
+    EXPECT_EQ(PlaneLayoutComponentType::RAW,
+              static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+    EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+    EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
+TEST_P(GraphicsMapperHidlTest, Lock_RAW12) {
+    auto info = mDummyDescriptorInfo;
+    info.format = PixelFormat::RAW12;
+
+    const native_handle_t* bufferHandle;
+    uint32_t stride;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(
+                                    info, true, Tolerance::kToleranceUnSupported, &stride));
+    if (bufferHandle == nullptr) {
+        GTEST_SUCCEED() << "RAW12 format is unsupported";
+        return;
+    }
+
+    const IMapper::Rect region{0, 0, static_cast<int32_t>(info.width),
+                               static_cast<int32_t>(info.height)};
+    unique_fd fence;
+
+    ASSERT_NO_FATAL_FAILURE(mGralloc->lock(bufferHandle, info.usage, region, fence.get()));
+
+    hidl_vec<uint8_t> vec;
+    ASSERT_EQ(Error::NONE, mGralloc->get(bufferHandle, gralloc4::MetadataType_PlaneLayouts, &vec));
+    std::vector<PlaneLayout> planeLayouts;
+    ASSERT_EQ(NO_ERROR, gralloc4::decodePlaneLayouts(vec, &planeLayouts));
+
+    ASSERT_EQ(1, planeLayouts.size());
+    auto planeLayout = planeLayouts[0];
+
+    EXPECT_EQ(0, planeLayout.sampleIncrementInBits);
+    EXPECT_EQ(1, planeLayout.horizontalSubsampling);
+    EXPECT_EQ(1, planeLayout.verticalSubsampling);
+
+    ASSERT_EQ(1, planeLayout.components.size());
+    auto planeLayoutComponent = planeLayout.components[0];
+
+    EXPECT_EQ(PlaneLayoutComponentType::RAW,
+              static_cast<PlaneLayoutComponentType>(planeLayoutComponent.type.value));
+    EXPECT_EQ(0, planeLayoutComponent.offsetInBits % 8);
+    EXPECT_EQ(-1, planeLayoutComponent.sizeInBits);
+
+    ASSERT_NO_FATAL_FAILURE(fence.reset(mGralloc->unlock(bufferHandle)));
+}
+
 /**
  * Test IMapper::unlock with bad access region
  */
@@ -1707,6 +1794,84 @@
 }
 
 /**
+ * Test get::metadata with cloned native_handle
+ */
+TEST_P(GraphicsMapperHidlTest, GetMetadataClonedHandle) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    const auto dataspace = Dataspace::SRGB_LINEAR;
+    {
+        hidl_vec<uint8_t> metadata;
+        ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &metadata));
+
+        Error err = mGralloc->set(bufferHandle, gralloc4::MetadataType_Dataspace, metadata);
+        if (err == Error::UNSUPPORTED) {
+            GTEST_SUCCEED() << "setting this metadata is unsupported";
+            return;
+        }
+        ASSERT_EQ(Error::NONE, err);
+    }
+
+    const native_handle_t* importedHandle;
+    {
+        auto clonedHandle = native_handle_clone(bufferHandle);
+        ASSERT_NO_FATAL_FAILURE(importedHandle = mGralloc->importBuffer(clonedHandle));
+        native_handle_close(clonedHandle);
+        native_handle_delete(clonedHandle);
+    }
+
+    Dataspace realSpace = Dataspace::UNKNOWN;
+    {
+        hidl_vec<uint8_t> metadata;
+        ASSERT_EQ(Error::NONE,
+                  mGralloc->get(importedHandle, gralloc4::MetadataType_Dataspace, &metadata));
+        ASSERT_NO_FATAL_FAILURE(gralloc4::decodeDataspace(metadata, &realSpace));
+    }
+
+    EXPECT_EQ(dataspace, realSpace);
+}
+
+/**
+ * Test set::metadata with cloned native_handle
+ */
+TEST_P(GraphicsMapperHidlTest, SetMetadataClonedHandle) {
+    const native_handle_t* bufferHandle = nullptr;
+    ASSERT_NO_FATAL_FAILURE(bufferHandle = mGralloc->allocate(mDummyDescriptorInfo, true));
+
+    const native_handle_t* importedHandle;
+    {
+        auto clonedHandle = native_handle_clone(bufferHandle);
+        ASSERT_NO_FATAL_FAILURE(importedHandle = mGralloc->importBuffer(clonedHandle));
+        native_handle_close(clonedHandle);
+        native_handle_delete(clonedHandle);
+    }
+
+    const auto dataspace = Dataspace::SRGB_LINEAR;
+    {
+        hidl_vec<uint8_t> metadata;
+        ASSERT_EQ(NO_ERROR, gralloc4::encodeDataspace(dataspace, &metadata));
+
+        Error err = mGralloc->set(importedHandle, gralloc4::MetadataType_Dataspace, metadata);
+        if (err == Error::UNSUPPORTED) {
+            GTEST_SUCCEED() << "setting this metadata is unsupported";
+            return;
+        }
+        ASSERT_EQ(Error::NONE, err);
+    }
+
+    Dataspace realSpace = Dataspace::UNKNOWN;
+    {
+        hidl_vec<uint8_t> metadata;
+        ASSERT_EQ(Error::NONE,
+                  mGralloc->get(bufferHandle, gralloc4::MetadataType_Dataspace, &metadata));
+        ASSERT_NO_FATAL_FAILURE(gralloc4::decodeDataspace(metadata, &realSpace));
+    }
+
+    EXPECT_EQ(dataspace, realSpace);
+}
+
+/**
  * Test IMapper::set(metadata) for constant metadata
  */
 TEST_P(GraphicsMapperHidlTest, SetConstantMetadata) {
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 58473dc..cd6f9b0 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -17,13 +17,13 @@
         "android.hardware.keymaster@4.0",
         "libbinder",
         "libcrypto",
-        "libkeymaster_portable",
-        "libsoft_attestation_cert",
-        "libpuresoftkeymasterdevice",
         "android.hardware.keymaster-ndk_platform",
     ],
     static_libs: [
         "libcppbor",
+        "libkeymaster_portable",
+        "libsoft_attestation_cert",
+        "libpuresoftkeymasterdevice",
         "android.hardware.identity-support-lib",
         "android.hardware.identity-cpp",
         "android.hardware.keymaster-cpp",
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 6cbe4da..aa2de2a 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -438,10 +438,10 @@
             EXPECT_TRUE(device_locked);
         }
 
-        // Check that the expected result from VBMeta matches the build type. Only a user build
-        // should have AVB reporting the device is locked.
-        EXPECT_NE(property_get("ro.build.type", property_value, ""), 0);
-        if (!strcmp(property_value, "user")) {
+        // Check that the device is locked if not debuggable, e.g., user build
+        // images in CTS. For VTS, debuggable images are used to allow adb root
+        // and the device is unlocked.
+        if (!property_get_bool("ro.debuggable", false)) {
             EXPECT_TRUE(device_locked);
         } else {
             EXPECT_FALSE(device_locked);
diff --git a/neuralnetworks/1.0/vts/functional/AndroidTest.xml b/neuralnetworks/1.0/vts/functional/AndroidTest.xml
index 54e6e91..13671f9 100644
--- a/neuralnetworks/1.0/vts/functional/AndroidTest.xml
+++ b/neuralnetworks/1.0/vts/functional/AndroidTest.xml
@@ -26,10 +26,6 @@
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
-        <!-- b/155577050, temporarily disable the failing tests.
-             Must be deleted after corresponding driver issues are fixed.
-        -->
-        <option name="native-test-flag" value="--gtest_filter=-*Validation*:*CycleTest*:*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*" />
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="VtsHalNeuralnetworksV1_0TargetTest" />
     </test>
diff --git a/neuralnetworks/1.1/vts/functional/AndroidTest.xml b/neuralnetworks/1.1/vts/functional/AndroidTest.xml
index a6f812f..cfde60c 100644
--- a/neuralnetworks/1.1/vts/functional/AndroidTest.xml
+++ b/neuralnetworks/1.1/vts/functional/AndroidTest.xml
@@ -26,10 +26,6 @@
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
-        <!-- b/155577050, temporarily disable the failing tests.
-             Must be deleted after corresponding driver issues are fixed.
-        -->
-        <option name="native-test-flag" value="--gtest_filter=-*Validation*:*CycleTest*:*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*" />
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="VtsHalNeuralnetworksV1_1TargetTest" />
     </test>
diff --git a/neuralnetworks/1.2/vts/functional/AndroidTest.xml b/neuralnetworks/1.2/vts/functional/AndroidTest.xml
index adbdf40..3f91618 100644
--- a/neuralnetworks/1.2/vts/functional/AndroidTest.xml
+++ b/neuralnetworks/1.2/vts/functional/AndroidTest.xml
@@ -26,10 +26,6 @@
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
-        <!-- b/155577050, b/155674368, b/153876253, temporarily disable the test.
-             Must be deleted after corresponding driver issues are fixed.
-        -->
-        <option name="native-test-flag" value="--gtest_filter=-*Validation*:*squeeze*_all*_inputs*:*strided_slice*_all*_inputs*:*transpose*_all*_inputs*:*l2_normalization_axis_corner_case*:*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*" />
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="VtsHalNeuralnetworksV1_2TargetTest" />
     </test>
diff --git a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
index 449b8f3..16b313a 100644
--- a/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.2/vts/functional/CompilationCachingTests.cpp
@@ -315,7 +315,8 @@
 
     void saveModelToCache(const Model& model, const hidl_vec<hidl_handle>& modelCache,
                           const hidl_vec<hidl_handle>& dataCache,
-                          sp<IPreparedModel>* preparedModel = nullptr) {
+                          sp<IPreparedModel>* preparedModel = nullptr,
+                          bool allowGeneralFailure = false) {
         if (preparedModel != nullptr) *preparedModel = nullptr;
 
         // Launch prepare model.
@@ -329,7 +330,10 @@
 
         // Retrieve prepared model.
         preparedModelCallback->wait();
-        ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
+        const auto prepareCallbackStatus = preparedModelCallback->getStatus();
+        if (!allowGeneralFailure || prepareCallbackStatus != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(prepareCallbackStatus, ErrorStatus::NONE);
+        }
         if (preparedModel != nullptr) {
             *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
                                      .withDefault(nullptr);
@@ -1022,7 +1026,8 @@
 
 // Number of operations in the large test model.
 constexpr uint32_t kLargeModelSize = 100;
-constexpr uint32_t kNumIterationsTOCTOU = 100;
+constexpr uint32_t kNumSuccessfulIterationsTOCTOU = 100;
+constexpr uint32_t kMaxNumFailedIterationsTOCTOU = 100;
 
 TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) {
     if (!mIsCachingSupported) return;
@@ -1050,18 +1055,30 @@
     // Use a different token for modelAdd.
     mToken[0]++;
 
-    // This test is probabilistic, so we run it multiple times.
-    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+    // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+    // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+    // enough successful iterations to ensure the test coverage.
+    uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+    while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
         // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
 
+            sp<IPreparedModel> preparedModel = nullptr;
             // Spawn a thread to copy the cache content concurrently while saving to cache.
             std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
-            saveModelToCache(modelAdd, modelCache, dataCache);
+            saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+                             /*allowGeneralFailure=*/true);
             thread.join();
+
+            if (preparedModel == nullptr) {
+                numFailedIterations++;
+                ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+            } else {
+                numSuccessfulIterations++;
+            }
         }
 
         // Retrieve preparedModel from cache.
@@ -1112,14 +1129,26 @@
     // Use a different token for modelAdd.
     mToken[0]++;
 
-    // This test is probabilistic, so we run it multiple times.
-    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+    // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+    // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+    // enough successful iterations to ensure the test coverage.
+    uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+    while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
         // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-            saveModelToCache(modelAdd, modelCache, dataCache);
+            sp<IPreparedModel> preparedModel = nullptr;
+            saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+                             /*allowGeneralFailure=*/true);
+
+            if (preparedModel == nullptr) {
+                numFailedIterations++;
+                ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+            } else {
+                numSuccessfulIterations++;
+            }
         }
 
         // Retrieve preparedModel from cache.
diff --git a/neuralnetworks/1.3/vts/functional/AndroidTest.xml b/neuralnetworks/1.3/vts/functional/AndroidTest.xml
index 30cff2e..e5acd90 100644
--- a/neuralnetworks/1.3/vts/functional/AndroidTest.xml
+++ b/neuralnetworks/1.3/vts/functional/AndroidTest.xml
@@ -26,10 +26,6 @@
     </target_preparer>
 
     <test class="com.android.tradefed.testtype.GTest" >
-        <!-- b/156691406, b/155577050, b/155674368, b/153876253, temporarily disable the test.
-             Must be deleted after corresponding driver issues are fixed.
-        -->
-        <option name="native-test-flag" value="--gtest_filter=-*Validation*:*DynamicOutputShapeTest*:*FencedComputeTest*:*MemoryDomain*:*QuantizationCouplingTest*:*DeadlineTest*:*resize_*_v1_3*:*squeeze*_all*_inputs*:*strided_slice*_all*_inputs*:*transpose*_all*_inputs*:*l2_normalization_axis_corner_case*:*sample_float_fast*:*sample_float_slow*:*sample_minimal*:*sample_quant*" />
         <option name="native-test-device-path" value="/data/local/tmp" />
         <option name="module-name" value="VtsHalNeuralnetworksV1_3TargetTest" />
     </test>
diff --git a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
index ac18c8f..382fc76 100644
--- a/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
+++ b/neuralnetworks/1.3/vts/functional/CompilationCachingTests.cpp
@@ -318,7 +318,8 @@
 
     void saveModelToCache(const Model& model, const hidl_vec<hidl_handle>& modelCache,
                           const hidl_vec<hidl_handle>& dataCache,
-                          sp<IPreparedModel>* preparedModel = nullptr) {
+                          sp<IPreparedModel>* preparedModel = nullptr,
+                          bool allowGeneralFailure = false) {
         if (preparedModel != nullptr) *preparedModel = nullptr;
 
         // Launch prepare model.
@@ -332,7 +333,10 @@
 
         // Retrieve prepared model.
         preparedModelCallback->wait();
-        ASSERT_EQ(preparedModelCallback->getStatus(), ErrorStatus::NONE);
+        const auto prepareCallbackStatus = preparedModelCallback->getStatus();
+        if (!allowGeneralFailure || prepareCallbackStatus != ErrorStatus::GENERAL_FAILURE) {
+            ASSERT_EQ(prepareCallbackStatus, ErrorStatus::NONE);
+        }
         if (preparedModel != nullptr) {
             *preparedModel = IPreparedModel::castFrom(preparedModelCallback->getPreparedModel())
                                      .withDefault(nullptr);
@@ -1013,7 +1017,8 @@
 
 // Number of operations in the large test model.
 constexpr uint32_t kLargeModelSize = 100;
-constexpr uint32_t kNumIterationsTOCTOU = 100;
+constexpr uint32_t kNumSuccessfulIterationsTOCTOU = 100;
+constexpr uint32_t kMaxNumFailedIterationsTOCTOU = 100;
 
 TEST_P(CompilationCachingTest, SaveToCache_TOCTOU) {
     if (!mIsCachingSupported) return;
@@ -1041,18 +1046,30 @@
     // Use a different token for modelAdd.
     mToken[0]++;
 
-    // This test is probabilistic, so we run it multiple times.
-    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+    // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+    // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+    // enough successful iterations to ensure the test coverage.
+    uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+    while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
         // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
 
+            sp<IPreparedModel> preparedModel = nullptr;
             // Spawn a thread to copy the cache content concurrently while saving to cache.
             std::thread thread(copyCacheFiles, std::cref(modelCacheMul), std::cref(mModelCache));
-            saveModelToCache(modelAdd, modelCache, dataCache);
+            saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+                             /*allowGeneralFailure=*/true);
             thread.join();
+
+            if (preparedModel == nullptr) {
+                numFailedIterations++;
+                ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+            } else {
+                numSuccessfulIterations++;
+            }
         }
 
         // Retrieve preparedModel from cache.
@@ -1103,14 +1120,26 @@
     // Use a different token for modelAdd.
     mToken[0]++;
 
-    // This test is probabilistic, so we run it multiple times.
-    for (uint32_t i = 0; i < kNumIterationsTOCTOU; i++) {
+    // This test is probabilistic, so we run it multiple times. We allow the compilation to fail
+    // because it is not related to the security aspect of the TOCTOU test. However, we need to have
+    // enough successful iterations to ensure the test coverage.
+    uint32_t numSuccessfulIterations = 0, numFailedIterations = 0;
+    while (numSuccessfulIterations < kNumSuccessfulIterationsTOCTOU) {
         // Save the modelAdd compilation to cache.
         {
             hidl_vec<hidl_handle> modelCache, dataCache;
             createCacheHandles(mModelCache, AccessMode::READ_WRITE, &modelCache);
             createCacheHandles(mDataCache, AccessMode::READ_WRITE, &dataCache);
-            saveModelToCache(modelAdd, modelCache, dataCache);
+            sp<IPreparedModel> preparedModel = nullptr;
+            saveModelToCache(modelAdd, modelCache, dataCache, &preparedModel,
+                             /*allowGeneralFailure=*/true);
+
+            if (preparedModel == nullptr) {
+                numFailedIterations++;
+                ASSERT_LE(numFailedIterations, kMaxNumFailedIterationsTOCTOU);
+            } else {
+                numSuccessfulIterations++;
+            }
         }
 
         // Retrieve preparedModel from cache.
diff --git a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
index 02dcbab..08121fd 100644
--- a/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.1/vts/functional/radio_hidl_hal_api.cpp
@@ -49,7 +49,6 @@
         }
         EXPECT_EQ(CardState::ABSENT, cardStatus.cardState);
     }
-#endif
 
     /* Test setSimCardPower power up */
     serial = GetRandomSerialNumber();
@@ -60,6 +59,7 @@
     ASSERT_TRUE(CheckAnyOfErrors(radioRsp_v1_1->rspInfo.error,
                                  {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
                                   RadioError::INVALID_ARGUMENTS, RadioError::RADIO_NOT_AVAILABLE}));
+#endif
 
     /**
      * If the sim card status for the testing environment is PRESENT,
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 8cbb2d0..9b6d450 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -1017,8 +1017,10 @@
     return Void();
 }
 
-Return<void> RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& /*info*/,
+Return<void> RadioResponse_v1_5::sendCdmaSmsExpectMoreResponse(const RadioResponseInfo& info,
                                                                const SendSmsResult& /*sms*/) {
+    rspInfo = info;
+    parent_v1_5.notify(info.serial);
     return Void();
 }
 
diff --git a/tv/tuner/1.0/default/Demux.cpp b/tv/tuner/1.0/default/Demux.cpp
index b74f6ec..67eff1b 100644
--- a/tv/tuner/1.0/default/Demux.cpp
+++ b/tv/tuner/1.0/default/Demux.cpp
@@ -48,8 +48,6 @@
         return Result::INVALID_STATE;
     }
 
-    mFrontendSourceFile = mFrontend->getSourceFile();
-
     mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
 
     return Result::SUCCESS;
@@ -62,8 +60,6 @@
     uint32_t filterId;
     filterId = ++mLastUsedFilterId;
 
-    mUsedFilterIds.insert(filterId);
-
     if (cb == nullptr) {
         ALOGW("[Demux] callback can't be null");
         _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
@@ -82,8 +78,13 @@
         mPcrFilterIds.insert(filterId);
     }
     bool result = true;
-    if (mDvr != nullptr && mDvr->getType() == DvrType::PLAYBACK) {
-        result = mDvr->addPlaybackFilter(filter);
+    if (!filter->isRecordFilter()) {
+        // Only save non-record filters for now. Record filters are saved when the
+        // IDvr.attacheFilter is called.
+        mPlaybackFilterIds.insert(filterId);
+        if (mDvrPlayback != nullptr) {
+            result = mDvrPlayback->addPlaybackFilter(filterId, filter);
+        }
     }
 
     _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter);
@@ -93,9 +94,9 @@
 Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
 
-    sp<TimeFilter> timeFilter = new TimeFilter(this);
+    mTimeFilter = new TimeFilter(this);
 
-    _hidl_cb(Result::SUCCESS, timeFilter);
+    _hidl_cb(Result::SUCCESS, mTimeFilter);
     return Void();
 }
 
@@ -154,7 +155,13 @@
 Return<Result> Demux::close() {
     ALOGV("%s", __FUNCTION__);
 
-    mUsedFilterIds.clear();
+    set<uint32_t>::iterator it;
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+        mDvrPlayback->removePlaybackFilter(*it);
+    }
+    mPlaybackFilterIds.clear();
+    mRecordFilterIds.clear();
+    mFilters.clear();
     mLastUsedFilterId = -1;
 
     return Result::SUCCESS;
@@ -170,15 +177,38 @@
         return Void();
     }
 
-    mDvr = new Dvr(type, bufferSize, cb, this);
+    set<uint32_t>::iterator it;
+    switch (type) {
+        case DvrType::PLAYBACK:
+            mDvrPlayback = new Dvr(type, bufferSize, cb, this);
+            if (!mDvrPlayback->createDvrMQ()) {
+                _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
+                return Void();
+            }
 
-    if (!mDvr->createDvrMQ()) {
-        _hidl_cb(Result::UNKNOWN_ERROR, mDvr);
-        return Void();
+            for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
+                if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
+                    ALOGE("[Demux] Can't get filter info for DVR playback");
+                    _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
+                    return Void();
+                }
+            }
+
+            _hidl_cb(Result::SUCCESS, mDvrPlayback);
+            return Void();
+        case DvrType::RECORD:
+            mDvrRecord = new Dvr(type, bufferSize, cb, this);
+            if (!mDvrRecord->createDvrMQ()) {
+                _hidl_cb(Result::UNKNOWN_ERROR, mDvrRecord);
+                return Void();
+            }
+
+            _hidl_cb(Result::SUCCESS, mDvrRecord);
+            return Void();
+        default:
+            _hidl_cb(Result::INVALID_ARGUMENT, nullptr);
+            return Void();
     }
-
-    _hidl_cb(Result::SUCCESS, mDvr);
-    return Void();
 }
 
 Return<Result> Demux::connectCiCam(uint32_t ciCamId) {
@@ -198,8 +228,10 @@
 Result Demux::removeFilter(uint32_t filterId) {
     ALOGV("%s", __FUNCTION__);
 
-    // resetFilterRecords(filterId);
-    mUsedFilterIds.erase(filterId);
+    if (mDvrPlayback != nullptr) {
+        mDvrPlayback->removePlaybackFilter(filterId);
+    }
+    mPlaybackFilterIds.erase(filterId);
     mRecordFilterIds.erase(filterId);
     mFilters.erase(filterId);
 
@@ -212,7 +244,7 @@
     if (DEBUG_DEMUX) {
         ALOGW("[Demux] start ts filter pid: %d", pid);
     }
-    for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
         if (pid == mFilters[*it]->getTpid()) {
             mFilters[*it]->updateFilterOutput(data);
         }
@@ -233,7 +265,7 @@
     set<uint32_t>::iterator it;
 
     // Handle the output data per filter type
-    for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
+    for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
         if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
             return false;
         }
@@ -280,58 +312,27 @@
 void Demux::frontendInputThreadLoop() {
     std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
     mFrontendInputThreadRunning = true;
-    mKeepFetchingDataFromFrontend = true;
-
-    // open the stream and get its length
-    std::ifstream inputData(mFrontendSourceFile, std::ifstream::binary);
-    // TODO take the packet size from the frontend setting
-    int packetSize = 188;
-    int writePacketAmount = 6;
-    char* buffer = new char[packetSize];
-    ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str());
-    if (!inputData.is_open()) {
-        mFrontendInputThreadRunning = false;
-        ALOGW("[Demux] Error %s", strerror(errno));
-    }
 
     while (mFrontendInputThreadRunning) {
-        // move the stream pointer for packet size * 6 every read until the end
-        while (mKeepFetchingDataFromFrontend) {
-            for (int i = 0; i < writePacketAmount; i++) {
-                inputData.read(buffer, packetSize);
-                if (!inputData) {
-                    mKeepFetchingDataFromFrontend = false;
-                    mFrontendInputThreadRunning = false;
-                    break;
-                }
-                // filter and dispatch filter output
-                vector<uint8_t> byteBuffer;
-                byteBuffer.resize(packetSize);
-                for (int index = 0; index < byteBuffer.size(); index++) {
-                    byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
-                }
-                if (mIsRecording) {
-                    // Feed the data into the Dvr recording input
-                    sendFrontendInputToRecord(byteBuffer);
-                } else {
-                    // Feed the data into the broadcast demux filter
-                    startBroadcastTsFilter(byteBuffer);
-                }
-            }
-            if (mIsRecording) {
-                // Dispatch the data into the broadcasting filters.
-                startRecordFilterDispatcher();
-            } else {
-                // Dispatch the data into the broadcasting filters.
-                startBroadcastFilterDispatcher();
-            }
-            usleep(100);
+        uint32_t efState = 0;
+        status_t status = mDvrPlayback->getDvrEventFlag()->wait(
+                static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
+                true /* retry on spurious wake */);
+        if (status != OK) {
+            ALOGD("[Demux] wait for data ready on the playback FMQ");
+            continue;
+        }
+        // Our current implementation filter the data and write it into the filter FMQ immediately
+        // after the DATA_READY from the VTS/framework
+        if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
+            !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) {
+            ALOGE("[Demux] playback data failed to be filtered. Ending thread");
+            break;
         }
     }
 
+    mFrontendInputThreadRunning = false;
     ALOGW("[Demux] Frontend Input thread end.");
-    delete[] buffer;
-    inputData.close();
 }
 
 void Demux::stopFrontendInput() {
@@ -346,18 +347,19 @@
 }
 
 bool Demux::attachRecordFilter(int filterId) {
-    if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+    if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
+        !mFilters[filterId]->isRecordFilter()) {
         return false;
     }
 
     mRecordFilterIds.insert(filterId);
-    mFilters[filterId]->attachFilterToRecord(mDvr);
+    mFilters[filterId]->attachFilterToRecord(mDvrRecord);
 
     return true;
 }
 
 bool Demux::detachRecordFilter(int filterId) {
-    if (mFilters[filterId] == nullptr || mDvr == nullptr) {
+    if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) {
         return false;
     }
 
diff --git a/tv/tuner/1.0/default/Demux.h b/tv/tuner/1.0/default/Demux.h
index 6c46b0d..7f282b2 100644
--- a/tv/tuner/1.0/default/Demux.h
+++ b/tv/tuner/1.0/default/Demux.h
@@ -91,13 +91,23 @@
     void setIsRecording(bool isRecording);
     void startFrontendInputLoop();
 
+    /**
+     * A dispatcher to read and dispatch input data to all the started filters.
+     * Each filter handler handles the data filtering/output writing/filterEvent updating.
+     * Note that recording filters are not included.
+     */
+    bool startBroadcastFilterDispatcher();
+    void startBroadcastTsFilter(vector<uint8_t> data);
+
+    void sendFrontendInputToRecord(vector<uint8_t> data);
+    bool startRecordFilterDispatcher();
+
   private:
     // Tuner service
     sp<Tuner> mTunerService;
 
     // Frontend source
     sp<Frontend> mFrontend;
-    string mFrontendSourceFile;
 
     // A struct that passes the arguments to a newly created filter thread
     struct ThreadArgs {
@@ -117,16 +127,6 @@
      */
     void deleteEventFlag();
     bool readDataFromMQ();
-    /**
-     * A dispatcher to read and dispatch input data to all the started filters.
-     * Each filter handler handles the data filtering/output writing/filterEvent updating.
-     * Note that recording filters are not included.
-     */
-    bool startBroadcastFilterDispatcher();
-    void startBroadcastTsFilter(vector<uint8_t> data);
-
-    void sendFrontendInputToRecord(vector<uint8_t> data);
-    bool startRecordFilterDispatcher();
 
     uint32_t mDemuxId;
     uint32_t mCiCamId;
@@ -137,25 +137,31 @@
      */
     uint32_t mLastUsedFilterId = -1;
     /**
-     * Record all the used filter Ids.
+     * Record all the used playback filter Ids.
      * Any removed filter id should be removed from this set.
      */
-    set<uint32_t> mUsedFilterIds;
+    set<uint32_t> mPlaybackFilterIds;
     /**
      * Record all the attached record filter Ids.
      * Any removed filter id should be removed from this set.
      */
     set<uint32_t> mRecordFilterIds;
     /**
-     * A list of created FilterMQ ptrs.
+     * A list of created Filter sp.
      * The array number is the filter ID.
      */
     std::map<uint32_t, sp<Filter>> mFilters;
 
     /**
+     * Local reference to the opened Timer Filter instance.
+     */
+    sp<TimeFilter> mTimeFilter;
+
+    /**
      * Local reference to the opened DVR object.
      */
-    sp<Dvr> mDvr;
+    sp<Dvr> mDvrPlayback;
+    sp<Dvr> mDvrRecord;
 
     // Thread handlers
     pthread_t mFrontendInputThread;
diff --git a/tv/tuner/1.0/default/Dvr.cpp b/tv/tuner/1.0/default/Dvr.cpp
index adb2635..68e175c 100644
--- a/tv/tuner/1.0/default/Dvr.cpp
+++ b/tv/tuner/1.0/default/Dvr.cpp
@@ -70,8 +70,7 @@
         return status;
     }
 
-    // check if the attached filter is a record filter
-    mFilters[filterId] = filter;
+    // TODO check if the attached filter is a record filter
     if (!mDemux->attachRecordFilter(filterId)) {
         return Result::INVALID_ARGUMENT;
     }
@@ -94,19 +93,8 @@
         return status;
     }
 
-    std::map<uint32_t, sp<IFilter>>::iterator it;
-
-    it = mFilters.find(filterId);
-    if (it != mFilters.end()) {
-        mFilters.erase(filterId);
-        if (!mDemux->detachRecordFilter(filterId)) {
-            return Result::INVALID_ARGUMENT;
-        }
-    }
-
-    // If all the filters are detached, record can't be started
-    if (mFilters.empty()) {
-        mIsRecordFilterAttached = false;
+    if (!mDemux->detachRecordFilter(filterId)) {
+        return Result::INVALID_ARGUMENT;
     }
 
     return Result::SUCCESS;
@@ -183,6 +171,10 @@
     return true;
 }
 
+EventFlag* Dvr::getDvrEventFlag() {
+    return mDvrEventFlag;
+}
+
 void* Dvr::__threadLoopPlayback(void* user) {
     Dvr* const self = static_cast<Dvr*>(user);
     self->playbackThreadLoop();
@@ -205,8 +197,9 @@
         }
         // Our current implementation filter the data and write it into the filter FMQ immediately
         // after the DATA_READY from the VTS/framework
-        if (!readPlaybackFMQ() || !startFilterDispatcher()) {
-            ALOGD("[Dvr] playback data failed to be filtered. Ending thread");
+        if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
+            !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
+            ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
             break;
         }
 
@@ -245,7 +238,7 @@
     return mPlaybackStatus;
 }
 
-bool Dvr::readPlaybackFMQ() {
+bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
     // Read playback data from the input FMQ
     int size = mDvrMQ->availableToRead();
     int playbackPacketSize = mDvrSettings.playback().packetSize;
@@ -256,7 +249,15 @@
         if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
             return false;
         }
-        startTpidFilter(dataOutputBuffer);
+        if (isVirtualFrontend) {
+            if (isRecording) {
+                mDemux->sendFrontendInputToRecord(dataOutputBuffer);
+            } else {
+                mDemux->startBroadcastTsFilter(dataOutputBuffer);
+            }
+        } else {
+            startTpidFilter(dataOutputBuffer);
+        }
     }
 
     return true;
@@ -275,7 +276,15 @@
     }
 }
 
-bool Dvr::startFilterDispatcher() {
+bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
+    if (isVirtualFrontend) {
+        if (isRecording) {
+            return mDemux->startRecordFilterDispatcher();
+        } else {
+            return mDemux->startBroadcastFilterDispatcher();
+        }
+    }
+
     std::map<uint32_t, sp<IFilter>>::iterator it;
     // Handle the output data per filter type
     for (it = mFilters.begin(); it != mFilters.end(); it++) {
@@ -329,27 +338,15 @@
     return mRecordStatus;
 }
 
-bool Dvr::addPlaybackFilter(sp<IFilter> filter) {
-    uint32_t filterId;
-    Result status;
-
-    filter->getId([&](Result result, uint32_t id) {
-        filterId = id;
-        status = result;
-    });
-
-    if (status != Result::SUCCESS) {
-        return false;
-    }
-
+bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) {
     mFilters[filterId] = filter;
     return true;
 }
 
-DvrType Dvr::getType() {
-    return mType;
+bool Dvr::removePlaybackFilter(uint32_t filterId) {
+    mFilters.erase(filterId);
+    return true;
 }
-
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Dvr.h b/tv/tuner/1.0/default/Dvr.h
index 08afd5d..a63a256 100644
--- a/tv/tuner/1.0/default/Dvr.h
+++ b/tv/tuner/1.0/default/Dvr.h
@@ -81,8 +81,11 @@
     bool createDvrMQ();
     void sendBroadcastInputToDvrRecord(vector<uint8_t> byteBuffer);
     bool writeRecordFMQ(const std::vector<uint8_t>& data);
-    DvrType getType();
-    bool addPlaybackFilter(sp<IFilter> filter);
+    bool addPlaybackFilter(uint32_t filterId, sp<IFilter> filter);
+    bool removePlaybackFilter(uint32_t filterId);
+    bool readPlaybackFMQ(bool isVirtualFrontend, bool isRecording);
+    bool startFilterDispatcher(bool isVirtualFrontend, bool isRecording);
+    EventFlag* getDvrEventFlag();
 
   private:
     // Demux service
@@ -105,9 +108,7 @@
      * A dispatcher to read and dispatch input data to all the started filters.
      * Each filter handler handles the data filtering/output writing/filterEvent updating.
      */
-    bool readPlaybackFMQ();
     void startTpidFilter(vector<uint8_t> data);
-    bool startFilterDispatcher();
     static void* __threadLoopPlayback(void* user);
     static void* __threadLoopRecord(void* user);
     void playbackThreadLoop();
@@ -123,7 +124,6 @@
 
     // Thread handlers
     pthread_t mDvrThread;
-    pthread_t mBroadcastInputThread;
 
     // FMQ status local records
     PlaybackStatus mPlaybackStatus;
@@ -132,7 +132,6 @@
      * If a specific filter's writing loop is still running
      */
     bool mDvrThreadRunning;
-    bool mBroadcastInputThreadRunning;
     bool mKeepFetchingDataFromFrontend;
     /**
      * Lock to protect writes to the FMQs
@@ -143,7 +142,6 @@
      */
     std::mutex mPlaybackStatusLock;
     std::mutex mRecordStatusLock;
-    std::mutex mBroadcastInputThreadLock;
     std::mutex mDvrThreadLock;
 
     const bool DEBUG_DVR = false;
@@ -151,7 +149,6 @@
     // Booleans to check if recording is running.
     // Recording is ready when both of the following are set to true.
     bool mIsRecordStarted = false;
-    bool mIsRecordFilterAttached = false;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Filter.cpp b/tv/tuner/1.0/default/Filter.cpp
index 8bca70c..30b19c0 100644
--- a/tv/tuner/1.0/default/Filter.cpp
+++ b/tv/tuner/1.0/default/Filter.cpp
@@ -47,12 +47,18 @@
             if (mType.subType.tsFilterType() == DemuxTsFilterType::PCR) {
                 mIsPcrFilter = true;
             }
+            if (mType.subType.tsFilterType() == DemuxTsFilterType::RECORD) {
+                mIsRecordFilter = true;
+            }
             break;
         case DemuxFilterMainType::MMTP:
             if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::AUDIO ||
                 mType.subType.mmtpFilterType() == DemuxMmtpFilterType::VIDEO) {
                 mIsMediaFilter = true;
             }
+            if (mType.subType.mmtpFilterType() == DemuxMmtpFilterType::RECORD) {
+                mIsRecordFilter = true;
+            }
             break;
         case DemuxFilterMainType::IP:
             break;
@@ -535,12 +541,6 @@
 }
 
 Result Filter::startRecordFilterHandler() {
-    /*DemuxFilterTsRecordEvent tsRecordEvent;
-    tsRecordEvent.pid.tPid(0);
-    tsRecordEvent.indexMask.tsIndexMask(0x01);
-    mFilterEvent.events.resize(1);
-    mFilterEvent.events[0].tsRecord(tsRecordEvent);
-*/
     std::lock_guard<std::mutex> lock(mRecordFilterOutputLock);
     if (mRecordFilterOutput.empty()) {
         return Result::SUCCESS;
@@ -567,7 +567,7 @@
 
 bool Filter::writeSectionsAndCreateEvent(vector<uint8_t> data) {
     // TODO check how many sections has been read
-    ALOGD("[Filter] section hander");
+    ALOGD("[Filter] section handler");
     std::lock_guard<std::mutex> lock(mFilterEventLock);
     if (!writeDataToFilterMQ(data)) {
         return false;
diff --git a/tv/tuner/1.0/default/Filter.h b/tv/tuner/1.0/default/Filter.h
index 09e9604..9386dca 100644
--- a/tv/tuner/1.0/default/Filter.h
+++ b/tv/tuner/1.0/default/Filter.h
@@ -91,6 +91,7 @@
     void freeAvHandle();
     bool isMediaFilter() { return mIsMediaFilter; };
     bool isPcrFilter() { return mIsPcrFilter; };
+    bool isRecordFilter() { return mIsRecordFilter; };
 
   private:
     // Tuner service
@@ -107,6 +108,7 @@
     DemuxFilterType mType;
     bool mIsMediaFilter = false;
     bool mIsPcrFilter = false;
+    bool mIsRecordFilter = false;
     DemuxFilterSettings mFilterSettings;
 
     uint16_t mTpid;
diff --git a/tv/tuner/1.0/default/Frontend.cpp b/tv/tuner/1.0/default/Frontend.cpp
index 61bbbf8..8bf0ec5 100644
--- a/tv/tuner/1.0/default/Frontend.cpp
+++ b/tv/tuner/1.0/default/Frontend.cpp
@@ -66,7 +66,7 @@
 
     mTunerService->frontendStartTune(mId);
     mCallback->onEvent(FrontendEventType::LOCKED);
-    mIsLocked = false;
+    mIsLocked = true;
     return Result::SUCCESS;
 }
 
@@ -268,14 +268,14 @@
     return mId;
 }
 
-string Frontend::getSourceFile() {
-    return FRONTEND_STREAM_FILE;
-}
-
 bool Frontend::supportsSatellite() {
     return mType == FrontendType::DVBS || mType == FrontendType::ISDBS ||
            mType == FrontendType::ISDBS3;
 }
+
+bool Frontend::isLocked() {
+    return mIsLocked;
+}
 }  // namespace implementation
 }  // namespace V1_0
 }  // namespace tuner
diff --git a/tv/tuner/1.0/default/Frontend.h b/tv/tuner/1.0/default/Frontend.h
index c0d1613..a529b74 100644
--- a/tv/tuner/1.0/default/Frontend.h
+++ b/tv/tuner/1.0/default/Frontend.h
@@ -68,6 +68,8 @@
 
     string getSourceFile();
 
+    bool isLocked();
+
   private:
     virtual ~Frontend();
     bool supportsSatellite();
@@ -77,7 +79,6 @@
     FrontendId mId = 0;
     bool mIsLocked = false;
 
-    const string FRONTEND_STREAM_FILE = "/vendor/etc/segment000000.ts";
     std::ifstream mFrontendData;
 };
 
diff --git a/tv/tuner/1.0/default/TimeFilter.cpp b/tv/tuner/1.0/default/TimeFilter.cpp
index 0b1fd1c..cec824f 100644
--- a/tv/tuner/1.0/default/TimeFilter.cpp
+++ b/tv/tuner/1.0/default/TimeFilter.cpp
@@ -34,24 +34,32 @@
 
 TimeFilter::~TimeFilter() {}
 
-Return<Result> TimeFilter::setTimeStamp(uint64_t /* timeStamp */) {
+Return<Result> TimeFilter::setTimeStamp(uint64_t timeStamp) {
     ALOGV("%s", __FUNCTION__);
+    if (timeStamp == INVALID_TIME_STAMP) {
+        return Result::INVALID_ARGUMENT;
+    }
+    mTimeStamp = timeStamp;
+    mBeginTime = time(NULL);
 
     return Result::SUCCESS;
 }
 
 Return<Result> TimeFilter::clearTimeStamp() {
     ALOGV("%s", __FUNCTION__);
+    mTimeStamp = INVALID_TIME_STAMP;
 
     return Result::SUCCESS;
 }
 
 Return<void> TimeFilter::getTimeStamp(getTimeStamp_cb _hidl_cb) {
     ALOGV("%s", __FUNCTION__);
+    if (mTimeStamp == INVALID_TIME_STAMP) {
+        _hidl_cb(Result::INVALID_STATE, mTimeStamp);
+    }
 
-    uint64_t timeStamp = 0;
-
-    _hidl_cb(Result::SUCCESS, timeStamp);
+    uint64_t currentTimeStamp = mTimeStamp + difftime(time(NULL), mBeginTime) * 900000;
+    _hidl_cb(Result::SUCCESS, currentTimeStamp);
     return Void();
 }
 
@@ -66,6 +74,7 @@
 
 Return<Result> TimeFilter::close() {
     ALOGV("%s", __FUNCTION__);
+    mTimeStamp = INVALID_TIME_STAMP;
 
     return Result::SUCCESS;
 }
diff --git a/tv/tuner/1.0/default/TimeFilter.h b/tv/tuner/1.0/default/TimeFilter.h
index 7131df8..cb3f29d 100644
--- a/tv/tuner/1.0/default/TimeFilter.h
+++ b/tv/tuner/1.0/default/TimeFilter.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/tv/tuner/1.0/ITimeFilter.h>
 #include "Demux.h"
+#include "time.h"
 
 using namespace std;
 
@@ -35,6 +36,8 @@
 
 using FilterMQ = MessageQueue<uint8_t, kSynchronizedReadWrite>;
 
+#define INVALID_TIME_STAMP -1
+
 class Demux;
 
 class TimeFilter : public ITimeFilter {
@@ -57,6 +60,8 @@
 
   private:
     sp<Demux> mDemux;
+    uint64_t mTimeStamp = INVALID_TIME_STAMP;
+    time_t mBeginTime;
 };
 
 }  // namespace implementation
diff --git a/tv/tuner/1.0/default/Tuner.cpp b/tv/tuner/1.0/default/Tuner.cpp
index ae8070c..48ce384 100644
--- a/tv/tuner/1.0/default/Tuner.cpp
+++ b/tv/tuner/1.0/default/Tuner.cpp
@@ -231,6 +231,9 @@
 
 void Tuner::setFrontendAsDemuxSource(uint32_t frontendId, uint32_t demuxId) {
     mFrontendToDemux[frontendId] = demuxId;
+    if (mFrontends[frontendId] != nullptr && mFrontends[frontendId]->isLocked()) {
+        mDemuxes[demuxId]->startFrontendInputLoop();
+    }
 }
 
 void Tuner::frontendStopTune(uint32_t frontendId) {
diff --git a/tv/tuner/1.0/vts/functional/DvrTests.cpp b/tv/tuner/1.0/vts/functional/DvrTests.cpp
index 7e7f8e6..0dfc032 100644
--- a/tv/tuner/1.0/vts/functional/DvrTests.cpp
+++ b/tv/tuner/1.0/vts/functional/DvrTests.cpp
@@ -49,49 +49,73 @@
     EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
                 android::OK);
 
-    // open the stream and get its length
-    std::ifstream inputData(mInputDataFile.c_str(), std::ifstream::binary);
-    int writeSize = mPlaybackSettings.packetSize * 6;
-    char* buffer = new char[writeSize];
-    ALOGW("[vts] playback thread loop start %s!", mInputDataFile.c_str());
-    if (!inputData.is_open()) {
+    int fd = open(mInputDataFile.c_str(), O_RDONLY | O_LARGEFILE);
+    int readBytes;
+    uint32_t regionSize = 0;
+    uint8_t* buffer;
+    ALOGW("[vts] playback thread loop start %s", mInputDataFile.c_str());
+    if (fd < 0) {
         mPlaybackThreadRunning = false;
         ALOGW("[vts] Error %s", strerror(errno));
     }
 
     while (mPlaybackThreadRunning) {
-        // move the stream pointer for packet size * 6 every read until the end
         while (mKeepWritingPlaybackFMQ) {
-            inputData.read(buffer, writeSize);
-            if (!inputData) {
-                int leftSize = inputData.gcount();
-                if (leftSize == 0) {
-                    mPlaybackThreadRunning = false;
-                    break;
-                }
-                inputData.clear();
-                inputData.read(buffer, leftSize);
-                // Write the left over of the input data and quit the thread
-                if (leftSize > 0) {
-                    EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], leftSize));
-                    playbackMQEventFlag->wake(
-                            static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
-                }
+            int totalWrite = mPlaybackMQ->availableToWrite();
+            if (totalWrite * 4 < mPlaybackMQ->getQuantumCount()) {
+                // Wait for the HAL implementation to read more data then write.
+                continue;
+            }
+            MessageQueue<uint8_t, kSynchronizedReadWrite>::MemTransaction memTx;
+            if (!mPlaybackMQ->beginWrite(totalWrite, &memTx)) {
+                ALOGW("[vts] Fail to write into Playback fmq.");
                 mPlaybackThreadRunning = false;
                 break;
             }
-            // Write input FMQ and notify the Tuner Implementation
-            EXPECT_TRUE(mPlaybackMQ->write((unsigned char*)&buffer[0], writeSize));
+            auto first = memTx.getFirstRegion();
+            buffer = first.getAddress();
+            regionSize = first.getLength();
+
+            if (regionSize > 0) {
+                readBytes = read(fd, buffer, regionSize);
+                if (readBytes <= 0) {
+                    if (readBytes < 0) {
+                        ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
+                    } else {
+                        ALOGW("[vts] playback input EOF.");
+                    }
+                    mPlaybackThreadRunning = false;
+                    break;
+                }
+            }
+            if (regionSize == 0 || (readBytes == regionSize && regionSize < totalWrite)) {
+                auto second = memTx.getSecondRegion();
+                buffer = second.getAddress();
+                regionSize = second.getLength();
+                int ret = read(fd, buffer, regionSize);
+                if (ret <= 0) {
+                    if (ret < 0) {
+                        ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
+                    } else {
+                        ALOGW("[vts] playback input EOF.");
+                    }
+                    mPlaybackThreadRunning = false;
+                    break;
+                }
+                readBytes += ret;
+            }
+            if (!mPlaybackMQ->commitWrite(readBytes)) {
+                ALOGW("[vts] Failed to commit write playback fmq.");
+                mPlaybackThreadRunning = false;
+                break;
+            }
             playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
-            inputData.seekg(writeSize, inputData.cur);
-            sleep(1);
         }
     }
 
+    mPlaybackThreadRunning = false;
     ALOGW("[vts] Playback thread end.");
-
-    delete[] buffer;
-    inputData.close();
+    close(fd);
 }
 
 void DvrCallback::testRecordOutput() {
@@ -186,32 +210,65 @@
     EXPECT_TRUE(mDemux) << "Test with openDemux first.";
 
     // Create dvr callback
-    mDvrCallback = new DvrCallback();
+    if (type == DvrType::PLAYBACK) {
+        mDvrPlaybackCallback = new DvrCallback();
+        mDemux->openDvr(type, bufferSize, mDvrPlaybackCallback,
+                        [&](Result result, const sp<IDvr>& dvr) {
+                            mDvrPlayback = dvr;
+                            status = result;
+                        });
+        if (status == Result::SUCCESS) {
+            mDvrPlaybackCallback->setDvr(mDvrPlayback);
+        }
+    }
 
-    mDemux->openDvr(type, bufferSize, mDvrCallback, [&](Result result, const sp<IDvr>& dvr) {
-        mDvr = dvr;
+    if (type == DvrType::RECORD) {
+        mDvrRecordCallback = new DvrCallback();
+        mDemux->openDvr(type, bufferSize, mDvrRecordCallback,
+                        [&](Result result, const sp<IDvr>& dvr) {
+                            mDvrRecord = dvr;
+                            status = result;
+                        });
+        if (status == Result::SUCCESS) {
+            mDvrRecordCallback->setDvr(mDvrRecord);
+        }
+    }
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::configDvrPlayback(DvrSettings setting) {
+    Result status = mDvrPlayback->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::configDvrRecord(DvrSettings setting) {
+    Result status = mDvrRecord->configure(setting);
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::getDvrPlaybackMQDescriptor() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
+
+    mDvrPlayback->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mDvrPlaybackMQDescriptor = dvrMQDesc;
         status = result;
     });
 
-    if (status == Result::SUCCESS) {
-        mDvrCallback->setDvr(mDvr);
-    }
     return AssertionResult(status == Result::SUCCESS);
 }
 
-AssertionResult DvrTests::configDvr(DvrSettings setting) {
-    Result status = mDvr->configure(setting);
-
-    return AssertionResult(status == Result::SUCCESS);
-}
-
-AssertionResult DvrTests::getDvrMQDescriptor() {
+AssertionResult DvrTests::getDvrRecordMQDescriptor() {
     Result status;
     EXPECT_TRUE(mDemux) << "Test with openDemux first.";
-    EXPECT_TRUE(mDvr) << "Test with openDvr first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
 
-    mDvr->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
-        mDvrMQDescriptor = dvrMQDesc;
+    mDvrRecord->getQueueDesc([&](Result result, const MQDesc& dvrMQDesc) {
+        mDvrRecordMQDescriptor = dvrMQDesc;
         status = result;
     });
 
@@ -221,9 +278,9 @@
 AssertionResult DvrTests::attachFilterToDvr(sp<IFilter> filter) {
     Result status;
     EXPECT_TRUE(mDemux) << "Test with openDemux first.";
-    EXPECT_TRUE(mDvr) << "Test with openDvr first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
 
-    status = mDvr->attachFilter(filter);
+    status = mDvrRecord->attachFilter(filter);
 
     return AssertionResult(status == Result::SUCCESS);
 }
@@ -231,35 +288,61 @@
 AssertionResult DvrTests::detachFilterToDvr(sp<IFilter> filter) {
     Result status;
     EXPECT_TRUE(mDemux) << "Test with openDemux first.";
-    EXPECT_TRUE(mDvr) << "Test with openDvr first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
 
-    status = mDvr->detachFilter(filter);
+    status = mDvrRecord->detachFilter(filter);
 
     return AssertionResult(status == Result::SUCCESS);
 }
 
-AssertionResult DvrTests::startDvr() {
+AssertionResult DvrTests::startDvrPlayback() {
     Result status;
     EXPECT_TRUE(mDemux) << "Test with openDemux first.";
-    EXPECT_TRUE(mDvr) << "Test with openDvr first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
 
-    status = mDvr->start();
+    status = mDvrPlayback->start();
 
     return AssertionResult(status == Result::SUCCESS);
 }
 
-AssertionResult DvrTests::stopDvr() {
+AssertionResult DvrTests::stopDvrPlayback() {
     Result status;
     EXPECT_TRUE(mDemux) << "Test with openDemux first.";
-    EXPECT_TRUE(mDvr) << "Test with openDvr first.";
+    EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
 
-    status = mDvr->stop();
+    status = mDvrPlayback->stop();
 
     return AssertionResult(status == Result::SUCCESS);
 }
 
-void DvrTests::closeDvr() {
+void DvrTests::closeDvrPlayback() {
     ASSERT_TRUE(mDemux);
-    ASSERT_TRUE(mDvr);
-    ASSERT_TRUE(mDvr->close() == Result::SUCCESS);
+    ASSERT_TRUE(mDvrPlayback);
+    ASSERT_TRUE(mDvrPlayback->close() == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::startDvrRecord() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->start();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult DvrTests::stopDvrRecord() {
+    Result status;
+    EXPECT_TRUE(mDemux) << "Test with openDemux first.";
+    EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
+
+    status = mDvrRecord->stop();
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+void DvrTests::closeDvrRecord() {
+    ASSERT_TRUE(mDemux);
+    ASSERT_TRUE(mDvrRecord);
+    ASSERT_TRUE(mDvrRecord->close() == Result::SUCCESS);
 }
diff --git a/tv/tuner/1.0/vts/functional/DvrTests.h b/tv/tuner/1.0/vts/functional/DvrTests.h
index dd00c27..3997839 100644
--- a/tv/tuner/1.0/vts/functional/DvrTests.h
+++ b/tv/tuner/1.0/vts/functional/DvrTests.h
@@ -14,14 +14,15 @@
  * limitations under the License.
  */
 
-#include <VtsHalHidlTargetTestBase.h>
-#include <VtsHalHidlTargetTestEnvBase.h>
 #include <android-base/logging.h>
 #include <android/hardware/tv/tuner/1.0/IDvr.h>
 #include <android/hardware/tv/tuner/1.0/IDvrCallback.h>
 #include <android/hardware/tv/tuner/1.0/ITuner.h>
 #include <android/hardware/tv/tuner/1.0/types.h>
+#include <fcntl.h>
 #include <fmq/MessageQueue.h>
+#include <gtest/gtest.h>
+#include <hidl/HidlSupport.h>
 #include <hidl/Status.h>
 #include <utils/Condition.h>
 #include <utils/Mutex.h>
@@ -52,6 +53,8 @@
 using android::hardware::tv::tuner::V1_0::RecordStatus;
 using android::hardware::tv::tuner::V1_0::Result;
 
+using namespace std;
+
 #define WAIT_TIMEOUT 3000000000
 
 class DvrCallback : public IDvrCallback {
@@ -149,25 +152,31 @@
     void setDemux(sp<IDemux> demux) { mDemux = demux; }
 
     void startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings) {
-        mDvrCallback->startPlaybackInputThread(dataInputFile, settings, mDvrMQDescriptor);
+        mDvrPlaybackCallback->startPlaybackInputThread(dataInputFile, settings,
+                                                       mDvrPlaybackMQDescriptor);
     };
 
     void startRecordOutputThread(RecordSettings settings) {
-        mDvrCallback->startRecordOutputThread(settings, mDvrMQDescriptor);
+        mDvrRecordCallback->startRecordOutputThread(settings, mDvrRecordMQDescriptor);
     };
 
-    void stopPlaybackThread() { mDvrCallback->stopPlaybackThread(); }
-    void testRecordOutput() { mDvrCallback->testRecordOutput(); }
-    void stopRecordThread() { mDvrCallback->stopPlaybackThread(); }
+    void stopPlaybackThread() { mDvrPlaybackCallback->stopPlaybackThread(); }
+    void testRecordOutput() { mDvrRecordCallback->testRecordOutput(); }
+    void stopRecordThread() { mDvrRecordCallback->stopRecordThread(); }
 
     AssertionResult openDvrInDemux(DvrType type, uint32_t bufferSize);
-    AssertionResult configDvr(DvrSettings setting);
-    AssertionResult getDvrMQDescriptor();
+    AssertionResult configDvrPlayback(DvrSettings setting);
+    AssertionResult configDvrRecord(DvrSettings setting);
+    AssertionResult getDvrPlaybackMQDescriptor();
+    AssertionResult getDvrRecordMQDescriptor();
     AssertionResult attachFilterToDvr(sp<IFilter> filter);
     AssertionResult detachFilterToDvr(sp<IFilter> filter);
-    AssertionResult stopDvr();
-    AssertionResult startDvr();
-    void closeDvr();
+    AssertionResult stopDvrPlayback();
+    AssertionResult startDvrPlayback();
+    AssertionResult stopDvrRecord();
+    AssertionResult startDvrRecord();
+    void closeDvrPlayback();
+    void closeDvrRecord();
 
   protected:
     static AssertionResult failure() { return ::testing::AssertionFailure(); }
@@ -175,11 +184,11 @@
     static AssertionResult success() { return ::testing::AssertionSuccess(); }
 
     sp<ITuner> mService;
-    sp<IDvr> mDvr;
+    sp<IDvr> mDvrPlayback;
+    sp<IDvr> mDvrRecord;
     sp<IDemux> mDemux;
-    sp<DvrCallback> mDvrCallback;
-    MQDesc mDvrMQDescriptor;
-
-    pthread_t mPlaybackshread;
-    bool mPlaybackThreadRunning;
+    sp<DvrCallback> mDvrPlaybackCallback;
+    sp<DvrCallback> mDvrRecordCallback;
+    MQDesc mDvrPlaybackMQDescriptor;
+    MQDesc mDvrRecordMQDescriptor;
 };
diff --git a/tv/tuner/1.0/vts/functional/FilterTests.cpp b/tv/tuner/1.0/vts/functional/FilterTests.cpp
index ca8bd19..0ecdf73 100644
--- a/tv/tuner/1.0/vts/functional/FilterTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FilterTests.cpp
@@ -149,6 +149,44 @@
     return AssertionResult(status == Result::SUCCESS);
 }
 
+AssertionResult FilterTests::openTimeFilterInDemux() {
+    if (!mDemux) {
+        ALOGW("[vts] Test with openDemux first.");
+        return failure();
+    }
+
+    // Add time filter to the local demux
+    Result status;
+    mDemux->openTimeFilter([&](Result result, const sp<ITimeFilter>& filter) {
+        mTimeFilter = filter;
+        status = result;
+    });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::setTimeStamp(uint64_t timeStamp) {
+    if (!mTimeFilter) {
+        ALOGW("[vts] Test with openTimeFilterInDemux first.");
+        return failure();
+    }
+
+    mBeginTimeStamp = timeStamp;
+    return AssertionResult(mTimeFilter->setTimeStamp(timeStamp) == Result::SUCCESS);
+}
+
+AssertionResult FilterTests::getTimeStamp() {
+    if (!mTimeFilter) {
+        ALOGW("[vts] Test with openTimeFilterInDemux first.");
+        return failure();
+    }
+
+    Result status;
+    mTimeFilter->getTimeStamp([&](Result result, uint64_t /*timeStamp*/) { status = result; });
+
+    return AssertionResult(status == Result::SUCCESS);
+}
+
 AssertionResult FilterTests::getNewlyOpenedFilterId(uint32_t& filterId) {
     Result status;
     EXPECT_TRUE(mDemux) << "Test with openDemux first.";
@@ -229,6 +267,15 @@
     return AssertionResult(status == Result::SUCCESS);
 }
 
+AssertionResult FilterTests::clearTimeStamp() {
+    if (!mTimeFilter) {
+        ALOGW("[vts] Test with openTimeFilterInDemux first.");
+        return failure();
+    }
+
+    return AssertionResult(mTimeFilter->clearTimeStamp() == Result::SUCCESS);
+}
+
 AssertionResult FilterTests::closeFilter(uint32_t filterId) {
     EXPECT_TRUE(mFilters[filterId]) << "Test with getNewlyOpenedFilterId first.";
     Result status = mFilters[filterId]->close();
@@ -244,3 +291,12 @@
     }
     return AssertionResult(status == Result::SUCCESS);
 }
+
+AssertionResult FilterTests::closeTimeFilter() {
+    if (!mTimeFilter) {
+        ALOGW("[vts] Test with openTimeFilterInDemux first.");
+        return failure();
+    }
+
+    return AssertionResult(mTimeFilter->close() == Result::SUCCESS);
+}
diff --git a/tv/tuner/1.0/vts/functional/FilterTests.h b/tv/tuner/1.0/vts/functional/FilterTests.h
index 2aa1b90..a76a6b9 100644
--- a/tv/tuner/1.0/vts/functional/FilterTests.h
+++ b/tv/tuner/1.0/vts/functional/FilterTests.h
@@ -57,6 +57,7 @@
 using android::hardware::tv::tuner::V1_0::IDemux;
 using android::hardware::tv::tuner::V1_0::IFilter;
 using android::hardware::tv::tuner::V1_0::IFilterCallback;
+using android::hardware::tv::tuner::V1_0::ITimeFilter;
 using android::hardware::tv::tuner::V1_0::ITuner;
 using android::hardware::tv::tuner::V1_0::Result;
 
@@ -151,14 +152,19 @@
     std::map<uint32_t, sp<FilterCallback>> getFilterCallbacks() { return mFilterCallbacks; }
 
     AssertionResult openFilterInDemux(DemuxFilterType type, uint32_t bufferSize);
+    AssertionResult openTimeFilterInDemux();
+    AssertionResult setTimeStamp(uint64_t timeStamp);
+    AssertionResult getTimeStamp();
     AssertionResult getNewlyOpenedFilterId(uint32_t& filterId);
     AssertionResult configFilter(DemuxFilterSettings setting, uint32_t filterId);
     AssertionResult getFilterMQDescriptor(uint32_t filterId);
     AssertionResult setFilterDataSource(uint32_t sourceFilterId, uint32_t sinkFilterId);
     AssertionResult setFilterDataSourceToDemux(uint32_t filterId);
     AssertionResult startFilter(uint32_t filterId);
+    AssertionResult clearTimeStamp();
     AssertionResult stopFilter(uint32_t filterId);
     AssertionResult closeFilter(uint32_t filterId);
+    AssertionResult closeTimeFilter();
 
     FilterEventType getFilterEventType(DemuxFilterType type) {
         FilterEventType eventType = FilterEventType::UNDEFINED;
@@ -214,6 +220,7 @@
 
     sp<ITuner> mService;
     sp<IFilter> mFilter;
+    sp<ITimeFilter> mTimeFilter;
     sp<IDemux> mDemux;
     std::map<uint32_t, sp<IFilter>> mFilters;
     std::map<uint32_t, sp<FilterCallback>> mFilterCallbacks;
@@ -223,4 +230,5 @@
     vector<uint32_t> mUsedFilterIds;
 
     uint32_t mFilterId = -1;
+    uint64_t mBeginTimeStamp;
 };
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.cpp b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
index d094510..45951d2 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.cpp
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.cpp
@@ -360,13 +360,28 @@
     ASSERT_TRUE(status == Result::SUCCESS);
 }
 
-AssertionResult FrontendTests::tuneFrontend(FrontendConfig config) {
+AssertionResult FrontendTests::tuneFrontend(FrontendConfig config, bool testWithDemux) {
     EXPECT_TRUE(mFrontendCallback)
             << "test with openFrontendById/setFrontendCallback/getFrontendInfo first.";
 
     EXPECT_TRUE(mFrontendInfo.type == config.type)
             << "FrontendConfig does not match the frontend info of the given id.";
 
+    mIsSoftwareFe = config.isSoftwareFe;
+    bool result = true;
+    if (mIsSoftwareFe && testWithDemux) {
+        DvrConfig dvrConfig;
+        getSoftwareFrontendPlaybackConfig(dvrConfig);
+        result &= mDvrTests.openDvrInDemux(dvrConfig.type, dvrConfig.bufferSize) == success();
+        result &= mDvrTests.configDvrPlayback(dvrConfig.settings) == success();
+        result &= mDvrTests.getDvrPlaybackMQDescriptor() == success();
+        mDvrTests.startPlaybackInputThread(dvrConfig.playbackInputFile,
+                                           dvrConfig.settings.playback());
+        if (!result) {
+            ALOGW("[vts] Software frontend dvr configure failed.");
+            return failure();
+        }
+    }
     mFrontendCallback->tuneTestOnLock(mFrontend, config.settings);
     return AssertionResult(true);
 }
@@ -379,10 +394,14 @@
     return AssertionResult(mFrontend->setLnb(lnbId) == Result::SUCCESS);
 }
 
-AssertionResult FrontendTests::stopTuneFrontend() {
+AssertionResult FrontendTests::stopTuneFrontend(bool testWithDemux) {
     EXPECT_TRUE(mFrontend) << "Test with openFrontendById first.";
     Result status;
     status = mFrontend->stopTune();
+    if (mIsSoftwareFe && testWithDemux) {
+        mDvrTests.stopPlaybackThread();
+        mDvrTests.closeDvrPlayback();
+    }
     return AssertionResult(status == Result::SUCCESS);
 }
 
@@ -415,9 +434,9 @@
     ASSERT_TRUE(feId != INVALID_ID);
     ASSERT_TRUE(openFrontendById(feId));
     ASSERT_TRUE(setFrontendCallback());
-    ASSERT_TRUE(tuneFrontend(frontendConf));
+    ASSERT_TRUE(tuneFrontend(frontendConf, false /*testWithDemux*/));
     verifyFrontendStatus(frontendConf.tuneStatusTypes, frontendConf.expectTuneStatuses);
-    ASSERT_TRUE(stopTuneFrontend());
+    ASSERT_TRUE(stopTuneFrontend(false /*testWithDemux*/));
     ASSERT_TRUE(closeFrontend());
 }
 
diff --git a/tv/tuner/1.0/vts/functional/FrontendTests.h b/tv/tuner/1.0/vts/functional/FrontendTests.h
index b8b9f47..c536325 100644
--- a/tv/tuner/1.0/vts/functional/FrontendTests.h
+++ b/tv/tuner/1.0/vts/functional/FrontendTests.h
@@ -31,6 +31,7 @@
 #include <utils/Mutex.h>
 #include <map>
 
+#include "DvrTests.h"
 #include "VtsHalTvTunerV1_0TestConfigurations.h"
 
 #define WAIT_TIMEOUT 3000000000
@@ -100,7 +101,10 @@
   public:
     sp<ITuner> mService;
 
-    void setService(sp<ITuner> tuner) { mService = tuner; }
+    void setService(sp<ITuner> tuner) {
+        mService = tuner;
+        mDvrTests.setService(tuner);
+    }
 
     AssertionResult getFrontendIds();
     AssertionResult getFrontendInfo(uint32_t frontendId);
@@ -108,23 +112,43 @@
     AssertionResult setFrontendCallback();
     AssertionResult scanFrontend(FrontendConfig config, FrontendScanType type);
     AssertionResult stopScanFrontend();
-    AssertionResult tuneFrontend(FrontendConfig config);
+    AssertionResult tuneFrontend(FrontendConfig config, bool testWithDemux);
     AssertionResult setLnb(uint32_t lnbId);
     void verifyFrontendStatus(vector<FrontendStatusType> statusTypes,
                               vector<FrontendStatus> expectStatuses);
-    AssertionResult stopTuneFrontend();
+    AssertionResult stopTuneFrontend(bool testWithDemux);
     AssertionResult closeFrontend();
 
     void getFrontendIdByType(FrontendType feType, uint32_t& feId);
     void tuneTest(FrontendConfig frontendConf);
     void scanTest(FrontendConfig frontend, FrontendScanType type);
 
+    void setDvrTests(DvrTests dvrTests) { mDvrTests = dvrTests; }
+    void setDemux(sp<IDemux> demux) { mDvrTests.setDemux(demux); }
+
   protected:
     static AssertionResult failure() { return ::testing::AssertionFailure(); }
     static AssertionResult success() { return ::testing::AssertionSuccess(); }
 
+    void getSoftwareFrontendPlaybackConfig(DvrConfig& dvrConfig) {
+        PlaybackSettings playbackSettings{
+                .statusMask = 0xf,
+                .lowThreshold = 0x1000,
+                .highThreshold = 0x07fff,
+                .dataFormat = DataFormat::TS,
+                .packetSize = 188,
+        };
+        dvrConfig.type = DvrType::PLAYBACK;
+        dvrConfig.playbackInputFile = "/data/local/tmp/segment000000.ts";
+        dvrConfig.bufferSize = FMQ_SIZE_4M;
+        dvrConfig.settings.playback(playbackSettings);
+    }
+
     sp<IFrontend> mFrontend;
     FrontendInfo mFrontendInfo;
     sp<FrontendCallback> mFrontendCallback;
     hidl_vec<FrontendId> mFeIds;
+
+    DvrTests mDvrTests;
+    bool mIsSoftwareFe = false;
 };
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
index e1284b4..6819659 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.cpp
@@ -56,6 +56,23 @@
     ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
 
+void TunerFilterHidlTest::testTimeFilter(TimeFilterConfig filterConf) {
+    if (!filterConf.supportTimeFilter) {
+        return;
+    }
+    uint32_t demuxId;
+    sp<IDemux> demux;
+
+    ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
+    mFilterTests.setDemux(demux);
+    ASSERT_TRUE(mFilterTests.openTimeFilterInDemux());
+    ASSERT_TRUE(mFilterTests.setTimeStamp(filterConf.timeStamp));
+    ASSERT_TRUE(mFilterTests.getTimeStamp());
+    ASSERT_TRUE(mFilterTests.clearTimeStamp());
+    ASSERT_TRUE(mFilterTests.closeTimeFilter());
+    ASSERT_TRUE(mDemuxTests.closeDemux());
+}
+
 void TunerBroadcastHidlTest::broadcastSingleFilterTest(FilterConfig filterConf,
                                                        FrontendConfig frontendConf) {
     uint32_t feId;
@@ -77,6 +94,7 @@
     }
     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(filterId));
@@ -84,9 +102,9 @@
     ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     // tune test
-    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf));
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
     ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
-    ASSERT_TRUE(mFrontendTests.stopTuneFrontend());
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
     ASSERT_TRUE(mDemuxTests.closeDemux());
@@ -122,21 +140,21 @@
     mFilterTests.setDemux(demux);
     mDvrTests.setDemux(demux);
     ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
-    ASSERT_TRUE(mDvrTests.configDvr(dvrConf.settings));
-    ASSERT_TRUE(mDvrTests.getDvrMQDescriptor());
+    ASSERT_TRUE(mDvrTests.configDvrPlayback(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrPlaybackMQDescriptor());
     ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
     ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
     ASSERT_TRUE(mFilterTests.getFilterMQDescriptor(filterId));
     mDvrTests.startPlaybackInputThread(dvrConf.playbackInputFile, dvrConf.settings.playback());
-    ASSERT_TRUE(mDvrTests.startDvr());
+    ASSERT_TRUE(mDvrTests.startDvrPlayback());
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
     mDvrTests.stopPlaybackThread();
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
-    ASSERT_TRUE(mDvrTests.stopDvr());
+    ASSERT_TRUE(mDvrTests.stopDvrPlayback());
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
-    mDvrTests.closeDvr();
+    mDvrTests.closeDvrPlayback();
     ASSERT_TRUE(mDemuxTests.closeDemux());
 }
 
@@ -159,9 +177,10 @@
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
     mFilterTests.setDemux(demux);
     mDvrTests.setDemux(demux);
+    mFrontendTests.setDvrTests(mDvrTests);
     ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
-    ASSERT_TRUE(mDvrTests.configDvr(dvrConf.settings));
-    ASSERT_TRUE(mDvrTests.getDvrMQDescriptor());
+    ASSERT_TRUE(mDvrTests.configDvrRecord(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrRecordMQDescriptor());
     ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
     ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
@@ -170,17 +189,17 @@
     ASSERT_TRUE(filter != nullptr);
     mDvrTests.startRecordOutputThread(dvrConf.settings.record());
     ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter));
-    ASSERT_TRUE(mDvrTests.startDvr());
+    ASSERT_TRUE(mDvrTests.startDvrRecord());
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
-    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf));
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
     mDvrTests.testRecordOutput();
     mDvrTests.stopRecordThread();
-    ASSERT_TRUE(mFrontendTests.stopTuneFrontend());
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
-    ASSERT_TRUE(mDvrTests.stopDvr());
+    ASSERT_TRUE(mDvrTests.stopDvrRecord());
     ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter));
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
-    mDvrTests.closeDvr();
+    mDvrTests.closeDvrRecord();
     ASSERT_TRUE(mDemuxTests.closeDemux());
     ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
@@ -223,8 +242,8 @@
     mFilterTests.setDemux(demux);
     mDvrTests.setDemux(demux);
     ASSERT_TRUE(mDvrTests.openDvrInDemux(dvrConf.type, dvrConf.bufferSize));
-    ASSERT_TRUE(mDvrTests.configDvr(dvrConf.settings));
-    ASSERT_TRUE(mDvrTests.getDvrMQDescriptor());
+    ASSERT_TRUE(mDvrTests.configDvrRecord(dvrConf.settings));
+    ASSERT_TRUE(mDvrTests.getDvrRecordMQDescriptor());
     ASSERT_TRUE(mFilterTests.openFilterInDemux(filterConf.type, filterConf.bufferSize));
     ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
     ASSERT_TRUE(mFilterTests.configFilter(filterConf.settings, filterId));
@@ -232,13 +251,13 @@
     filter = mFilterTests.getFilterById(filterId);
     ASSERT_TRUE(filter != nullptr);
     ASSERT_TRUE(mDvrTests.attachFilterToDvr(filter));
-    ASSERT_TRUE(mDvrTests.startDvr());
+    ASSERT_TRUE(mDvrTests.startDvrRecord());
     ASSERT_TRUE(mFilterTests.startFilter(filterId));
     ASSERT_TRUE(mFilterTests.stopFilter(filterId));
-    ASSERT_TRUE(mDvrTests.stopDvr());
+    ASSERT_TRUE(mDvrTests.stopDvrRecord());
     ASSERT_TRUE(mDvrTests.detachFilterToDvr(filter));
     ASSERT_TRUE(mFilterTests.closeFilter(filterId));
-    mDvrTests.closeDvr();
+    mDvrTests.closeDvrRecord();
     ASSERT_TRUE(mDemuxTests.closeDemux());
     ASSERT_TRUE(mFrontendTests.closeFrontend());
 }
@@ -266,6 +285,7 @@
     ASSERT_TRUE(mDemuxTests.openDemux(demux, demuxId));
     ASSERT_TRUE(mDemuxTests.setDemuxFrontendDataSource(feId));
     mFilterTests.setDemux(demux);
+    mFrontendTests.setDemux(demux);
     for (config = mediaFilterConfs.begin(); config != mediaFilterConfs.end(); config++) {
         ASSERT_TRUE(mFilterTests.openFilterInDemux((*config).type, (*config).bufferSize));
         ASSERT_TRUE(mFilterTests.getNewlyOpenedFilterId(filterId));
@@ -289,9 +309,9 @@
         ASSERT_TRUE(mFilterTests.startFilter(*id));
     }
     // tune test
-    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf));
+    ASSERT_TRUE(mFrontendTests.tuneFrontend(frontendConf, true /*testWithDemux*/));
     ASSERT_TRUE(filterDataOutputTest(goldenOutputFiles));
-    ASSERT_TRUE(mFrontendTests.stopTuneFrontend());
+    ASSERT_TRUE(mFrontendTests.stopTuneFrontend(true /*testWithDemux*/));
     for (id = filterIds.begin(); id != filterIds.end(); id++) {
         ASSERT_TRUE(mFilterTests.stopFilter(*id));
     }
@@ -321,6 +341,17 @@
     mFrontendTests.scanTest(frontendScanArray[SCAN_DVBT], FrontendScanType::SCAN_BLIND);
 }
 
+TEST_P(TunerLnbHidlTest, OpenLnbByName) {
+    description("Open and configure an Lnb with name then send a diseqc msg to it.");
+    ASSERT_TRUE(mLnbTests.openLnbByName(lnbArray[LNB_EXTERNAL].name));
+    ASSERT_TRUE(mLnbTests.setLnbCallback());
+    ASSERT_TRUE(mLnbTests.setVoltage(lnbArray[LNB_EXTERNAL].voltage));
+    ASSERT_TRUE(mLnbTests.setTone(lnbArray[LNB_EXTERNAL].tone));
+    ASSERT_TRUE(mLnbTests.setSatellitePosition(lnbArray[LNB_EXTERNAL].position));
+    ASSERT_TRUE(mLnbTests.sendDiseqcMessage(diseqcMsgArray[DISEQC_POWER_ON]));
+    ASSERT_TRUE(mLnbTests.closeLnb());
+}
+
 TEST_P(TunerLnbHidlTest, SendDiseqcMessageToLnb) {
     description("Open and configure an Lnb with specific settings then send a diseqc msg to it.");
     vector<uint32_t> ids;
@@ -424,6 +455,12 @@
     ASSERT_TRUE(mDemuxTests.closeDemux());
 }
 
+TEST_P(TunerFilterHidlTest, testTimeFilter) {
+    description("Open a timer filter in Demux and set time stamp.");
+    // TODO use paramterized tests
+    testTimeFilter(timeFilterArray[TIMER0]);
+}
+
 TEST_P(TunerBroadcastHidlTest, BroadcastDataFlowVideoFilterTest) {
     description("Test Video Filter functionality in Broadcast use case.");
     broadcastSingleFilterTest(filterArray[TS_VIDEO1], frontendArray[DVBT]);
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
index d71222b..6804f3c 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TargetTest.h
@@ -16,7 +16,6 @@
 
 #include "DemuxTests.h"
 #include "DescramblerTests.h"
-#include "DvrTests.h"
 #include "FrontendTests.h"
 #include "LnbTests.h"
 
@@ -34,6 +33,7 @@
     initFrontendScanConfig();
     initLnbConfig();
     initFilterConfig();
+    initTimeFilterConfig();
     initDvrConfig();
     initDescramblerConfig();
 }
@@ -127,6 +127,7 @@
     }
 
     void configSingleFilterInDemuxTest(FilterConfig filterConf, FrontendConfig frontendConf);
+    void testTimeFilter(TimeFilterConfig filterConf);
 
     sp<ITuner> mService;
     FrontendTests mFrontendTests;
@@ -145,6 +146,7 @@
         mDemuxTests.setService(mService);
         mFilterTests.setService(mService);
         mLnbTests.setService(mService);
+        mDvrTests.setService(mService);
     }
 
   protected:
@@ -157,6 +159,7 @@
     DemuxTests mDemuxTests;
     FilterTests mFilterTests;
     LnbTests mLnbTests;
+    DvrTests mDvrTests;
 
     AssertionResult filterDataOutputTest(vector<string> goldenOutputFiles);
 
@@ -245,6 +248,7 @@
 
         mFrontendTests.setService(mService);
         mDemuxTests.setService(mService);
+        mDvrTests.setService(mService);
         mDescramblerTests.setService(mService);
         mDescramblerTests.setCasService(mCasService);
     }
@@ -264,5 +268,6 @@
     DemuxTests mDemuxTests;
     FilterTests mFilterTests;
     DescramblerTests mDescramblerTests;
+    DvrTests mDvrTests;
 };
 }  // namespace
diff --git a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
index d0f2b9c..6c68e35 100644
--- a/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
+++ b/tv/tuner/1.0/vts/functional/VtsHalTvTunerV1_0TestConfigurations.h
@@ -86,6 +86,11 @@
 } Filter;
 
 typedef enum {
+    TIMER0,
+    TIMER_MAX,
+} TimeFilter;
+
+typedef enum {
     SOURCE,
     SINK,
     LINKAGE_DIR,
@@ -99,6 +104,7 @@
 
 typedef enum {
     LNB0,
+    LNB_EXTERNAL,
     LNB_MAX,
 } Lnb;
 
@@ -115,6 +121,7 @@
 typedef enum {
     DVR_RECORD0,
     DVR_PLAYBACK0,
+    DVR_SOFTWARE_FE,
     DVR_MAX,
 } Dvr;
 
@@ -131,7 +138,13 @@
     bool operator<(const FilterConfig& /*c*/) const { return false; }
 };
 
+struct TimeFilterConfig {
+    bool supportTimeFilter;
+    uint64_t timeStamp;
+};
+
 struct FrontendConfig {
+    bool isSoftwareFe;
     FrontendType type;
     FrontendSettings settings;
     vector<FrontendStatusType> tuneStatusTypes;
@@ -140,6 +153,7 @@
 
 struct LnbConfig {
     bool usingLnb;
+    string name;
     LnbVoltage voltage;
     LnbTone tone;
     LnbPosition position;
@@ -172,6 +186,7 @@
 static vector<uint8_t> diseqcMsgArray[DISEQC_MAX];
 static ChannelConfig channelArray[FRONTEND_MAX];
 static FilterConfig filterArray[FILTER_MAX];
+static TimeFilterConfig timeFilterArray[TIMER_MAX];
 static DemuxFilterType filterLinkageTypes[LINKAGE_DIR][FILTER_MAIN_TYPE_BIT_COUNT];
 static DvrConfig dvrArray[DVR_MAX];
 static DescramblerConfig descramblerArray[DESC_MAX];
@@ -200,7 +215,9 @@
     statuses.push_back(status);
     frontendArray[DVBT].tuneStatusTypes = types;
     frontendArray[DVBT].expectTuneStatuses = statuses;
+    frontendArray[DVBT].isSoftwareFe = true;
     frontendArray[DVBS].type = FrontendType::DVBS;
+    frontendArray[DVBS].isSoftwareFe = true;
 };
 
 /** Configuration array for the frontend scan test */
@@ -226,6 +243,11 @@
     lnbArray[LNB0].voltage = LnbVoltage::VOLTAGE_12V;
     lnbArray[LNB0].tone = LnbTone::NONE;
     lnbArray[LNB0].position = LnbPosition::UNDEFINED;
+    lnbArray[LNB_EXTERNAL].usingLnb = true;
+    lnbArray[LNB_EXTERNAL].name = "default_lnb_external";
+    lnbArray[LNB_EXTERNAL].voltage = LnbVoltage::VOLTAGE_5V;
+    lnbArray[LNB_EXTERNAL].tone = LnbTone::NONE;
+    lnbArray[LNB_EXTERNAL].position = LnbPosition::UNDEFINED;
 };
 
 /** Diseqc messages array for the Lnb test */
@@ -311,6 +333,12 @@
     filterLinkageTypes[SINK][4] = filterLinkageTypes[SOURCE][4];
 };
 
+/** Configuration array for the timer filter test */
+inline void initTimeFilterConfig() {
+    timeFilterArray[TIMER0].supportTimeFilter = true;
+    timeFilterArray[TIMER0].timeStamp = 1;
+}
+
 /** Configuration array for the dvr test */
 inline void initDvrConfig() {
     RecordSettings recordSettings{
@@ -331,9 +359,20 @@
             .packetSize = 188,
     };
     dvrArray[DVR_PLAYBACK0].type = DvrType::PLAYBACK;
-    dvrArray[DVR_PLAYBACK0].playbackInputFile = "/vendor/etc/segment000000.ts";
+    dvrArray[DVR_PLAYBACK0].playbackInputFile = "/data/local/tmp/segment000000.ts";
     dvrArray[DVR_PLAYBACK0].bufferSize = FMQ_SIZE_4M;
     dvrArray[DVR_PLAYBACK0].settings.playback(playbackSettings);
+    PlaybackSettings softwareFePlaybackSettings{
+            .statusMask = 0xf,
+            .lowThreshold = 0x1000,
+            .highThreshold = 0x07fff,
+            .dataFormat = DataFormat::TS,
+            .packetSize = 188,
+    };
+    dvrArray[DVR_SOFTWARE_FE].type = DvrType::PLAYBACK;
+    dvrArray[DVR_SOFTWARE_FE].playbackInputFile = "/data/local/tmp/segment000000.ts";
+    dvrArray[DVR_SOFTWARE_FE].bufferSize = FMQ_SIZE_4M;
+    dvrArray[DVR_SOFTWARE_FE].settings.playback(softwareFePlaybackSettings);
 };
 
 /** Configuration array for the descrambler test */