Revert "Merge AuthFsHostTest into MicrodroidTestCase"
This reverts commit 7fc99e6c5e03bccc7d461a86c46b1a03b34a547b.
Reason for revert: Affects MicrodroidHostTestCases. b/193749869
Change-Id: Ic72353d85427264845cf04408b256b74882cdc66
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 4d70c70..968c991 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -8,14 +8,9 @@
test_suites: ["device-tests"],
libs: [
"tradefed",
- "compatibility-tradefed",
- "compatibility-host-util",
],
static_libs: [
"VirtualizationTestHelper",
],
- data: [
- ":authfs_test_files",
- ":MicrodroidTestApp.signed",
- ],
+ data: [":MicrodroidTestApp.signed"],
}
diff --git a/tests/hostside/AndroidTest.xml b/tests/hostside/AndroidTest.xml
index 889fc4e..eda733a 100644
--- a/tests/hostside/AndroidTest.xml
+++ b/tests/hostside/AndroidTest.xml
@@ -22,38 +22,6 @@
a test-only permission, run it without selinux -->
<target_preparer class="com.android.tradefed.targetprep.DisableSELinuxTargetPreparer"/>
- <!-- Prepare test directory for AuthFsTestCase. -->
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="throw-if-cmd-fail" value="true" />
- <!-- 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" />
- </target_preparer>
-
- <!-- Prepare files for AuthFsTestCase. -->
- <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
- <option name="cleanup" value="true" />
- <option name="abort-on-push-failure" value="true" />
- <option name="push-file" key="cert.der" value="/data/local/tmp/authfs/cert.der" />
- <option name="push-file" key="input.4m" value="/data/local/tmp/authfs/input.4m" />
- <option name="push-file" key="input.4k1" value="/data/local/tmp/authfs/input.4k1" />
- <option name="push-file" key="input.4k" value="/data/local/tmp/authfs/input.4k" />
- <option name="push-file" key="input.4m.fsv_sig"
- value="/data/local/tmp/authfs/input.4m.fsv_sig" />
- <option name="push-file" key="input.4k1.fsv_sig"
- value="/data/local/tmp/authfs/input.4k1.fsv_sig" />
- <option name="push-file" key="input.4k.fsv_sig"
- value="/data/local/tmp/authfs/input.4k.fsv_sig" />
- <option name="push-file" key="input.4m.merkle_dump"
- value="/data/local/tmp/authfs/input.4m.merkle_dump" />
- <option name="push-file" key="input.4m.merkle_dump.bad"
- value="/data/local/tmp/authfs/input.4m.merkle_dump.bad" />
- <option name="push-file" key="input.4k1.merkle_dump"
- value="/data/local/tmp/authfs/input.4k1.merkle_dump" />
- <option name="push-file" key="input.4k.merkle_dump"
- value="/data/local/tmp/authfs/input.4k.merkle_dump" />
- </target_preparer>
-
<test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
<option name="jar" value="MicrodroidHostTestCases.jar" />
</test>
diff --git a/tests/hostside/helper/java/android/virt/test/CommandRunner.java b/tests/hostside/helper/java/android/virt/test/CommandRunner.java
deleted file mode 100644
index 696c89a..0000000
--- a/tests/hostside/helper/java/android/virt/test/CommandRunner.java
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.virt.test;
-
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeThat;
-
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.util.CommandResult;
-import com.android.tradefed.util.CommandStatus;
-
-import java.util.Arrays;
-
-import javax.annotation.Nonnull;
-
-/** A helper class to provide easy way to run commands on a test device. */
-public class CommandRunner {
-
- /** Default timeout. 30 sec because Microdroid is extremely slow on GCE-on-CF. */
- private static final long DEFAULT_TIMEOUT = 30000;
-
- private ITestDevice mDevice;
-
- public CommandRunner(@Nonnull ITestDevice device) {
- mDevice = device;
- }
-
- public ITestDevice getDevice() {
- return mDevice;
- }
-
- public String run(String... cmd) throws DeviceNotAvailableException {
- CommandResult result = runForResult(cmd);
- if (result.getStatus() != CommandStatus.SUCCESS) {
- fail(join(cmd) + " has failed: " + result);
- }
- return result.getStdout().trim();
- }
-
- public String tryRun(String... cmd) throws DeviceNotAvailableException {
- CommandResult result = runForResult(cmd);
- if (result.getStatus() == CommandStatus.SUCCESS) {
- return result.getStdout().trim();
- } else {
- CLog.d(join(cmd) + " has failed (but ok): " + result);
- return null;
- }
- }
-
- public String runWithTimeout(long timeoutMillis, String... cmd)
- throws DeviceNotAvailableException {
- CommandResult result =
- mDevice.executeShellV2Command(
- join(cmd), timeoutMillis, java.util.concurrent.TimeUnit.MILLISECONDS);
- if (result.getStatus() != CommandStatus.SUCCESS) {
- fail(join(cmd) + " has failed: " + result);
- }
- return result.getStdout().trim();
- }
-
- public CommandResult runForResult(String... cmd) throws DeviceNotAvailableException {
- return mDevice.executeShellV2Command(join(cmd));
- }
-
- public void assumeSuccess(String... cmd) throws DeviceNotAvailableException {
- assumeThat(runForResult(cmd).getStatus(), is(CommandStatus.SUCCESS));
- }
-
- private static String join(String... strs) {
- return String.join(" ", Arrays.asList(strs));
- }
-}
diff --git a/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java b/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
index 7a17619..451f9ba 100644
--- a/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
+++ b/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
@@ -20,11 +20,10 @@
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeThat;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.util.CommandResult;
@@ -51,63 +50,92 @@
private static final long MICRODROID_ADB_CONNECT_TIMEOUT_MINUTES = 5;
- public static void prepareVirtualizationTestSetup(ITestDevice androidDevice)
- throws DeviceNotAvailableException {
- CommandRunner android = new CommandRunner(androidDevice);
-
+ public void prepareVirtualizationTestSetup() throws DeviceNotAvailableException {
// kill stale crosvm processes
- android.tryRun("killall", "crosvm");
+ tryRunOnAndroid("killall", "crosvm");
+
+ // Prepare the test root
+ tryRunOnAndroid("rm", "-rf", TEST_ROOT);
+ tryRunOnAndroid("mkdir", "-p", TEST_ROOT);
// disconnect from microdroid
tryRunOnHost("adb", "disconnect", MICRODROID_SERIAL);
}
- public static void cleanUpVirtualizationTestSetup(ITestDevice androidDevice)
- throws DeviceNotAvailableException {
- CommandRunner android = new CommandRunner(androidDevice);
-
+ public void cleanUpVirtualizationTestSetup() throws DeviceNotAvailableException {
// disconnect from microdroid
tryRunOnHost("adb", "disconnect", MICRODROID_SERIAL);
// kill stale VMs and directories
- android.tryRun("killall", "crosvm");
- android.tryRun("rm", "-rf", "/data/misc/virtualizationservice/*");
- android.tryRun("stop", "virtualizationservice");
+ tryRunOnAndroid("killall", "crosvm");
+ tryRunOnAndroid("rm", "-rf", "/data/misc/virtualizationservice/*");
+ tryRunOnAndroid("stop", "virtualizationservice");
}
- public static void testIfDeviceIsCapable(ITestDevice androidDevice)
- throws DeviceNotAvailableException {
- CommandRunner android = new CommandRunner(androidDevice);
-
+ public void testIfDeviceIsCapable() throws DeviceNotAvailableException {
// Checks the preconditions to run microdroid. If the condition is not satisfied
// don't run the test (instead of failing)
- android.assumeSuccess("ls /dev/kvm");
- android.assumeSuccess("ls /dev/vhost-vsock");
- android.assumeSuccess("ls /apex/com.android.virt/bin/crosvm");
+ skipIfFail("ls /dev/kvm");
+ skipIfFail("ls /dev/vhost-vsock");
+ skipIfFail("ls /apex/com.android.virt/bin/crosvm");
}
// Run an arbitrary command in the host side and returns the result
- private static String runOnHost(String... cmd) {
+ private String runOnHost(String... cmd) {
return runOnHostWithTimeout(10000, cmd);
}
// Same as runOnHost, but failure is not an error
- private static String tryRunOnHost(String... cmd) {
+ private String tryRunOnHost(String... cmd) {
final long timeout = 10000;
CommandResult result = RunUtil.getDefault().runTimedCmd(timeout, cmd);
return result.getStdout().trim();
}
// Same as runOnHost, but with custom timeout
- private static String runOnHostWithTimeout(long timeoutMillis, String... cmd) {
+ private String runOnHostWithTimeout(long timeoutMillis, String... cmd) {
assertTrue(timeoutMillis >= 0);
CommandResult result = RunUtil.getDefault().runTimedCmd(timeoutMillis, cmd);
assertThat(result.getStatus(), is(CommandStatus.SUCCESS));
return result.getStdout().trim();
}
+ // Run a shell command on Android. the default timeout is 2 min by tradefed
+ public String runOnAndroid(String... cmd) throws DeviceNotAvailableException {
+ CommandResult result = getDevice().executeShellV2Command(join(cmd));
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ fail(join(cmd) + " has failed: " + result);
+ }
+ return result.getStdout().trim();
+ }
+
+ // Same as runOnAndroid, but returns null on error.
+ public String tryRunOnAndroid(String... cmd) throws DeviceNotAvailableException {
+ CommandResult result = getDevice().executeShellV2Command(join(cmd));
+ if (result.getStatus() == CommandStatus.SUCCESS) {
+ return result.getStdout().trim();
+ } else {
+ CLog.d(join(cmd) + " has failed (but ok): " + result);
+ return null;
+ }
+ }
+
+ private String runOnAndroidWithTimeout(long timeoutMillis, String... cmd)
+ throws DeviceNotAvailableException {
+ CommandResult result =
+ getDevice()
+ .executeShellV2Command(
+ join(cmd),
+ timeoutMillis,
+ java.util.concurrent.TimeUnit.MILLISECONDS);
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ fail(join(cmd) + " has failed: " + result);
+ }
+ return result.getStdout().trim();
+ }
+
// Run a shell command on Microdroid
- public static String runOnMicrodroid(String... cmd) {
+ public String runOnMicrodroid(String... cmd) {
CommandResult result = runOnMicrodroidForResult(cmd);
if (result.getStatus() != CommandStatus.SUCCESS) {
fail(join(cmd) + " has failed: " + result);
@@ -116,7 +144,7 @@
}
// Same as runOnMicrodroid, but returns null on error.
- public static String tryRunOnMicrodroid(String... cmd) {
+ public String tryRunOnMicrodroid(String... cmd) {
CommandResult result = runOnMicrodroidForResult(cmd);
if (result.getStatus() == CommandStatus.SUCCESS) {
return result.getStdout().trim();
@@ -126,62 +154,51 @@
}
}
- public static CommandResult runOnMicrodroidForResult(String... cmd) {
+ public CommandResult runOnMicrodroidForResult(String... cmd) {
final long timeout = 30000; // 30 sec. Microdroid is extremely slow on GCE-on-CF.
return RunUtil.getDefault()
.runTimedCmd(timeout, "adb", "-s", MICRODROID_SERIAL, "shell", join(cmd));
}
- private static String join(String... strs) {
+ private String join(String... strs) {
return String.join(" ", Arrays.asList(strs));
}
public File findTestFile(String name) {
- return findTestFile(getBuild(), name);
- }
-
- private static File findTestFile(IBuildInfo buildInfo, String name) {
try {
- return (new CompatibilityBuildHelper(buildInfo)).getTestFile(name);
+ return (new CompatibilityBuildHelper(getBuild())).getTestFile(name);
} catch (FileNotFoundException e) {
fail("Missing test file: " + name);
return null;
}
}
- public static String startMicrodroid(
- ITestDevice androidDevice,
- IBuildInfo buildInfo,
- String apkName,
- String packageName,
- String configPath,
- boolean debug)
+ public String startMicrodroid(
+ String apkName, String packageName, String configPath, boolean debug)
throws DeviceNotAvailableException {
- CommandRunner android = new CommandRunner(androidDevice);
-
// Install APK
- File apkFile = findTestFile(buildInfo, apkName);
- androidDevice.installPackage(apkFile, /* reinstall */ true);
+ File apkFile = findTestFile(apkName);
+ getDevice().installPackage(apkFile, /* reinstall */ true);
// Get the path to the installed apk. Note that
// getDevice().getAppPackageInfo(...).getCodePath() doesn't work due to the incorrect
// parsing of the "=" character. (b/190975227). So we use the `pm path` command directly.
- String apkPath = android.run("pm", "path", packageName);
+ String apkPath = runOnAndroid("pm", "path", packageName);
assertTrue(apkPath.startsWith("package:"));
apkPath = apkPath.substring("package:".length());
// Push the idsig file to the device
- File idsigOnHost = findTestFile(buildInfo, apkName + ".idsig");
+ File idsigOnHost = findTestFile(apkName + ".idsig");
final String apkIdsigPath = TEST_ROOT + apkName + ".idsig";
- androidDevice.pushFile(idsigOnHost, apkIdsigPath);
+ getDevice().pushFile(idsigOnHost, apkIdsigPath);
final String logPath = TEST_ROOT + "log.txt";
final String debugFlag = debug ? "--debug " : "";
// Run the VM
- android.run("start", "virtualizationservice");
+ runOnAndroid("start", "virtualizationservice");
String ret =
- android.run(
+ runOnAndroid(
VIRT_APEX + "bin/vm",
"run-app",
"--daemonize",
@@ -197,7 +214,7 @@
() -> {
try {
// Keep redirecting sufficiently long enough
- android.runWithTimeout(
+ runOnAndroidWithTimeout(
MICRODROID_BOOT_TIMEOUT_MINUTES * 60 * 1000,
"logwrapper",
"tail",
@@ -216,20 +233,17 @@
return matcher.group(1);
}
- public static void shutdownMicrodroid(ITestDevice androidDevice, String cid)
- throws DeviceNotAvailableException {
- CommandRunner android = new CommandRunner(androidDevice);
-
+ public void shutdownMicrodroid(String cid) throws DeviceNotAvailableException {
// Close the connection before shutting the VM down. Otherwise, b/192660485.
tryRunOnHost("adb", "disconnect", MICRODROID_SERIAL);
- final String serial = androidDevice.getSerialNumber();
+ final String serial = getDevice().getSerialNumber();
tryRunOnHost("adb", "-s", serial, "forward", "--remove", "tcp:" + TEST_VM_ADB_PORT);
// Shutdown the VM
- android.run(VIRT_APEX + "bin/vm", "stop", cid);
+ runOnAndroid(VIRT_APEX + "bin/vm", "stop", cid);
}
- public static void rootMicrodroid() throws DeviceNotAvailableException {
+ public void rootMicrodroid() throws DeviceNotAvailableException {
runOnHost("adb", "-s", MICRODROID_SERIAL, "root");
// TODO(192660959): Figure out the root cause and remove the sleep. For unknown reason,
@@ -237,12 +251,6 @@
// `adb -s $MICRODROID_SERIAL shell ...` often fails with "adb: device offline".
try {
Thread.sleep(1000);
- runOnHostWithTimeout(
- MICRODROID_ADB_CONNECT_TIMEOUT_MINUTES * 60 * 1000,
- "adb",
- "-s",
- MICRODROID_SERIAL,
- "wait-for-device");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
@@ -250,13 +258,12 @@
// Establish an adb connection to microdroid by letting Android forward the connection to
// microdroid. Wait until the connection is established and microdroid is booted.
- public static void adbConnectToMicrodroid(ITestDevice androidDevice, String cid)
- throws DeviceNotAvailableException {
+ public void adbConnectToMicrodroid(String cid) throws DeviceNotAvailableException {
long start = System.currentTimeMillis();
long timeoutMillis = MICRODROID_ADB_CONNECT_TIMEOUT_MINUTES * 60 * 1000;
long elapsed = 0;
- final String serial = androidDevice.getSerialNumber();
+ final String serial = getDevice().getSerialNumber();
final String from = "tcp:" + TEST_VM_ADB_PORT;
final String to = "vsock:" + cid + ":5555";
runOnHost("adb", "-s", serial, "forward", from, to);
@@ -290,4 +297,9 @@
// Check if it actually booted by reading a sysprop.
assertThat(runOnMicrodroid("getprop", "ro.hardware"), is("microdroid"));
}
+
+ private void skipIfFail(String command) throws DeviceNotAvailableException {
+ CommandResult result = getDevice().executeShellV2Command(command);
+ assumeThat(result.getStatus(), is(CommandStatus.SUCCESS));
+ }
}
diff --git a/tests/hostside/java/android/virt/test/AuthFsTestCase.java b/tests/hostside/java/android/virt/test/AuthFsTestCase.java
deleted file mode 100644
index ae29a09..0000000
--- a/tests/hostside/java/android/virt/test/AuthFsTestCase.java
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.virt.test;
-
-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 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;
-
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-@RootPermissionTest
-@RunWith(DeviceJUnit4ClassRunner.class)
-public final class AuthFsTestCase extends VirtualizationTestCaseBase {
-
- /** Test directory on Android where data are located */
- private static final String TEST_DIR = "/data/local/tmp/authfs";
-
- /** Mount point of authfs on Microdroid during the test */
- private static final String MOUNT_DIR = "/data/local/tmp";
-
- /** Path to fd_server on Android */
- private static final String FD_SERVER_BIN = "/apex/com.android.virt/bin/fd_server";
-
- /** Path to authfs on Microdroid */
- 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 = 3000;
-
- /** FUSE's magic from statfs(2) */
- private static final String FUSE_SUPER_MAGIC_HEX = "65735546";
-
- private static CommandRunner sAndroid;
- private static String sCid;
- private static boolean sAssumptionFailed;
-
- private ExecutorService mThreadPool = Executors.newCachedThreadPool();
-
- @BeforeClassWithInfo
- public static void beforeClassWithDevice(TestInformation testInfo)
- throws DeviceNotAvailableException {
- assertNotNull(testInfo.getDevice());
- ITestDevice androidDevice = testInfo.getDevice();
- sAndroid = new CommandRunner(androidDevice);
-
- 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;
- }
-
- 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
- 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();
- }
-
- @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;
- }
-
- cleanUpVirtualizationTestSetup(sAndroid.getDevice());
- sAndroid = null;
- }
-
- @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
- public void testReadWithFsverityVerification_RemoteFile()
- throws DeviceNotAvailableException, InterruptedException {
- // Setup
- runFdServerOnAndroid(
- "3<input.4m 4<input.4m.merkle_dump 5<input.4m.fsv_sig 6<input.4m",
- "--ro-fds 3:4:5 --ro-fds 6 --rpc-binder");
-
- runAuthFsOnMicrodroid(
- "--remote-ro-file-unverified 10:6:4194304 --remote-ro-file 11:3:4194304:cert.der"
- + " --cid 2");
-
- // Action
- String actualHashUnverified4m = computeFileHashOnMicrodroid(MOUNT_DIR + "/10");
- String actualHash4m = computeFileHashOnMicrodroid(MOUNT_DIR + "/11");
-
- // Verify
- String expectedHash4m = computeFileHashOnAndroid(TEST_DIR + "/input.4m");
-
- assertEquals("Inconsistent hash from /authfs/10: ", expectedHash4m, actualHashUnverified4m);
- assertEquals("Inconsistent hash from /authfs/11: ", expectedHash4m, actualHash4m);
- }
-
- // Separate the test from the above simply because exec in shell does not allow open too many
- // files.
- @Test
- public void testReadWithFsverityVerification_RemoteSmallerFile()
- throws DeviceNotAvailableException, InterruptedException {
- // Setup
- runFdServerOnAndroid(
- "3<input.4k 4<input.4k.merkle_dump 5<input.4k.fsv_sig"
- + " 6<input.4k1 7<input.4k1.merkle_dump 8<input.4k1.fsv_sig",
- "--ro-fds 3:4:5 --ro-fds 6:7:8 --rpc-binder");
- runAuthFsOnMicrodroid(
- "--remote-ro-file 10:3:4096:cert.der --remote-ro-file 11:6:4097:cert.der --cid 2");
-
- // Action
- String actualHash4k = computeFileHashOnMicrodroid(MOUNT_DIR + "/10");
- String actualHash4k1 = computeFileHashOnMicrodroid(MOUNT_DIR + "/11");
-
- // Verify
- String expectedHash4k = computeFileHashOnAndroid(TEST_DIR + "/input.4k");
- String expectedHash4k1 = computeFileHashOnAndroid(TEST_DIR + "/input.4k1");
-
- assertEquals("Inconsistent hash from /authfs/10: ", expectedHash4k, actualHash4k);
- assertEquals("Inconsistent hash from /authfs/11: ", expectedHash4k1, actualHash4k1);
- }
-
- @Test
- public void testReadWithFsverityVerification_TamperedMerkleTree()
- throws DeviceNotAvailableException, InterruptedException {
- // Setup
- runFdServerOnAndroid(
- "3<input.4m 4<input.4m.merkle_dump.bad 5<input.4m.fsv_sig",
- "--ro-fds 3:4:5 --rpc-binder");
- runAuthFsOnMicrodroid("--remote-ro-file 10:3:4096:cert.der --cid 2");
-
- // Verify
- assertFalse(copyFileOnMicrodroid(MOUNT_DIR + "/10", "/dev/null"));
- }
-
- @Test
- public void testWriteThroughCorrectly()
- throws DeviceNotAvailableException, InterruptedException {
- // Setup
- runFdServerOnAndroid("3<>output", "--rw-fds 3 --rpc-binder");
- runAuthFsOnMicrodroid("--remote-new-rw-file 20:3 --cid 2");
-
- // Action
- String srcPath = "/system/bin/linker64";
- String destPath = MOUNT_DIR + "/20";
- String backendPath = TEST_DIR + "/output";
- assertTrue(copyFileOnMicrodroid(srcPath, destPath));
-
- // Verify
- String expectedHash = computeFileHashOnMicrodroid(srcPath);
- expectBackingFileConsistency(destPath, backendPath, expectedHash);
- }
-
- @Test
- public void testWriteFailedIfDetectsTampering()
- throws DeviceNotAvailableException, InterruptedException {
- // Setup
- runFdServerOnAndroid("3<>output", "--rw-fds 3 --rpc-binder");
- runAuthFsOnMicrodroid("--remote-new-rw-file 20:3 --cid 2");
-
- String srcPath = "/system/bin/linker64";
- String destPath = MOUNT_DIR + "/20";
- String backendPath = TEST_DIR + "/output";
- assertTrue(copyFileOnMicrodroid(srcPath, destPath));
-
- // Action
- // Tampering with the first 2 4K block of the backing file.
- 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
- // when the content is inconsistent to the known hash. Use direct I/O to avoid simply
- // writing to the filesystem cache.
- assertEquals(
- tryRunOnMicrodroid("dd if=/dev/zero of=" + destPath + " bs=1 count=1024 direct"),
- null);
-
- // A full 4K write does not require to read back, so write can succeed even if the backing
- // block has already been tampered.
- runOnMicrodroid("dd if=/dev/zero of=" + destPath + " bs=1 count=4096 skip=4096");
-
- // Otherwise, a partial write with correct backing file should still succeed.
- runOnMicrodroid("dd if=/dev/zero of=" + destPath + " bs=1 count=1024 skip=8192");
- }
-
- @Test
- public void testFileResize() throws DeviceNotAvailableException, InterruptedException {
- // Setup
- runFdServerOnAndroid("3<>output", "--rw-fds 3 --rpc-binder");
- runAuthFsOnMicrodroid("--remote-new-rw-file 20:3 --cid 2");
- String outputPath = MOUNT_DIR + "/20";
- String backendPath = TEST_DIR + "/output";
-
- // Action & Verify
- runOnMicrodroid("yes $'\\x01' | tr -d '\\n' | dd bs=1 count=10000 of=" + outputPath);
- assertEquals(getFileSizeInBytesOnMicrodroid(outputPath), 10000);
- expectBackingFileConsistency(
- outputPath,
- backendPath,
- "684ad25fdc2bbb80cbc910dd1bde6d5499ccf860ca6ee44704b77ec445271353");
-
- resizeFileOnMicrodroid(outputPath, 15000);
- assertEquals(getFileSizeInBytesOnMicrodroid(outputPath), 15000);
- expectBackingFileConsistency(
- outputPath,
- backendPath,
- "567c89f62586e0d33369157afdfe99a2fa36cdffb01e91dcdc0b7355262d610d");
-
- resizeFileOnMicrodroid(outputPath, 5000);
- assertEquals(getFileSizeInBytesOnMicrodroid(outputPath), 5000);
- expectBackingFileConsistency(
- outputPath,
- backendPath,
- "e53130831c13dabff71d5d1797e3aaa467b4b7d32b3b8782c4ff03d76976f2aa");
- }
-
- private void expectBackingFileConsistency(
- String authFsPath, String backendPath, String expectedHash)
- throws DeviceNotAvailableException {
- String hashOnAuthFs = computeFileHashOnMicrodroid(authFsPath);
- assertEquals("File hash is different to expectation", expectedHash, hashOnAuthFs);
-
- String hashOfBackingFile = computeFileHashOnAndroid(backendPath);
- assertEquals(
- "Inconsistent file hash on the backend storage", hashOnAuthFs, hashOfBackingFile);
- }
-
- private String computeFileHashOnMicrodroid(String path) {
- String result = runOnMicrodroid("sha256sum " + path);
- String[] tokens = result.split("\\s");
- if (tokens.length > 0) {
- return tokens[0];
- } else {
- CLog.e("Unrecognized output by sha256sum: " + result);
- return "";
- }
- }
-
- private boolean copyFileOnMicrodroid(String src, String dest)
- throws DeviceNotAvailableException {
- // TODO(b/182576497): cp returns error because close(2) returns ENOSYS in the current authfs
- // implementation. We should probably fix that since programs can expect close(2) return 0.
- String cmd = "cat " + src + " > " + dest;
- return tryRunOnMicrodroid(cmd) != null;
- }
-
- private String computeFileHashOnAndroid(String path) throws DeviceNotAvailableException {
- String result = sAndroid.run("sha256sum " + path);
- String[] tokens = result.split("\\s");
- if (tokens.length > 0) {
- return tokens[0];
- } else {
- CLog.e("Unrecognized output by sha256sum: " + result);
- return "";
- }
- }
-
- private void resizeFileOnMicrodroid(String path, long size) {
- runOnMicrodroid("truncate -c -s " + size + " " + path);
- }
-
- private long getFileSizeInBytesOnMicrodroid(String path) {
- return Long.parseLong(runOnMicrodroid("stat -c '%s' " + path));
- }
-
- private void runAuthFsOnMicrodroid(String flags) {
- String cmd = AUTHFS_BIN + " " + MOUNT_DIR + " " + flags;
-
- mThreadPool.submit(
- () -> {
- CLog.i("Starting authfs");
- CommandResult result = runOnMicrodroidForResult(cmd);
- CLog.w("authfs has stopped: " + result);
- });
- try {
- PollingCheck.waitFor(
- AUTHFS_INIT_TIMEOUT_MS, () -> isMicrodroidDirectoryOnFuse(MOUNT_DIR));
- } catch (Exception e) {
- // Convert the broad Exception into an unchecked exception to avoid polluting all other
- // methods. waitFor throws Exception because the callback, Callable#call(), has a
- // signature to throw an Exception.
- throw new RuntimeException(e);
- }
- }
-
- private void runFdServerOnAndroid(String execParamsForOpeningFds, String flags)
- throws DeviceNotAvailableException {
- String cmd = "cd " + TEST_DIR + " && exec " + execParamsForOpeningFds + " " + FD_SERVER_BIN
- + " " + flags;
- mThreadPool.submit(
- () -> {
- try {
- CLog.i("Starting fd_server");
- CommandResult result = sAndroid.runForResult(cmd);
- CLog.w("fd_server has stopped: " + result);
- } catch (DeviceNotAvailableException e) {
- CLog.e("Error running fd_server", e);
- throw new RuntimeException(e);
- }
- });
- }
-
- private boolean isMicrodroidDirectoryOnFuse(String path) {
- String fs_type = tryRunOnMicrodroid("stat -f -c '%t' " + path);
- return FUSE_SUPER_MAGIC_HEX.equals(fs_type);
- }
-}
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index d48028e..02fb7e5 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -35,15 +35,8 @@
@Test
public void testMicrodroidBoots() throws Exception {
final String configPath = "assets/vm_config.json"; // path inside the APK
- final String cid =
- startMicrodroid(
- getDevice(),
- getBuild(),
- APK_NAME,
- PACKAGE_NAME,
- configPath,
- /* debug */ false);
- adbConnectToMicrodroid(getDevice(), cid);
+ final String cid = startMicrodroid(APK_NAME, PACKAGE_NAME, configPath, /* debug */ false);
+ adbConnectToMicrodroid(cid);
// Test writing to /data partition
runOnMicrodroid("echo MicrodroidTest > /data/local/tmp/test.txt");
@@ -80,27 +73,26 @@
// Check that keystore was found by the payload
assertThat(runOnMicrodroid("getprop", "debug.microdroid.test.keystore"), is("PASS"));
- shutdownMicrodroid(getDevice(), cid);
+ shutdownMicrodroid(cid);
}
@Test
public void testDebugMode() throws Exception {
final String configPath = "assets/vm_config.json"; // path inside the APK
final boolean debug = true;
- final String cid =
- startMicrodroid(getDevice(), getBuild(), APK_NAME, PACKAGE_NAME, configPath, debug);
- adbConnectToMicrodroid(getDevice(), cid);
+ final String cid = startMicrodroid(APK_NAME, PACKAGE_NAME, configPath, debug);
+ adbConnectToMicrodroid(cid);
assertThat(runOnMicrodroid("getenforce"), is("Permissive"));
- shutdownMicrodroid(getDevice(), cid);
+ shutdownMicrodroid(cid);
}
@Before
public void setUp() throws Exception {
- testIfDeviceIsCapable(getDevice());
+ testIfDeviceIsCapable();
- prepareVirtualizationTestSetup(getDevice());
+ prepareVirtualizationTestSetup();
getDevice().installPackage(findTestFile(APK_NAME), /* reinstall */ false);
@@ -110,7 +102,7 @@
@After
public void shutdown() throws Exception {
- cleanUpVirtualizationTestSetup(getDevice());
+ cleanUpVirtualizationTestSetup();
getDevice().uninstallPackage(PACKAGE_NAME);
}