Upgraded payload accepted & downgraded rejected
Add Microdroid host tests which re-run Microdroid instance with
upgraded/downgraded payload apk & check the intended behaviour.
Test: Run the added tests.
Bug: 291213394
Change-Id: I1af13fe54b4b41b6f42bae66f0815093780fdff7
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 068d8f9..2eca2fa 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -23,6 +23,7 @@
per_testcase_directory: true,
data: [
":MicrodroidTestApp",
+ ":MicrodroidTestAppUpdated",
":microdroid_general_sepolicy.conf",
":test.com.android.virt.pem",
":test2.com.android.virt.pem",
diff --git a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
index 007f38c..60b7706 100644
--- a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
+++ b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
@@ -31,6 +31,7 @@
import com.android.tradefed.device.TestDevice;
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
import com.android.tradefed.util.FileUtil;
import com.android.tradefed.util.RunUtil;
@@ -49,12 +50,16 @@
public abstract class MicrodroidHostTestCaseBase extends BaseHostJUnit4Test {
protected static final String TEST_ROOT = "/data/local/tmp/virt/";
+ private static final String TRADEFED_TEST_ROOT = "/data/local/tmp/virt/tradefed/";
protected static final String LOG_PATH = TEST_ROOT + "log.txt";
protected static final String CONSOLE_PATH = TEST_ROOT + "console.txt";
+ protected static final String TRADEFED_CONSOLE_PATH = TRADEFED_TEST_ROOT + "console.txt";
private static final int TEST_VM_ADB_PORT = 8000;
private static final String MICRODROID_SERIAL = "localhost:" + TEST_VM_ADB_PORT;
private static final String INSTANCE_IMG = "instance.img";
protected static final String VIRT_APEX = "/apex/com.android.virt/";
+ protected static final String SECRETKEEPER_AIDL =
+ "android.hardware.security.secretkeeper.ISecretkeeper/default";
private static final long MICRODROID_ADB_CONNECT_TIMEOUT_MINUTES = 5;
protected static final long MICRODROID_COMMAND_TIMEOUT_MILLIS = 30000;
@@ -244,6 +249,17 @@
return ret;
}
+ public boolean isUpdatableVmSupported() throws DeviceNotAvailableException {
+ // Updatable VMs are possible iff device supports Secretkeeper.
+ CommandRunner android = new CommandRunner(getDevice());
+ CommandResult result = android.runForResult("service check", SECRETKEEPER_AIDL);
+ assertWithMessage("Failed to run service check. Result= " + result)
+ .that(result.getStatus() == CommandStatus.SUCCESS && result.getExitCode() == 0)
+ .isTrue();
+ boolean is_sk_supported = !result.getStdout().trim().contains("not found");
+ return is_sk_supported;
+ }
+
public List<String> getSupportedOSList() throws Exception {
return parseStringArrayFieldsFromVmInfo("Available OS list: ");
}
diff --git a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
index 06806ec..2b53571 100644
--- a/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
+++ b/tests/hostside/java/com/android/microdroid/test/MicrodroidHostTests.java
@@ -19,12 +19,14 @@
import static com.android.microdroid.test.host.CommandResultSubject.command_results;
import static com.android.tradefed.device.TestDevice.MicrodroidBuilder;
import static com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestLogData;
+import com.android.tradefed.device.DeviceRuntimeException;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
@@ -88,9 +90,12 @@
@UseParametersRunnerFactory(DeviceJUnit4ClassRunnerWithParameters.RunnerFactory.class)
public class MicrodroidHostTests extends MicrodroidHostTestCaseBase {
private static final String APK_NAME = "MicrodroidTestApp.apk";
+ private static final String APK_UPDATED_NAME = "MicrodroidTestAppUpdated.apk";
private static final String PACKAGE_NAME = "com.android.microdroid.test";
private static final String SHELL_PACKAGE_NAME = "com.android.shell";
private static final String VIRT_APEX = "/apex/com.android.virt/";
+ private static final String INSTANCE_IMG = TEST_ROOT + "instance.img";
+ private static final String INSTANCE_ID_FILE = TEST_ROOT + "instance_id";
private static final int MIN_MEM_ARM64 = 170;
private static final int MIN_MEM_X86_64 = 196;
@@ -409,6 +414,67 @@
}
@Test
+ @CddTest
+ public void UpgradedPackageIsAcceptedWithSecretkeeper() throws Exception {
+ assumeUpdatableVmSupported();
+ getDevice().uninstallPackage(PACKAGE_NAME);
+ getDevice().installPackage(findTestFile(APK_NAME), /* reinstall= */ true);
+ ensureMicrodroidBootsSuccessfully(INSTANCE_ID_FILE, INSTANCE_IMG);
+
+ getDevice().uninstallPackage(PACKAGE_NAME);
+ cleanUpVirtualizationTestSetup(getDevice());
+ // Install the updated version of app (versionCode 6)
+ getDevice().installPackage(findTestFile(APK_UPDATED_NAME), /* reinstall= */ true);
+ ensureMicrodroidBootsSuccessfully(INSTANCE_ID_FILE, INSTANCE_IMG);
+ }
+
+ @Test
+ @CddTest
+ public void DowngradedPackageIsRejectedProtectedVm() throws Exception {
+ assumeProtectedVm(); // Rollback protection is provided only for protected VM.
+
+ // Install the upgraded version (v6)
+ getDevice().uninstallPackage(PACKAGE_NAME);
+ getDevice().installPackage(findTestFile(APK_UPDATED_NAME), /* reinstall= */ true);
+ ensureMicrodroidBootsSuccessfully(INSTANCE_ID_FILE, INSTANCE_IMG);
+
+ getDevice().uninstallPackage(PACKAGE_NAME);
+ cleanUpVirtualizationTestSetup(getDevice());
+ // Install the older version (v5)
+ getDevice().installPackage(findTestFile(APK_NAME), /* reinstall= */ true);
+
+ assertThrows(
+ "pVM must fail to boot with downgraded payload apk",
+ DeviceRuntimeException.class,
+ () -> ensureMicrodroidBootsSuccessfully(INSTANCE_ID_FILE, INSTANCE_IMG));
+ }
+
+ private void ensureMicrodroidBootsSuccessfully(String instanceIdPath, String instanceImgPath)
+ throws DeviceNotAvailableException {
+ final String configPath = "assets/vm_config.json";
+ ITestDevice microdroid = null;
+ int timeout = 30000; // 30 seconds
+ try {
+ microdroid =
+ MicrodroidBuilder.fromDevicePath(getPathForPackage(PACKAGE_NAME), configPath)
+ .debugLevel("full")
+ .memoryMib(minMemorySize())
+ .cpuTopology("match_host")
+ .protectedVm(mProtectedVm)
+ .instanceIdFile(instanceIdPath)
+ .instanceImgFile(instanceImgPath)
+ .setAdbConnectTimeoutMs(timeout)
+ .build(getAndroidDevice());
+ assertThat(microdroid.waitForBootComplete(timeout)).isTrue();
+ assertThat(microdroid.enableAdbRoot()).isTrue();
+ } finally {
+ if (microdroid != null) {
+ getAndroidDevice().shutdownMicrodroid(microdroid);
+ }
+ }
+ }
+
+ @Test
@CddTest(requirements = {"9.17/C-2-1", "9.17/C-2-2", "9.17/C-2-6"})
public void protectedVmRunsPvmfw() throws Exception {
// Arrange
@@ -427,7 +493,7 @@
// Assert
mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT);
- String consoleLog = getDevice().pullFileContents(CONSOLE_PATH);
+ String consoleLog = getDevice().pullFileContents(TRADEFED_CONSOLE_PATH);
assertWithMessage("Failed to verify that pvmfw started")
.that(consoleLog)
.contains("pVM firmware");
@@ -1106,7 +1172,7 @@
prepareVirtualizationTestSetup(getDevice());
- getDevice().installPackage(findTestFile(APK_NAME), /* reinstall */ false);
+ getDevice().installPackage(findTestFile(APK_NAME), /* reinstall= */ false);
// Skip test if given device doesn't support protected or non-protected VM.
assumeTrue(
@@ -1159,6 +1225,12 @@
&& device.doesFileExist("/sys/bus/platform/drivers/vfio-platform"));
}
+ private void assumeUpdatableVmSupported() throws DeviceNotAvailableException {
+ assumeTrue(
+ "This test is only applicable if if Updatable VMs are supported",
+ isUpdatableVmSupported());
+ }
+
private TestDevice getAndroidDevice() {
TestDevice androidDevice = (TestDevice) getDevice();
assertThat(androidDevice).isNotNull();
diff --git a/tests/pvmfw/java/com/android/pvmfw/test/CustomPvmfwHostTestCaseBase.java b/tests/pvmfw/java/com/android/pvmfw/test/CustomPvmfwHostTestCaseBase.java
index 541f5ec..563fffd 100644
--- a/tests/pvmfw/java/com/android/pvmfw/test/CustomPvmfwHostTestCaseBase.java
+++ b/tests/pvmfw/java/com/android/pvmfw/test/CustomPvmfwHostTestCaseBase.java
@@ -19,7 +19,6 @@
import static com.android.tradefed.device.TestDevice.MicrodroidBuilder;
import static com.google.common.truth.Truth.assertThat;
-import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assume.assumeTrue;
@@ -27,12 +26,9 @@
import androidx.annotation.Nullable;
import com.android.microdroid.test.host.MicrodroidHostTestCaseBase;
-import com.android.microdroid.test.host.CommandRunner;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.TestDevice;
-import com.android.tradefed.util.CommandResult;
-import com.android.tradefed.util.CommandStatus;
import com.android.tradefed.util.FileUtil;
import org.junit.After;
@@ -65,15 +61,6 @@
@NonNull public static final String CUSTOM_PVMFW_IMG_PATH = TEST_ROOT + PVMFW_FILE_NAME;
@NonNull public static final String CUSTOM_PVMFW_IMG_PATH_PROP = "hypervisor.pvmfw.path";
- @NonNull private static final String DUMPSYS = "dumpsys";
-
- @NonNull
- private static final String DUMPSYS_MISSING_SERVICE_MSG_PREFIX = "Can't find service: ";
-
- @NonNull
- private static final String SECRET_KEEPER_AIDL =
- "android.hardware.security.secretkeeper.ISecretkeeper/default";
-
@Nullable private File mPvmfwBinFileOnHost;
@Nullable private File mBccFileOnHost;
@Nullable private File mVmReferenceDtFile;
@@ -100,23 +87,7 @@
// This is prepared by AndroidTest.xml
mVmReferenceDtFile = mAndroidDevice.pullFile(VM_REFERENCE_DT_PATH);
- CommandRunner runner = new CommandRunner(mAndroidDevice);
- CommandResult result = runner.runForResult(DUMPSYS, SECRET_KEEPER_AIDL);
-
- // dumpsys prints 'Can't find service: ~' to stderr if secret keeper HAL is missing,
- // but it doesn't return any error code for it.
- // Read stderr to know whether secret keeper is supported, and stop test for any other case.
- assertWithMessage("Failed to run " + DUMPSYS + ", result=" + result)
- .that(result.getStatus() == CommandStatus.SUCCESS && result.getExitCode() == 0)
- .isTrue();
- if (result.getStderr() != null && !result.getStderr().trim().isEmpty()) {
- assertWithMessage(
- "Unexpected stderr from " + DUMPSYS + ", stderr=" + result.getStderr())
- .that(result.getStderr().trim().startsWith(DUMPSYS_MISSING_SERVICE_MSG_PREFIX))
- .isTrue();
- } else {
- mSecretKeeperSupported = true;
- }
+ mSecretKeeperSupported = isUpdatableVmSupported();
// Prepare for system properties for custom pvmfw.img.
// File will be prepared later in individual test and then pushed to device
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 84bf098..471aea7 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -33,10 +33,10 @@
compile_multilib: "both",
}
-android_test {
- name: "MicrodroidTestApp",
- defaults: ["MicrodroidTestAppsDefaults"],
+java_defaults {
+ name: "MicrodroidVersionsTestAppDefaults",
srcs: ["src/java/**/*.java"],
+ defaults: ["MicrodroidTestAppsDefaults"],
static_libs: [
"MicrodroidDeviceTestHelper",
"VmAttestationTestUtil",
@@ -58,14 +58,27 @@
"libvm_attestation_test_payload",
],
min_sdk_version: "33",
+}
+
+android_test {
+ name: "MicrodroidTestApp",
+ defaults: ["MicrodroidVersionsTestAppDefaults"],
+ manifest: "AndroidManifestV5.xml",
// Defined in ../vmshareapp/Android.bp
data: [
+ ":MicrodroidTestAppUpdated",
":MicrodroidVmShareApp",
":test_microdroid_vendor_image",
":test_microdroid_vendor_image_unsigned",
],
}
+android_test_helper_app {
+ name: "MicrodroidTestAppUpdated",
+ defaults: ["MicrodroidVersionsTestAppDefaults"],
+ manifest: "AndroidManifestV6.xml",
+}
+
// Defaults shared between MicrodroidTestNativeLib and MicrodroidPayloadInOtherAppNativeLib shared
// libs. They are expected to share everything apart from the name, so that one app
// (MicrodroidTestApp) can start a payload defined in the another app (MicrodroidVmShareApp).
diff --git a/tests/testapk/AndroidManifest.xml b/tests/testapk/AndroidManifestV5.xml
similarity index 94%
copy from tests/testapk/AndroidManifest.xml
copy to tests/testapk/AndroidManifestV5.xml
index d6e6004..7d97680 100644
--- a/tests/testapk/AndroidManifest.xml
+++ b/tests/testapk/AndroidManifestV5.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.microdroid.test">
+ package="com.android.microdroid.test"
+ android:versionCode="5">
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
<uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />
diff --git a/tests/testapk/AndroidManifest.xml b/tests/testapk/AndroidManifestV6.xml
similarity index 94%
rename from tests/testapk/AndroidManifest.xml
rename to tests/testapk/AndroidManifestV6.xml
index d6e6004..19d5674 100644
--- a/tests/testapk/AndroidManifest.xml
+++ b/tests/testapk/AndroidManifestV6.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.microdroid.test">
+ package="com.android.microdroid.test"
+ android:versionCode="6">
<uses-permission android:name="android.permission.MANAGE_VIRTUAL_MACHINE" />
<uses-permission android:name="android.permission.USE_CUSTOM_VIRTUAL_MACHINE" />
<uses-sdk android:minSdkVersion="33" android:targetSdkVersion="33" />