cheets_CTS/GTS: Add filter tags for first_api_level.

To flag tests or modules that can be ignored only
on devices launched with a particular Android version.

BUG=b:158951171
TEST=cheets_CTS_R.11_r3.x86.CtsUsb still works

Change-Id: I0d01e2232b2e62caf719baa6a4174e27b6d9b83e
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/autotest/+/2595566
Tested-by: Kazuhiro Inaba <kinaba@chromium.org>
Auto-Submit: Kazuhiro Inaba <kinaba@chromium.org>
Commit-Queue: Jiyoun Ha <jiyounha@chromium.org>
Reviewed-by: Jiyoun Ha <jiyounha@chromium.org>
diff --git a/server/cros/tradefed/cts_expected_failure_parser.py b/server/cros/tradefed/cts_expected_failure_parser.py
index 7fe27e1..7ed2112 100644
--- a/server/cros/tradefed/cts_expected_failure_parser.py
+++ b/server/cros/tradefed/cts_expected_failure_parser.py
@@ -11,23 +11,35 @@
     def __init__(self, failure_files):
         self.waivers_yaml = self._load_failures(failure_files)
 
-    def _validate_waiver_config(self, arch, board, bundle_abi, sdk_ver, config):
+    def _validate_waiver_config(self, arch, board, bundle_abi, sdk_ver,
+                                first_api_level, config):
         """Validate if the test environment matches the test config.
 
         @param arch: DUT's arch type.
         @param board: DUT's board name.
         @param bundle_abi: The test's abi type.
         @param sdk_ver: DUT's Android SDK version
+        @param first_api_level: DUT's Android first API level.
         @param config: config for an expected failing test.
         @return True if test arch or board is part of the config, else False.
         """
+        # Map only the versions that ARC releases care.
+        sdk_ver_map = {25: 'N', 28: 'P', 30: 'R'}
+
+        # 'all' applies to all devices.
+        # 'x86' or 'arm' applies to the DUT's architecture.
+        # board name like 'eve' or 'kevin' applies to the DUT running the board.
         dut_config = ['all', arch, board]
+        # 'nativebridge' applies to the case running ARM CTS on x86 devices.
         if bundle_abi and bundle_abi != arch:
             dut_config.append('nativebridge')
-        # Map only the versions that ARC releases care.
-        sdk_ver_map = {25: 'N', 28: 'P'}
+        # 'N' or 'P' or 'R' applies to the device running that Android version.
         if sdk_ver in sdk_ver_map:
-           dut_config.append(sdk_ver_map[sdk_ver])
+            dut_config.append(sdk_ver_map[sdk_ver])
+        # 'shipatN' or 'shipatP' or 'shipatR' applies to those originally
+        # launched at that Android version.
+        if first_api_level in sdk_ver_map:
+            dut_config.append('shipat' + sdk_ver_map[first_api_level])
         return len(set(dut_config).intersection(config)) > 0
 
     def _load_failures(self, failure_files):
@@ -51,19 +63,20 @@
                          failure_file)
         return waivers_yaml
 
-    def find_waivers(self, arch, board, bundle_abi, sdk_ver):
+    def find_waivers(self, arch, board, bundle_abi, sdk_ver, first_api_level):
         """Finds waivers for the test board.
 
         @param arch: DUT's arch type.
         @param board: DUT's board name.
         @param bundle_abi: The test's abi type.
-        @param sdk_ver: DUT's Android SDK version
+        @param sdk_ver: DUT's Android SDK version.
+        @param first_api_level: DUT's Android first API level.
         @return a set of waivers/no-test-modules applied to the test board.
         """
         applied_waiver_list = set()
         for test, config in self.waivers_yaml.iteritems():
             if self._validate_waiver_config(arch, board, bundle_abi, sdk_ver,
-                                            config):
+                                            first_api_level, config):
                 applied_waiver_list.add(test)
         logging.info('Excluding tests/packages from rerun: %s.',
                      applied_waiver_list)
diff --git a/server/cros/tradefed/tradefed_test.py b/server/cros/tradefed/tradefed_test.py
index f7e45b1..e47d860 100644
--- a/server/cros/tradefed/tradefed_test.py
+++ b/server/cros/tradefed/tradefed_test.py
@@ -66,6 +66,7 @@
     _board_name = None
     _release_branch_number = None  # The 'y' of OS version Rxx-xxxxx.y.z
     _android_version = None
+    _first_api_level = None
     _num_media_bundles = 0
     _abilist = []
 
@@ -809,13 +810,15 @@
         test_board = self._get_board_name()
         test_arch = self._get_board_arch()
         sdk_ver = self._get_android_version()
+        first_api_level = self._get_first_api_level()
         expected_fail_dir = os.path.join(self.bindir, directory)
         if os.path.exists(expected_fail_dir):
             expected_fail_files += glob.glob(expected_fail_dir + '/*.yaml')
 
         waivers = cts_expected_failure_parser.ParseKnownCTSFailures(
             expected_fail_files)
-        return waivers.find_waivers(test_arch, test_board, bundle_abi, sdk_ver)
+        return waivers.find_waivers(test_arch, test_board, bundle_abi, sdk_ver,
+                                    first_api_level)
 
     def _get_abilist(self):
         """Return the abilist supported by calling adb command.
@@ -866,6 +869,12 @@
                 ignore_status=True).stdout.rstrip().split('=')[1]
         return int(self._android_version)
 
+    def _get_first_api_level(self):
+        """Return target DUT Android first API level."""
+        if not self._first_api_level:
+            self._first_api_level = self._hosts[0].get_arc_first_api_level()
+        return int(self._first_api_level)
+
     def _get_max_retry(self, max_retry):
         """Return the maximum number of retries.