Speed up AuthFsHostTest by reusing the VM

This is basically 7fc99e6c5e03bccc7d461a86c46b1a03b34a547b without
merging AuthFsHostTest into MicrodroidHostTestCases.

Also, add the test to presubmit.

Bug: 191056545
Bug: 193749869
Test: atest AuthFsHostTest

Change-Id: I866c4bbd6dbfc6d47719ad68dd91dafa8096b2c3
diff --git a/authfs/TEST_MAPPING b/authfs/TEST_MAPPING
index d0c0b09..14f1824 100644
--- a/authfs/TEST_MAPPING
+++ b/authfs/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "authfs_device_test_src_lib"
+    },
+    {
+      "name": "AuthFsHostTest"
     }
   ]
 }
diff --git a/authfs/tests/AndroidTest.xml b/authfs/tests/AndroidTest.xml
index 8f940f6..6100ab9 100644
--- a/authfs/tests/AndroidTest.xml
+++ b/authfs/tests/AndroidTest.xml
@@ -18,18 +18,11 @@
     <!-- Need root to start virtualizationservice -->
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
 
-    <!-- virtualizationservice doesn't have access to shell_data_file. Instead of giving it
-          a test-only permission, run it without selinux -->
+    <!-- Still need to define SELinux policy for authfs and fd_server properly. -->
     <target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer"/>
 
-    <!-- Basic checks that the device has all the prerequisites. -->
     <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
         <option name="throw-if-cmd-fail" value="true" />
-        <!-- Make sure kernel has FUSE enabled. -->
-        <option name="run-command" value="ls /dev/fuse" />
-        <!-- Make sure necessary executables are installed. -->
-        <option name="run-command" value="ls /apex/com.android.virt/bin/fd_server" />
-        <option name="run-command" value="ls /apex/com.android.virt/bin/authfs" />
         <!-- Prepare test directory. -->
         <option name="run-command" value="mkdir -p /data/local/tmp/authfs/mnt" />
         <option name="teardown-command" value="rm -rf /data/local/tmp/authfs" />
diff --git a/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java b/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
index 426b333..6e1c890 100644
--- a/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
+++ b/authfs/tests/java/src/com/android/fs/AuthFsHostTest.java
@@ -18,18 +18,26 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.platform.test.annotations.RootPermissionTest;
+import android.virt.test.CommandRunner;
 import android.virt.test.VirtualizationTestCaseBase;
 
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.TestInformation;
 import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
+import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
 import com.android.tradefed.util.CommandResult;
 
 import org.junit.After;
+import org.junit.AssumptionViolatedException;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,7 +45,6 @@
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 
-// TODO move to Virtualization/tests/hostside/
 @RootPermissionTest
 @RunWith(DeviceJUnit4ClassRunner.class)
 public final class AuthFsHostTest extends VirtualizationTestCaseBase {
@@ -55,50 +62,87 @@
     private static final String AUTHFS_BIN = "/system/bin/authfs";
 
     /** Plenty of time for authfs to get ready */
-    private static final int AUTHFS_INIT_TIMEOUT_MS = 1500;
+    private static final int AUTHFS_INIT_TIMEOUT_MS = 3000;
 
     /** FUSE's magic from statfs(2) */
     private static final String FUSE_SUPER_MAGIC_HEX = "65735546";
 
-    private ExecutorService mThreadPool;
-    private String mCid;
+    private static CommandRunner sAndroid;
+    private static String sCid;
+    private static boolean sAssumptionFailed;
 
-    @Before
-    public void setUp() throws DeviceNotAvailableException {
-        testIfDeviceIsCapable();
+    private ExecutorService mThreadPool = Executors.newCachedThreadPool();
 
-        cleanUpTestFiles();
+    @BeforeClassWithInfo
+    public static void beforeClassWithDevice(TestInformation testInfo)
+            throws DeviceNotAvailableException {
+        assertNotNull(testInfo.getDevice());
+        ITestDevice androidDevice = testInfo.getDevice();
+        sAndroid = new CommandRunner(androidDevice);
 
-        prepareVirtualizationTestSetup();
+        try {
+            testIfDeviceIsCapable(androidDevice);
+        } catch (AssumptionViolatedException e) {
+            // NB: The assumption exception is NOT handled by the test infra when it is thrown from
+            // a class method (see b/37502066). This has not only caused the loss of log, but also
+            // prevented the test cases to be reported at all and thus confused the test infra.
+            //
+            // Since we want to avoid the big overhead to start the VM repeatedly on CF, let's catch
+            // AssumptionViolatedException and emulate it artifitially.
+            CLog.e("Assumption failed: " + e);
+            sAssumptionFailed = true;
+            return;
+        }
 
-        mThreadPool = Executors.newCachedThreadPool();
+        prepareVirtualizationTestSetup(androidDevice);
 
         // For each test case, boot and adb connect to a new Microdroid
+        CLog.i("Starting the shared VM");
         final String apkName = "MicrodroidTestApp.apk";
         final String packageName = "com.android.microdroid.test";
         final String configPath = "assets/vm_config.json"; // path inside the APK
-        mCid = startMicrodroid(apkName, packageName, configPath, /* debug */ false);
-        adbConnectToMicrodroid(mCid);
+        sCid =
+                startMicrodroid(
+                        androidDevice,
+                        testInfo.getBuildInfo(),
+                        apkName,
+                        packageName,
+                        configPath,
+                        /* debug */ false);
+        adbConnectToMicrodroid(androidDevice, sCid);
 
         // Root because authfs (started from shell in this test) currently require root to open
         // /dev/fuse and mount the FUSE.
         rootMicrodroid();
     }
 
-    @After
-    public void tearDown() throws DeviceNotAvailableException {
-        if (mCid != null) {
-            shutdownMicrodroid(mCid);
-            mCid = null;
+    @AfterClassWithInfo
+    public static void afterClassWithDevice(TestInformation testInfo)
+            throws DeviceNotAvailableException {
+        assertNotNull(sAndroid);
+
+        if (sCid != null) {
+            CLog.i("Shutting down shared VM");
+            shutdownMicrodroid(sAndroid.getDevice(), sCid);
+            sCid = null;
         }
 
-        tryRunOnAndroid("killall fd_server");
-        cleanUpTestFiles();
-        cleanUpVirtualizationTestSetup();
+        cleanUpVirtualizationTestSetup(sAndroid.getDevice());
+        sAndroid = null;
     }
 
-    private void cleanUpTestFiles() throws DeviceNotAvailableException {
-        tryRunOnAndroid("rm -f " + TEST_DIR + "/output");
+    @Before
+    public void setUp() {
+        assumeFalse(sAssumptionFailed);
+    }
+
+    @After
+    public void tearDown() throws DeviceNotAvailableException {
+        sAndroid.tryRun("killall fd_server");
+        sAndroid.tryRun("rm -f " + TEST_DIR + "/output");
+
+        tryRunOnMicrodroid("killall authfs");
+        tryRunOnMicrodroid("umount " + MOUNT_DIR);
     }
 
     @Test
@@ -194,7 +238,7 @@
 
         // Action
         // Tampering with the first 2 4K block of the backing file.
-        runOnAndroid("dd if=/dev/zero of=" + backendPath + " bs=1 count=8192");
+        sAndroid.run("dd if=/dev/zero of=" + backendPath + " bs=1 count=8192");
 
         // Verify
         // Write to a block partially requires a read back to calculate the new hash. It should fail
@@ -274,7 +318,7 @@
     }
 
     private String computeFileHashOnAndroid(String path) throws DeviceNotAvailableException {
-        String result = runOnAndroid("sha256sum " + path);
+        String result = sAndroid.run("sha256sum " + path);
         String[] tokens = result.split("\\s");
         if (tokens.length > 0) {
             return tokens[0];
@@ -320,7 +364,7 @@
                 () -> {
                     try {
                         CLog.i("Starting fd_server");
-                        CommandResult result = getDevice().executeShellV2Command(cmd);
+                        CommandResult result = sAndroid.runForResult(cmd);
                         CLog.w("fd_server has stopped: " + result);
                     } catch (DeviceNotAvailableException e) {
                         CLog.e("Error running fd_server", e);