Merge "[uwb-hal] Add antenna mode capability" into main
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
index e198293..9b89055 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.cpp
@@ -601,7 +601,6 @@
     const IBluetoothAudioProvider::LeAudioDeviceCapabilities& capabilities,
     uint8_t direction) {
   // Create a new LeAudioAseConfigurationSetting and return
-  // For other direction will contain all settings
   LeAudioAseConfigurationSetting filtered_setting{
       .audioContext = setting.audioContext,
       .sinkAseConfiguration = setting.sinkAseConfiguration,
@@ -651,17 +650,10 @@
     IBluetoothAudioProvider::LeAudioAseConfigurationSetting& setting,
     const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
         requirement) {
-  // Try to match context in metadata.
-  if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
-      requirement.audioContext.bitmask)
-    return std::nullopt;
-
-  // Further filter setting's context
-  setting.audioContext.bitmask &= requirement.audioContext.bitmask;
-
   // Create a new LeAudioAseConfigurationSetting to return
+  // Make context the same as the requirement
   LeAudioAseConfigurationSetting filtered_setting{
-      .audioContext = setting.audioContext,
+      .audioContext = requirement.audioContext,
       .packing = setting.packing,
       .flags = setting.flags,
   };
@@ -707,41 +699,39 @@
   return filtered_setting;
 }
 
-std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+std::optional<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
 LeAudioOffloadAudioProvider::matchWithRequirement(
     std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
         matched_ase_configuration_settings,
-    const std::vector<IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
-        in_requirements) {
-  // Each requirement will match with a valid setting
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
-  for (auto& requirement : in_requirements) {
-    LOG(INFO) << __func__ << ": Trying to match for the requirement "
-              << requirement.toString();
-    bool is_matched = false;
-
-    for (auto& setting : matched_ase_configuration_settings) {
-      auto filtered_ase_configuration_setting =
-          getRequirementMatchedAseConfigurationSettings(setting, requirement);
-      if (filtered_ase_configuration_setting.has_value()) {
-        result.push_back(filtered_ase_configuration_setting.value());
-        LOG(INFO) << __func__ << ": Result found: "
-                  << getSettingOutputString(
-                         filtered_ase_configuration_setting.value());
-        // Found a matched setting, ignore other settings
-        is_matched = true;
-        break;
-      }
+    const IBluetoothAudioProvider::LeAudioConfigurationRequirement& requirement,
+    bool isMatchContext) {
+  LOG(INFO) << __func__ << ": Trying to match for the requirement "
+            << requirement.toString() << ", match context = " << isMatchContext;
+  for (auto& setting : matched_ase_configuration_settings) {
+    // Try to match context in metadata.
+    if (isMatchContext) {
+      if ((setting.audioContext.bitmask & requirement.audioContext.bitmask) !=
+          requirement.audioContext.bitmask)
+        continue;
+      LOG(DEBUG) << __func__ << ": Setting with matched context: "
+                 << getSettingOutputString(setting);
     }
-    if (!is_matched) {
-      // If cannot satisfy this requirement, return an empty result
-      LOG(WARNING) << __func__ << ": Cannot match the requirement "
-                   << requirement.toString();
-      result.clear();
-      break;
+
+    auto filtered_ase_configuration_setting =
+        getRequirementMatchedAseConfigurationSettings(setting, requirement);
+    if (filtered_ase_configuration_setting.has_value()) {
+      LOG(INFO) << __func__ << ": Result found: "
+                << getSettingOutputString(
+                       filtered_ase_configuration_setting.value());
+      // Found a matched setting, ignore other settings
+      return filtered_ase_configuration_setting;
     }
   }
-  return result;
+  // If cannot satisfy this requirement, return nullopt
+  LOG(WARNING) << __func__ << ": Cannot match the requirement "
+               << requirement.toString()
+               << ", match context = " << isMatchContext;
+  return std::nullopt;
 }
 
 // For each requirement, a valid ASE configuration will satify:
@@ -769,20 +759,11 @@
     return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
   }
 
-  // Split out preferred and non-preferred settings based on context
-  // An example: preferred = MEDIA, available: MEDIA | CONVERSATION
-  // -> preferred list will have settings with MEDIA context
-  // -> non-preferred list will have settings with any context
-  // We want to match requirement with preferred context settings first
+  // Matched ASE configuration with ignored audio context
   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
       sink_matched_ase_configuration_settings;
   std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
       matched_ase_configuration_settings;
-  // Matched ASE configuration with non-preferred audio context
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
-      sink_non_prefer_matched_ase_configuration_settings;
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
-      non_prefer_matched_ase_configuration_settings;
 
   // A setting must match both source and sink.
   // First filter all setting matched with sink capability
@@ -790,32 +771,20 @@
     for (auto& setting : ase_configuration_settings)
       for (auto& capability : in_remoteSinkAudioCapabilities.value()) {
         if (!capability.has_value()) continue;
-        // LOG(DEBUG) << __func__ << ": " << capability.value().toString();
         auto filtered_ase_configuration_setting =
             getCapabilitiesMatchedAseConfigurationSettings(
                 setting, capability.value(), kLeAudioDirectionSink);
         if (filtered_ase_configuration_setting.has_value()) {
-          // Push to non-prefer first for the broadest matching possible
-          sink_non_prefer_matched_ase_configuration_settings.push_back(
+          sink_matched_ase_configuration_settings.push_back(
               filtered_ase_configuration_setting.value());
-          // Try to filter out prefer context to another vector.
-          if (filterCapabilitiesMatchedContext(
-                  filtered_ase_configuration_setting.value().audioContext,
-                  capability.value())) {
-            sink_matched_ase_configuration_settings.push_back(
-                filtered_ase_configuration_setting.value());
-          }
         }
       }
   } else {
     sink_matched_ase_configuration_settings = ase_configuration_settings;
-    sink_non_prefer_matched_ase_configuration_settings =
-        ase_configuration_settings;
   }
 
   // Combine filter every source capability
   if (in_remoteSourceAudioCapabilities.has_value()) {
-    // Prefer context
     for (auto& setting : sink_matched_ase_configuration_settings)
       for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
         if (!capability.has_value()) continue;
@@ -823,62 +792,47 @@
             getCapabilitiesMatchedAseConfigurationSettings(
                 setting, capability.value(), kLeAudioDirectionSource);
         if (filtered_ase_configuration_setting.has_value()) {
-          // Try to filter out prefer context to another vector.
-          if (filterCapabilitiesMatchedContext(
-                  filtered_ase_configuration_setting.value().audioContext,
-                  capability.value())) {
-            matched_ase_configuration_settings.push_back(
-                filtered_ase_configuration_setting.value());
-          }
-        }
-      }
-
-    // Non prefer context
-    for (auto& setting : sink_non_prefer_matched_ase_configuration_settings)
-      for (auto& capability : in_remoteSourceAudioCapabilities.value()) {
-        if (!capability.has_value()) continue;
-        auto filtered_ase_configuration_setting =
-            getCapabilitiesMatchedAseConfigurationSettings(
-                setting, capability.value(), kLeAudioDirectionSource);
-        if (filtered_ase_configuration_setting.has_value()) {
-          // Push to non-prefer first for the broadest matching possible
-          non_prefer_matched_ase_configuration_settings.push_back(
+          matched_ase_configuration_settings.push_back(
               filtered_ase_configuration_setting.value());
         }
       }
   } else {
     matched_ase_configuration_settings =
         sink_matched_ase_configuration_settings;
-    non_prefer_matched_ase_configuration_settings =
-        sink_non_prefer_matched_ase_configuration_settings;
   }
 
-  // Matching priority list:
-  // Preferred context - exact match with allocation
-  // Any context - exact match with allocation
-
-  LOG(DEBUG) << __func__ << ": Called with requirement: ";
+  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting> result;
   for (auto& requirement : in_requirements) {
-    LOG(DEBUG) << __func__ << " requirement: " << requirement.toString();
+    // For each requirement, try to match with a setting.
+    // If we cannot match, return an empty result.
+
+    // Matching priority list:
+    // Preferred context - exact match with allocation
+    // Any context - exact match with allocation
+
+    auto matched_setting_with_context = matchWithRequirement(
+        matched_ase_configuration_settings, requirement, true);
+    if (matched_setting_with_context.has_value()) {
+      result.push_back(matched_setting_with_context.value());
+    } else {
+      auto matched_setting = matchWithRequirement(
+          matched_ase_configuration_settings, requirement, false);
+      if (matched_setting.has_value()) {
+        result.push_back(matched_setting_with_context.value());
+      } else {
+        // Cannot find a match for this requirement
+        // Immediately return
+        LOG(ERROR)
+            << __func__
+            << ": Cannot find any match for this requirement, exitting...";
+        result.clear();
+        *_aidl_return = result;
+        return ndk::ScopedAStatus::ok();
+      }
+    }
   }
 
-  LOG(DEBUG) << __func__ << ": List of settings with the same context:";
-  for (auto& setting : matched_ase_configuration_settings) {
-    LOG(DEBUG) << __func__ << ": " << getSettingOutputString(setting);
-  }
-
-  auto result =
-      matchWithRequirement(matched_ase_configuration_settings, in_requirements);
-  if (result.empty()) {
-    LOG(WARNING) << __func__
-                 << ": Cannot match with preferred context settings";
-    result = matchWithRequirement(non_prefer_matched_ase_configuration_settings,
-                                  in_requirements);
-  }
-  if (result.empty()) {
-    LOG(ERROR) << __func__
-               << ": Cannot match with non-preferred context settings";
-  }
+  LOG(INFO) << __func__ << ": Found matches for all requirements!";
   *_aidl_return = result;
   return ndk::ScopedAStatus::ok();
 };
diff --git a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
index 38af1ff..798f183 100644
--- a/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
+++ b/bluetooth/audio/aidl/default/LeAudioOffloadAudioProvider.h
@@ -167,13 +167,13 @@
       AudioContext requirement_context,
       IBluetoothAudioProvider::BroadcastQuality quality,
       LeAudioBroadcastSubgroupConfiguration configuration);
-  std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
+  std::optional<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>
   matchWithRequirement(
       std::vector<IBluetoothAudioProvider::LeAudioAseConfigurationSetting>&
           matched_ase_configuration_settings,
-      const std::vector<
-          IBluetoothAudioProvider::LeAudioConfigurationRequirement>&
-          in_requirements);
+      const IBluetoothAudioProvider::LeAudioConfigurationRequirement&
+          requirements,
+      bool isMatchContext);
 };
 
 class LeAudioOffloadOutputAudioProvider : public LeAudioOffloadAudioProvider {
diff --git a/camera/device/aidl/android/hardware/camera/device/ShutterMsg.aidl b/camera/device/aidl/android/hardware/camera/device/ShutterMsg.aidl
index 24ae1a0..f5489d4 100644
--- a/camera/device/aidl/android/hardware/camera/device/ShutterMsg.aidl
+++ b/camera/device/aidl/android/hardware/camera/device/ShutterMsg.aidl
@@ -40,6 +40,9 @@
      * as timestamp, and for a rolling shutter sensor, the value must be
      * timestamp + exposureTime + t_crop_top where t_crop_top is the exposure time
      * skew of the cropped lines on the top.
+     *
+     * If ANDROID_SENSOR_READOUT_TIMESTAMP is set to NOT_SUPPORTED, this field
+     * will be ignored by the camera framework.
      */
     long readoutTimestamp;
 }
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index 1673ab0..c38c2f4 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -456,6 +456,22 @@
     return ret;
 }
 
+bool CameraAidlTest::isReadoutTimestampSupported(const camera_metadata_t* staticMeta) {
+    camera_metadata_ro_entry readoutTimestampEntry;
+    int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_SENSOR_READOUT_TIMESTAMP,
+                                           &readoutTimestampEntry);
+    if (rc != 0) {
+        ALOGI("%s: Failed to find ANDROID_SENSOR_READOUT_TIMESTAMP", __FUNCTION__);
+        return true;
+    }
+    if (readoutTimestampEntry.count == 1 && !readoutTimestampEntry.data.u8[0]) {
+        ALOGI("%s: readout timestamp not supported", __FUNCTION__);
+        return false;
+    }
+    ALOGI("%s: readout timestamp supported", __FUNCTION__);
+    return true;
+}
+
 void CameraAidlTest::verifyLogicalCameraResult(const camera_metadata_t* staticMetadata,
                                                const std::vector<uint8_t>& resultMetadata) {
     camera_metadata_t* metadata = (camera_metadata_t*)resultMetadata.data();
@@ -2380,13 +2396,13 @@
             ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
             ASSERT_EQ(testStream.id, inflightReq->resultOutputBuffers[0].buffer.streamId);
 
-            // shutterReadoutTimestamp must be available, and it must
+            // shutterReadoutTimestamp, if supported, must
             // be >= shutterTimestamp + exposureTime,
             // and < shutterTimestamp + exposureTime + rollingShutterSkew / 2.
-            ASSERT_TRUE(inflightReq->shutterReadoutTimestampValid);
             ASSERT_FALSE(inflightReq->collectedResult.isEmpty());
 
-            if (inflightReq->collectedResult.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
+            if (mSupportReadoutTimestamp &&
+                inflightReq->collectedResult.exists(ANDROID_SENSOR_EXPOSURE_TIME)) {
                 camera_metadata_entry_t exposureTimeResult =
                         inflightReq->collectedResult.find(ANDROID_SENSOR_EXPOSURE_TIME);
                 nsecs_t exposureToReadout =
@@ -2901,13 +2917,14 @@
             ASSERT_FALSE(inflightReq->errorCodeValid);
             ASSERT_NE(inflightReq->resultOutputBuffers.size(), 0u);
             ASSERT_EQ(testStream.id, inflightReq->resultOutputBuffers[0].buffer.streamId);
-            ASSERT_TRUE(inflightReq->shutterReadoutTimestampValid);
-            nsecs_t readoutTimestamp = inflightReq->shutterReadoutTimestamp;
+            nsecs_t captureTimestamp = mSupportReadoutTimestamp
+                                               ? inflightReq->shutterReadoutTimestamp
+                                               : inflightReq->shutterTimestamp;
 
             if (previewStabilizationOn) {
                 // Here we collect the time difference between the buffer ready
-                // timestamp - notify readout timestamp.
-                // timeLag = buffer ready timestamp - notify readout timestamp.
+                // timestamp - notify timestamp.
+                // timeLag = buffer ready timestamp - notify timestamp.
                 // timeLag(previewStabilization) must be <=
                 //        timeLag(stabilization off) + 1 frame duration.
                 auto it = cameraDeviceToTimeLag.find(name);
@@ -2918,12 +2935,12 @@
                 ASSERT_TRUE(it != cameraDeviceToTimeLag.end());
 
                 nsecs_t previewStabOnLagTime =
-                        inflightReq->resultOutputBuffers[0].timeStamp - readoutTimestamp;
+                        inflightReq->resultOutputBuffers[0].timeStamp - captureTimestamp;
                 ASSERT_TRUE(previewStabOnLagTime <= (it->second + frameDuration));
             } else {
                 // Fill in the buffer ready timestamp - notify timestamp;
                 cameraDeviceToTimeLag[std::string(name)] =
-                        inflightReq->resultOutputBuffers[0].timeStamp - readoutTimestamp;
+                        inflightReq->resultOutputBuffers[0].timeStamp - captureTimestamp;
             }
         }
 
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index 782794b..9edbf41 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -346,6 +346,8 @@
 
     static Status isOfflineSessionSupported(const camera_metadata_t* staticMeta);
 
+    static bool isReadoutTimestampSupported(const camera_metadata_t* staticMeta);
+
     static Status getPhysicalCameraIds(const camera_metadata_t* staticMeta,
                                        std::unordered_set<std::string>* physicalIds /*out*/);
 
@@ -456,8 +458,6 @@
     struct InFlightRequest {
         // Set by notify() SHUTTER call.
         nsecs_t shutterTimestamp;
-
-        bool shutterReadoutTimestampValid;
         nsecs_t shutterReadoutTimestamp;
 
         bool errorCodeValid;
@@ -523,7 +523,6 @@
 
         InFlightRequest()
             : shutterTimestamp(0),
-              shutterReadoutTimestampValid(false),
               shutterReadoutTimestamp(0),
               errorCodeValid(false),
               errorCode(ErrorCode::ERROR_BUFFER),
@@ -541,7 +540,6 @@
         InFlightRequest(ssize_t numBuffers, bool hasInput, bool partialResults,
                         int32_t partialCount, std::shared_ptr<ResultMetadataQueue> queue = nullptr)
             : shutterTimestamp(0),
-              shutterReadoutTimestampValid(false),
               shutterReadoutTimestamp(0),
               errorCodeValid(false),
               errorCode(ErrorCode::ERROR_BUFFER),
@@ -561,7 +559,6 @@
                         const std::unordered_set<std::string>& extraPhysicalResult,
                         std::shared_ptr<ResultMetadataQueue> queue = nullptr)
             : shutterTimestamp(0),
-              shutterReadoutTimestampValid(false),
               shutterReadoutTimestamp(0),
               errorCodeValid(false),
               errorCode(ErrorCode::ERROR_BUFFER),
@@ -631,6 +628,8 @@
 
     HandleImporter mHandleImporter;
 
+    bool mSupportReadoutTimestamp;
+
     friend class DeviceCb;
     friend class SimpleDeviceCb;
     friend class TorchProviderCb;
diff --git a/camera/provider/aidl/vts/device_cb.cpp b/camera/provider/aidl/vts/device_cb.cpp
index 8a8b925..bfd1cd1 100644
--- a/camera/provider/aidl/vts/device_cb.cpp
+++ b/camera/provider/aidl/vts/device_cb.cpp
@@ -32,10 +32,11 @@
 
 DeviceCb::DeviceCb(CameraAidlTest* parent, camera_metadata_t* staticMeta) : mParent(parent) {
     mStaticMetadata = staticMeta;
+    parent->mSupportReadoutTimestamp = CameraAidlTest::isReadoutTimestampSupported(staticMeta);
 }
 
 ScopedAStatus DeviceCb::notify(const std::vector<NotifyMsg>& msgs) {
-    std::vector<std::pair<bool, nsecs_t>> readoutTimestamps;
+    std::vector<nsecs_t> readoutTimestamps;
 
     size_t count = msgs.size();
     readoutTimestamps.resize(count);
@@ -44,11 +45,11 @@
         const NotifyMsg& msg = msgs[i];
         switch (msg.getTag()) {
             case NotifyMsg::Tag::error:
-                readoutTimestamps[i] = {false, 0};
+                readoutTimestamps[i] = 0;
                 break;
             case NotifyMsg::Tag::shutter:
                 const auto& shutter = msg.get<NotifyMsg::Tag::shutter>();
-                readoutTimestamps[i] = {true, shutter.readoutTimestamp};
+                readoutTimestamps[i] = shutter.readoutTimestamp;
                 break;
         }
     }
@@ -446,9 +447,8 @@
     return notify;
 }
 
-ScopedAStatus DeviceCb::notifyHelper(
-        const std::vector<NotifyMsg>& msgs,
-        const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps) {
+ScopedAStatus DeviceCb::notifyHelper(const std::vector<NotifyMsg>& msgs,
+                                     const std::vector<nsecs_t>& readoutTimestamps) {
     std::lock_guard<std::mutex> l(mParent->mLock);
 
     for (size_t i = 0; i < msgs.size(); i++) {
@@ -514,8 +514,7 @@
                 }
                 auto& r = itr->second;
                 r->shutterTimestamp = msg.get<NotifyMsg::Tag::shutter>().timestamp;
-                r->shutterReadoutTimestampValid = readoutTimestamps[i].first;
-                r->shutterReadoutTimestamp = readoutTimestamps[i].second;
+                r->shutterReadoutTimestamp = readoutTimestamps[i];
                 break;
         }
     }
diff --git a/camera/provider/aidl/vts/device_cb.h b/camera/provider/aidl/vts/device_cb.h
index 3ae7d10..d839ab4 100644
--- a/camera/provider/aidl/vts/device_cb.h
+++ b/camera/provider/aidl/vts/device_cb.h
@@ -60,7 +60,7 @@
     bool processCaptureResultLocked(const CaptureResult& results,
                                     std::vector<PhysicalCameraMetadata> physicalCameraMetadata);
     ScopedAStatus notifyHelper(const std::vector<NotifyMsg>& msgs,
-                               const std::vector<std::pair<bool, nsecs_t>>& readoutTimestamps);
+                               const std::vector<nsecs_t>& readoutTimestamps);
 
     CameraAidlTest* mParent;  // Parent object
 
diff --git a/compatibility_matrices/bump.py b/compatibility_matrices/bump.py
index a5a453b..35633c1 100755
--- a/compatibility_matrices/bump.py
+++ b/compatibility_matrices/bump.py
@@ -21,7 +21,7 @@
 import argparse
 import os
 import pathlib
-import shutil
+import re
 import subprocess
 import textwrap
 
@@ -44,6 +44,7 @@
 
         self.current_level = cmdline_args.current_level
         self.current_letter = cmdline_args.current_letter
+        self.current_version = cmdline_args.platform_version
         self.current_module_name = f"framework_compatibility_matrix.{self.current_level}.xml"
         self.current_xml = self.interfaces_dir / f"compatibility_matrices/compatibility_matrix.{self.current_level}.xml"
         self.device_module_name = "framework_compatibility_matrix.device.xml"
@@ -58,12 +59,13 @@
         self.copy_matrix()
         self.edit_android_bp()
         self.edit_android_mk()
+        self.bump_libvintf()
 
     def bump_kernel_configs(self):
         check_call([
             self.top / "kernel/configs/tools/bump.py",
-            self.current_letter,
-            self.next_letter,
+            self.current_letter.lower(),
+            self.next_letter.lower(),
         ])
 
     def copy_matrix(self):
@@ -87,7 +89,7 @@
         next_kernel_configs = check_output(
             """grep -rh name: | sed -E 's/^.*"(.*)".*/\\1/g'""",
             cwd=self.top / "kernel/configs" /
-            self.next_letter,
+            self.next_letter.lower(),
             text=True,
             shell=True,
         ).splitlines()
@@ -128,21 +130,69 @@
         with open(android_mk, "w") as f:
             f.write("".join(lines))
 
+    def bump_libvintf(self):
+        if not self.current_version:
+            print("Skip libvintf update...")
+            return
+        try:
+            check_call(["grep", "-h",
+                        f"{self.current_letter.upper()} = {self.current_level}",
+                        "system/libvintf/include/vintf/Level.h"])
+        except subprocess.CalledProcessError:
+            print("Adding new API level to libvintf")
+            add_lines_above("system/libvintf/analyze_matrix/analyze_matrix.cpp",
+                            "        case Level::UNSPECIFIED:",
+                            textwrap.indent(textwrap.dedent(f"""\
+                                    case Level::{self.current_letter.upper()}:
+                                        return "Android {self.current_version} ({self.current_letter.upper()})";"""),
+                            "    "*2))
+            add_lines_above("system/libvintf/include/vintf/Level.h",
+                            "    // To add new values:",
+                            f"    {self.current_letter.upper()} = {self.current_level},")
+            add_lines_above("system/libvintf/include/vintf/Level.h",
+                            "        Level::UNSPECIFIED,",
+                            f"        Level::{self.current_letter.upper()},")
+            add_lines_above("system/libvintf/RuntimeInfo.cpp",
+                            "            // Add more levels above this line.",
+                            textwrap.indent(textwrap.dedent(f"""\
+                                        case {self.current_version}: {{
+                                            ret = Level::{self.current_letter.upper()};
+                                        }} break;"""),
+                            "    "*3))
+
+
+def add_lines_above(file, pattern, lines):
+    with open(file, 'r+') as f:
+        text = f.read()
+        split_text = re.split(rf"\n{pattern}\n", text)
+        if len(split_text) != 2:
+            # Only one pattern must be found, otherwise the source must be
+            # changed unexpectedly.
+            raise Exception(
+                f'Pattern "{pattern}" not found or multiple patterns found in {file}')
+        f.seek(0)
+        f.write(f"\n{lines}\n{pattern}\n".join(split_text))
+        f.truncate()
+
 
 def main():
     parser = argparse.ArgumentParser(description=__doc__)
     parser.add_argument("current_level",
                         type=str,
-                        help="VINTF level of the current version (e.g. 9)")
+                        help="VINTF level of the current version (e.g. 202404)")
     parser.add_argument("next_level",
                         type=str,
-                        help="VINTF level of the next version (e.g. 10)")
+                        help="VINTF level of the next version (e.g. 202504)")
     parser.add_argument("current_letter",
                         type=str,
                         help="Letter of the API level of the current version (e.g. v)")
     parser.add_argument("next_letter",
                         type=str,
                         help="Letter of the API level of the next version (e.g. w)")
+    parser.add_argument("platform_version",
+                        type=str,
+                        nargs="?",
+                        help="Android release version number number (e.g. 15)")
     cmdline_args = parser.parse_args()
 
     Bump(cmdline_args).run()
diff --git a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
index 7e095f1..41a78eb 100644
--- a/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
+++ b/tv/input/aidl/vts/functional/VtsHalTvInputTargetTest.cpp
@@ -137,13 +137,15 @@
 }
 
 bool TvInputAidlTest::isValidHandle(NativeHandle& handle) {
-    if (handle.fds.empty()) {
+    if (handle.fds.empty() && handle.ints.empty()) {
         return false;
     }
-    for (size_t i = 0; i < handle.fds.size(); i++) {
-        int fd = handle.fds[i].get();
-        if (fcntl(fd, F_GETFL) < 0) {
-            return false;
+    if (!(handle.fds.empty())) {
+        for (size_t i = 0; i < handle.fds.size(); i++) {
+            int fd = handle.fds[i].get();
+            if (fcntl(fd, F_GETFL) < 0) {
+                return false;
+            }
         }
     }
     return true;
diff --git a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
index 6cabb3d..be9b996 100644
--- a/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
+++ b/tv/tuner/aidl/vts/functional/VtsHalTvTunerTargetTest.h
@@ -32,9 +32,10 @@
 bool initConfiguration() {
     std::array<char, PROPERTY_VALUE_MAX> variant;
     property_get("ro.vendor.vts_tuner_configuration_variant", variant.data(), "");
+    string variantString = variant.data();
     string configFilePath = "/vendor/etc/tuner_vts_config_aidl_V1";
-    if (variant.size() != 0) {
-        configFilePath = configFilePath + "."  + variant.data();
+    if (variantString.length() != 0) {
+        configFilePath = configFilePath + "." + variantString;
     }
     configFilePath = configFilePath + ".xml";
     TunerTestingConfigAidlReader1_0::setConfigFilePath(configFilePath);