Check APF version, VSR API level, and Android version

This commit introduces checks for APF version, VSR API level,
and Android version to decide whether an APFv4 test should be
run, skipped, or fail:
* If Android version is less than V, skip the test
* If VSR API level is greater than or equal to 14 and APF
  version is less than 4, fail the test
* Otherwise, if APF version is less than 4, skip the test

Test: m connectivity_multi_devices_snippet && \
      atest CtsConnectivityMultiDevicesTestCases:ConnectivityMultiDevicesTest
Fix: 352132428
Change-Id: I023164fb59ad40f489abea2e0c45761efc39699b
diff --git a/staticlibs/testutils/host/python/apf_test_base.py b/staticlibs/testutils/host/python/apf_test_base.py
index 7203265..9a30978 100644
--- a/staticlibs/testutils/host/python/apf_test_base.py
+++ b/staticlibs/testutils/host/python/apf_test_base.py
@@ -23,6 +23,11 @@
     super().setup_class()
 
     # Check test preconditions.
+    asserts.abort_class_if(
+        not self.client.isAtLeastV(),
+        "Do not enforce the test until V+ since chipset potential bugs are"
+        " expected to be fixed on V+ releases.",
+    )
     tether_utils.assume_hotspot_test_preconditions(
         self.serverDevice, self.clientDevice, UpstreamType.NONE
     )
@@ -34,13 +39,12 @@
     )
 
     # Fetch device properties and storing them locally for later use.
-    client = self.clientDevice.connectivity_multi_devices_snippet
     self.server_iface_name, client_network = (
         tether_utils.setup_hotspot_and_client_for_upstream_type(
             self.serverDevice, self.clientDevice, UpstreamType.NONE
         )
     )
-    self.client_iface_name = client.getInterfaceNameFromNetworkHandle(
+    self.client_iface_name = self.client.getInterfaceNameFromNetworkHandle(
         client_network
     )
     self.server_mac_address = apf_utils.get_hardware_address(
diff --git a/staticlibs/testutils/host/python/apf_utils.py b/staticlibs/testutils/host/python/apf_utils.py
index a3ec6e9..c3330d2 100644
--- a/staticlibs/testutils/host/python/apf_utils.py
+++ b/staticlibs/testutils/host/python/apf_utils.py
@@ -236,7 +236,7 @@
     ad: android_device.AndroidDevice, iface_name: str, expected_version: int
 ) -> None:
   caps = get_apf_capabilities(ad, iface_name)
-  asserts.skip_if(
+  asserts.abort_class_if(
       caps.apf_version_supported < expected_version,
       f"Supported apf version {caps.apf_version_supported} < expected version"
       f" {expected_version}",
diff --git a/staticlibs/testutils/host/python/multi_devices_test_base.py b/staticlibs/testutils/host/python/multi_devices_test_base.py
index f8a92f3..677329a 100644
--- a/staticlibs/testutils/host/python/multi_devices_test_base.py
+++ b/staticlibs/testutils/host/python/multi_devices_test_base.py
@@ -52,3 +52,4 @@
         max_workers=2,
         raise_on_exception=True,
     )
+    self.client = self.clientDevice.connectivity_multi_devices_snippet
diff --git a/tests/cts/multidevices/apfv4_test.py b/tests/cts/multidevices/apfv4_test.py
index 6460dcf..7795be5 100644
--- a/tests/cts/multidevices/apfv4_test.py
+++ b/tests/cts/multidevices/apfv4_test.py
@@ -13,7 +13,8 @@
 #  limitations under the License.
 
 from absl.testing import parameterized
-from net_tests_utils.host.python import apf_test_base
+from mobly import asserts
+from net_tests_utils.host.python import apf_test_base, apf_utils
 
 # Constants.
 COUNTER_DROPPED_ETHERTYPE_NOT_ALLOWED = "DROPPED_ETHERTYPE_NOT_ALLOWED"
@@ -21,6 +22,23 @@
 
 
 class ApfV4Test(apf_test_base.ApfTestBase, parameterized.TestCase):
+  def setup_class(self):
+    super().setup_class()
+    # Check apf version preconditions.
+    caps = apf_utils.get_apf_capabilities(
+        self.clientDevice, self.client_iface_name
+    )
+    if self.client.getVsrApiLevel() >= 34:
+      # Enforce APFv4 support for Android 14+ VSR.
+      asserts.assert_true(
+          caps.apf_version_supported >= 4,
+          "APFv4 became mandatory in Android 14 VSR.",
+      )
+    else:
+      # Skip tests for APF version < 4 before Android 14 VSR.
+      apf_utils.assume_apf_version_support_at_least(
+          self.clientDevice, self.client_iface_name, 4
+      )
 
   # APF L2 packet filtering on V+ Android allows only specific
   # types: IPv4, ARP, IPv6, EAPOL, WAPI.
diff --git a/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt b/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt
index 7368669..49688cc 100644
--- a/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt
+++ b/tests/cts/multidevices/snippet/ConnectivityMultiDevicesSnippet.kt
@@ -36,6 +36,7 @@
 import android.net.wifi.WifiNetworkSpecifier
 import android.net.wifi.WifiSsid
 import androidx.test.platform.app.InstrumentationRegistry
+import com.android.compatibility.common.util.PropertyUtil
 import com.android.modules.utils.build.SdkLevel
 import com.android.testutils.AutoReleaseNetworkCallbackRule
 import com.android.testutils.ConnectUtil
@@ -75,6 +76,12 @@
     @Rpc(description = "Check whether the device SDK is as least T")
     fun isAtLeastT() = SdkLevel.isAtLeastT()
 
+    @Rpc(description = "Return whether the Sdk level is at least V.")
+    fun isAtLeastV() = SdkLevel.isAtLeastV()
+
+    @Rpc(description = "Return the API level that the VSR requirement must be fulfilled.")
+    fun getVsrApiLevel() = PropertyUtil.getVsrApiLevel()
+
     @Rpc(description = "Request cellular connection and ensure it is the default network.")
     fun requestCellularAndEnsureDefault() {
         ctsNetUtils.disableWifi()