Fix the race condition of the static ITestDevice

Commit I9f79065d95c54bb5f7471ecbdb098b2a2e75537 made the reference
of sDevice static, which introduces the race condition when multiple
instances of the testing class is created for sharding the tests
across multiple devices.

A typical error is that TradeFed finds that the device is
unavailable after sDevice.rebootIntoFastbootd(), because the
sDevice might be pointed to another device during sharding.

Fixing this by using getDevice() from TestInformation each time
without storing the ITestDevice.

Also using ConcurrentHashMap for static references to make them
thread-safe. e.g., sDeviceIsGKI10, sDeviceCodeName.

Bug: 214331533
Bug: 215040011
Test: vts-tradefed run commandAndExit vts --module FastbootVerifyUserspaceTest --shard-count=2
Test: vts-tradefed run commandAndExit vts --module FastbootGetvarUserspaceTest --shard-count=2
Change-Id: Id7cc72ed806dd36061638602b6d23775b5bc688c
Merged-In: Id7cc72ed806dd36061638602b6d23775b5bc688c
(cherry picked from commit e84edd6fbb36efbcc0a72309551f5f9d2ea1f423)
diff --git a/testcases/host/fastboot_getvar/src/com/android/tests/FastbootGetvarUserspaceTest.java b/testcases/host/fastboot_getvar/src/com/android/tests/FastbootGetvarUserspaceTest.java
index d693770..1c4b709 100644
--- a/testcases/host/fastboot_getvar/src/com/android/tests/FastbootGetvarUserspaceTest.java
+++ b/testcases/host/fastboot_getvar/src/com/android/tests/FastbootGetvarUserspaceTest.java
@@ -34,6 +34,7 @@
 import java.text.SimpleDateFormat;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.junit.Assert;
@@ -48,21 +49,26 @@
     private static final int PLATFORM_API_LEVEL_R = 30;
     private static final int ANDROID_RELEASE_VERSION_R = 11;
 
-    private static ITestDevice sDevice;
-    private static String sCodeName;
     private static String executeShellKernelARM64 =
             "cat /proc/config.gz | gzip -d | grep CONFIG_ARM64=y";
-    private static boolean isGKI10;
+
+    // IMPORTANT: Multiple instances of this class will be created while sharding
+    // the tests across multiple devices. So it needs to use ConcurrentHashMap to
+    // make these static variables thread-safe.
+    private static ConcurrentHashMap<ITestDevice, String> sDeviceCodeName =
+            new ConcurrentHashMap<>();
+    private static ConcurrentHashMap<ITestDevice, Boolean> sDeviceIsGKI10 =
+            new ConcurrentHashMap<>();
 
     @BeforeClassWithInfo
     public static void setUpClass(TestInformation testInfo) throws Exception {
-        sDevice = testInfo.getDevice();
-
-        boolean isKernelARM64 =
-                sDevice.executeShellCommand(executeShellKernelARM64).contains("CONFIG_ARM64");
-        isGKI10 = false;
+        // Collects information while adb is available, prior to rebooting into fastbootd.
+        boolean isKernelARM64 = testInfo.getDevice()
+                                        .executeShellCommand(executeShellKernelARM64)
+                                        .contains("CONFIG_ARM64");
+        boolean isGKI10 = false;
         if (isKernelARM64) {
-            String output = sDevice.executeShellCommand("uname -r");
+            String output = testInfo.getDevice().executeShellCommand("uname -r");
             Pattern p = Pattern.compile("^(\\d+)\\.(\\d+)");
             Matcher m1 = p.matcher(output);
             assertTrue(m1.find());
@@ -72,26 +78,34 @@
         // Gets the code name via adb first. The following test cases might
         // assert different values based on if the build is a final release build
         // or not, where the value of the code name will be "REL" in this case.
-        sCodeName = sDevice.getProperty(DeviceProperties.BUILD_CODENAME);
-        assertNotNull(sCodeName);
-        sCodeName = sCodeName.trim();
+        String codeName = testInfo.getDevice().getProperty(DeviceProperties.BUILD_CODENAME);
+        assertNotNull(codeName);
+        codeName = codeName.trim();
+
+        // Saves the local variables to static variables for later use, because adb
+        // is not available in the following tests.
+        sDeviceIsGKI10.put(testInfo.getDevice(), isGKI10);
+        sDeviceCodeName.put(testInfo.getDevice(), codeName);
 
         // Transfers from adb to fastbootd.
         if (!isGKI10) {
-            sDevice.rebootIntoFastbootd();
+            testInfo.getDevice().rebootIntoFastbootd();
         }
     }
 
     @Before
     public void setUp() throws Exception {
-        Assume.assumeFalse("Skipping test for fastbootd on GKI 1.0", isGKI10);
+        Assume.assumeFalse("Skipping test for fastbootd on GKI 1.0",
+                sDeviceIsGKI10.get(getTestInformation().getDevice()));
     }
 
     @AfterClassWithInfo
     public static void tearDownClass(TestInformation testInfo) throws Exception {
-        if (!isGKI10) {
-            testInfo.getDevice().reboot(); // back to adb.
+        if (!sDeviceIsGKI10.get(testInfo.getDevice())) {
+            testInfo.getDevice().reboot(); // reboot from fastbootd to adb.
         }
+        sDeviceIsGKI10.remove(testInfo.getDevice());
+        sDeviceCodeName.remove(testInfo.getDevice());
     }
 
     /* Devices launching in R and after must export cpu-abi. */
@@ -99,7 +113,7 @@
     public void testCpuAbiInfo() throws Exception {
         final HashSet<String> allCpuAbis = new HashSet<String>(
                 Arrays.asList("armeabi-v7a", "arm64-v8a", "mips", "mips64", "x86", "x86_64"));
-        String cpuAbi = sDevice.getFastbootVariable("cpu-abi");
+        String cpuAbi = getTestInformation().getDevice().getFastbootVariable("cpu-abi");
         CLog.d("cpuAbi: '%s'", cpuAbi);
         assertTrue(allCpuAbis.contains(cpuAbi));
     }
@@ -107,7 +121,7 @@
     /* Devices launching in R and after must export version-os. */
     @Test
     public void testOsVersion() throws Exception {
-        String osVersion = sDevice.getFastbootVariable("version-os");
+        String osVersion = getTestInformation().getDevice().getFastbootVariable("version-os");
         CLog.d("os version: '%s'", osVersion);
         // The value of osVersion is derived from "ro.build.version.release",
         // which is a user-visible version string. The value does not have
@@ -119,12 +133,13 @@
     /* Devices launching in R and after must export version-vndk. */
     @Test
     public void testVndkVersion() throws Exception {
-        String vndkVersion = sDevice.getFastbootVariable("version-vndk");
-        CLog.d("vndk version: '%s'", vndkVersion);
+        String vndkVersion = getTestInformation().getDevice().getFastbootVariable("version-vndk");
+        String codeName = sDeviceCodeName.get(getTestInformation().getDevice());
+        CLog.d("vndk version: '%s', code name: '%s'", vndkVersion, codeName);
         // The value of vndkVersion might be a letter or a string on pre-release builds,
         // e.g., R or Tiramisu.
         // And it is a number representing the API level on final release builds, e.g., 30.
-        if ("REL".equals(sCodeName)) {
+        if ("REL".equals(codeName)) {
             try {
                 int intVndkVersion = Integer.parseInt(vndkVersion);
                 assertTrue(intVndkVersion >= PLATFORM_API_LEVEL_R);
@@ -139,7 +154,8 @@
     /* Devices launching in R and after must export dynamic-partition. */
     @Test
     public void testDynamicPartition() throws Exception {
-        String dynamic_partition = sDevice.getFastbootVariable("dynamic-partition");
+        String dynamic_partition =
+                getTestInformation().getDevice().getFastbootVariable("dynamic-partition");
         CLog.d("dynamic_partition: '%s'", dynamic_partition);
         assertTrue(dynamic_partition.equals("true"));
     }
@@ -147,7 +163,8 @@
     /* Devices launching in R and after must export treble-enabled. */
     @Test
     public void testTrebleEnable() throws Exception {
-        String treble_enabled = sDevice.getFastbootVariable("treble-enabled");
+        String treble_enabled =
+                getTestInformation().getDevice().getFastbootVariable("treble-enabled");
         CLog.d("treble_enabled: '%s'", treble_enabled);
         assertTrue(treble_enabled.equals("true") || treble_enabled.equals("false"));
     }
@@ -155,7 +172,8 @@
     /* Devices launching in R and after must export first-api-level. */
     @Test
     public void testFirstApiLevel() throws Exception {
-        String first_api_level = sDevice.getFastbootVariable("first-api-level");
+        String first_api_level =
+                getTestInformation().getDevice().getFastbootVariable("first-api-level");
         CLog.d("first_api_level: '%s'", first_api_level);
         try {
             int api_level = Integer.parseInt(first_api_level);
@@ -168,7 +186,7 @@
     /* Devices launching in R and after must export security-patch-level. */
     @Test
     public void testSecurityPatchLevel() throws Exception {
-        String SPL = sDevice.getFastbootVariable("security-patch-level");
+        String SPL = getTestInformation().getDevice().getFastbootVariable("security-patch-level");
         CLog.d("SPL: '%s'", SPL);
         try {
             SimpleDateFormat template = new SimpleDateFormat("yyyy-MM-dd");
@@ -181,7 +199,8 @@
     /* Devices launching in R and after must export system-fingerprint. */
     @Test
     public void testSystemFingerprint() throws Exception {
-        String systemFingerprint = sDevice.getFastbootVariable("system-fingerprint");
+        String systemFingerprint =
+                getTestInformation().getDevice().getFastbootVariable("system-fingerprint");
         CLog.d("system fingerprint: '%s'", systemFingerprint);
         verifyFingerprint(systemFingerprint);
     }
@@ -189,7 +208,8 @@
     /* Devices launching in R and after must export vendor-fingerprint. */
     @Test
     public void testVendorFingerprint() throws Exception {
-        String vendorFingerprint = sDevice.getFastbootVariable("vendor-fingerprint");
+        String vendorFingerprint =
+                getTestInformation().getDevice().getFastbootVariable("vendor-fingerprint");
         CLog.d("vendor fingerprint: '%s'", vendorFingerprint);
         verifyFingerprint(vendorFingerprint);
     }
diff --git a/testcases/host/fastboot_test/src/com/android/tests/FastbootVerifyUserspaceTest.java b/testcases/host/fastboot_test/src/com/android/tests/FastbootVerifyUserspaceTest.java
index 6a23fa4..a6916c8 100644
--- a/testcases/host/fastboot_test/src/com/android/tests/FastbootVerifyUserspaceTest.java
+++ b/testcases/host/fastboot_test/src/com/android/tests/FastbootVerifyUserspaceTest.java
@@ -34,6 +34,7 @@
 import java.lang.Thread;
 import java.util.Arrays;
 import java.util.HashSet;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.junit.Assert;
@@ -49,39 +50,47 @@
 public class FastbootVerifyUserspaceTest extends BaseHostJUnit4Test {
     // Default maximum command run time is set to 90 seconds.
     private static final long MAX_CMD_RUN_TIME = 90000L;
-
-    private static ITestDevice sDevice;
     private static String executeShellKernelARM64 =
             "cat /proc/config.gz | gzip -d | grep CONFIG_ARM64=y";
-    private static boolean isGKI10;
 
     private IRunUtil mRunUtil = RunUtil.getDefault();
     private String mFuzzyFastbootPath;
 
+    // IMPORTANT: Multiple instances of this class will be created while sharding
+    // the tests across multiple devices. So it needs to use ConcurrentHashMap to
+    // make these static variables thread-safe.
+    private static ConcurrentHashMap<ITestDevice, Boolean> sDeviceIsGKI10 =
+            new ConcurrentHashMap<>();
+
     @BeforeClassWithInfo
     public static void setUpClass(TestInformation testInfo) throws Exception {
-        sDevice = testInfo.getDevice();
-
-        boolean isKernelARM64 =
-                sDevice.executeShellCommand(executeShellKernelARM64).contains("CONFIG_ARM64");
-        isGKI10 = false;
+        // Collects information while adb is available, prior to rebooting into fastbootd.
+        boolean isKernelARM64 = testInfo.getDevice()
+                                        .executeShellCommand(executeShellKernelARM64)
+                                        .contains("CONFIG_ARM64");
+        boolean isGKI10 = false;
         if (isKernelARM64) {
-            String output = sDevice.executeShellCommand("uname -r");
+            String output = testInfo.getDevice().executeShellCommand("uname -r");
             Pattern p = Pattern.compile("^(\\d+)\\.(\\d+)");
             Matcher m1 = p.matcher(output);
             Assert.assertTrue(m1.find());
             isGKI10 = (Integer.parseInt(m1.group(1)) == 5 && Integer.parseInt(m1.group(2)) == 4);
         }
 
+        // Saves the local variable to the static variable for later use, because adb
+        // is not available in the following tests.
+        sDeviceIsGKI10.put(testInfo.getDevice(), isGKI10);
+
         // Transfers from adb to fastbootd.
         if (!isGKI10) {
-            sDevice.rebootIntoFastbootd();
+            testInfo.getDevice().rebootIntoFastbootd();
         }
     }
 
     @Before
     public void setUp() throws Exception {
-        Assume.assumeFalse("Skipping test for fastbootd on GKI 1.0", isGKI10);
+        Assume.assumeFalse("Skipping test for fastbootd on GKI 1.0",
+                sDeviceIsGKI10.get(getTestInformation().getDevice()));
 
         CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(getBuild());
         File file = buildHelper.getTestFile("fuzzy_fastboot", getAbi());
@@ -92,7 +101,7 @@
 
     @AfterClassWithInfo
     public static void tearDownClass(TestInformation testInfo) throws Exception {
-        if (!isGKI10) {
+        if (!sDeviceIsGKI10.get(testInfo.getDevice())) {
             // Make sure the device state still is FASTBOOTD after the test class have
             // been executed, because fastboot commands in the tests will disrupt
             // device state
@@ -100,8 +109,9 @@
                 ((IManagedTestDevice) testInfo.getDevice())
                         .setDeviceState(TestDeviceState.FASTBOOTD);
             }
-            testInfo.getDevice().reboot(); // back to adb.
+            testInfo.getDevice().reboot(); // reboot from fastbootd to adb.
         }
+        sDeviceIsGKI10.remove(testInfo.getDevice());
     }
 
     /* Runs fuzzy_fastboot gtest to verify slot operations in fastbootd implementation. */
@@ -109,7 +119,8 @@
     @Test
     public void testFastbootdSlotOperations() throws Exception {
         CommandResult result = mRunUtil.runTimedCmd(MAX_CMD_RUN_TIME, mFuzzyFastbootPath,
-                String.format("--serial=%s", sDevice.getFastbootSerialNumber()),
+                String.format(
+                        "--serial=%s", getTestInformation().getDevice().getFastbootSerialNumber()),
                 "--gtest_filter=Conformance.Slots:Conformance.SetActive");
         Assert.assertEquals(CommandStatus.SUCCESS, result.getStatus());
     }
@@ -118,7 +129,8 @@
     @Test
     public void testLogicalPartitionCommands() throws Exception {
         CommandResult result = mRunUtil.runTimedCmd(MAX_CMD_RUN_TIME, mFuzzyFastbootPath,
-                String.format("--serial=%s", sDevice.getFastbootSerialNumber()),
+                String.format(
+                        "--serial=%s", getTestInformation().getDevice().getFastbootSerialNumber()),
                 "--gtest_filter=LogicalPartitionCompliance.GetVarIsLogical:LogicalPartitionCompliance.SuperPartition");
         Assert.assertEquals(CommandStatus.SUCCESS, result.getStatus());
     }
@@ -126,7 +138,8 @@
     /* Devices launching with DAP must have a super partition named "super". */
     @Test
     public void testSuperPartitionName() throws Exception {
-        String superPartitionName = sDevice.getFastbootVariable("super-partition-name");
+        String superPartitionName =
+                getTestInformation().getDevice().getFastbootVariable("super-partition-name");
         Assert.assertEquals("super", superPartitionName);
     }
 
@@ -134,7 +147,8 @@
     @Test
     public void testFastbootReboot() throws Exception {
         CommandResult result = mRunUtil.runTimedCmd(MAX_CMD_RUN_TIME, mFuzzyFastbootPath,
-                String.format("--serial=%s", sDevice.getFastbootSerialNumber()),
+                String.format(
+                        "--serial=%s", getTestInformation().getDevice().getFastbootSerialNumber()),
                 "--gtest_filter=LogicalPartitionCompliance.FastbootRebootTest");
         Assert.assertEquals(CommandStatus.SUCCESS, result.getStatus());
     }
@@ -143,7 +157,8 @@
     @Test
     public void testLogicalPartitionFlashing() throws Exception {
         CommandResult result = mRunUtil.runTimedCmd(MAX_CMD_RUN_TIME, mFuzzyFastbootPath,
-                String.format("--serial=%s", sDevice.getFastbootSerialNumber()),
+                String.format(
+                        "--serial=%s", getTestInformation().getDevice().getFastbootSerialNumber()),
                 "--gtest_filter=LogicalPartitionCompliance.CreateResizeDeleteLP");
         Assert.assertEquals(CommandStatus.SUCCESS, result.getStatus());
     }