Add debug policy tests for ramdump

Bug: 243671509, Bug: 243630590
Test: atest
Change-Id: Id414b6efb1c84bd5d77deb176b40819da9dbdf5d
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index 0d6a9a4..9cb997b 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -65,6 +65,22 @@
     },
 }
 
+// Provide pvmfw.bin binary regardless of the architecture for building test.
+// Note that skipping tests on unsupported device is easy
+// while configuring server configuration to make such tests to run on working
+// devices.
+prebuilt_etc {
+    name: "pvmfw_test",
+    filename: "pvmfw_test.bin",
+    target: {
+        android_arm64: {
+            src: ":pvmfw_bin",
+        },
+    },
+    src: "empty_file",
+    installable: false,
+}
+
 prebuilt_etc {
     name: "pvmfw_embedded_key",
     src: ":avb_testkey_rsa4096_pub_bin",
diff --git a/pvmfw/empty_file b/pvmfw/empty_file
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/pvmfw/empty_file
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 6e0cf5a..046a9d6 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -2,6 +2,26 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
+genrule_defaults {
+    name: "test_avf_debug_policy_overlay",
+    tools: ["dtc"],
+    cmd: "$(location dtc) -I dts -O dtb $(in) -o $(out)",
+}
+
+genrule {
+    name: "test_avf_debug_policy_with_ramdump",
+    defaults: ["test_avf_debug_policy_overlay"],
+    srcs: ["assets/avf_debug_policy_with_ramdump.dts"],
+    out: ["avf_debug_policy_with_ramdump.dtbo"],
+}
+
+genrule {
+    name: "test_avf_debug_policy_without_ramdump",
+    defaults: ["test_avf_debug_policy_overlay"],
+    srcs: ["assets/avf_debug_policy_without_ramdump.dts"],
+    out: ["avf_debug_policy_without_ramdump.dtbo"],
+}
+
 java_test_host {
     name: "MicrodroidHostTestCases",
     srcs: ["java/**/*.java"],
@@ -10,6 +30,7 @@
         "general-tests",
     ],
     libs: [
+        "androidx.annotation_annotation",
         "tradefed",
     ],
     static_libs: [
@@ -23,6 +44,10 @@
         ":microdroid_general_sepolicy.conf",
         ":test.com.android.virt.pem",
         ":test2.com.android.virt.pem",
+        ":pvmfw_test",
+        ":test_avf_debug_policy_with_ramdump",
+        ":test_avf_debug_policy_without_ramdump",
+        "assets/bcc.dat",
     ],
     data_native_bins: [
         "sepolicy-analyze",
diff --git a/tests/hostside/assets/avf_debug_policy_with_ramdump.dts b/tests/hostside/assets/avf_debug_policy_with_ramdump.dts
new file mode 100644
index 0000000..f1a5196
--- /dev/null
+++ b/tests/hostside/assets/avf_debug_policy_with_ramdump.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+    fragment@avf {
+        target-path = "/";
+
+        __overlay__ {
+            avf {
+                guest {
+                    common {
+                        ramdump = <1>;
+                    };
+                };
+            };
+        };
+    };
+};
\ No newline at end of file
diff --git a/tests/hostside/assets/avf_debug_policy_without_ramdump.dts b/tests/hostside/assets/avf_debug_policy_without_ramdump.dts
new file mode 100644
index 0000000..5b15d51
--- /dev/null
+++ b/tests/hostside/assets/avf_debug_policy_without_ramdump.dts
@@ -0,0 +1,18 @@
+/dts-v1/;
+/plugin/;
+
+/ {
+    fragment@avf {
+        target-path = "/";
+
+        __overlay__ {
+            avf {
+                guest {
+                    common {
+                        ramdump = <0>;
+                    };
+                };
+            };
+        };
+    };
+};
\ No newline at end of file
diff --git a/tests/hostside/assets/bcc.dat b/tests/hostside/assets/bcc.dat
new file mode 100644
index 0000000..7ab71f1
--- /dev/null
+++ b/tests/hostside/assets/bcc.dat
Binary files differ
diff --git a/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
new file mode 100644
index 0000000..bda52dd
--- /dev/null
+++ b/tests/hostside/java/com/android/microdroid/test/PvmfwDebugPolicyHostTests.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2023 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 com.android.microdroid.test;
+
+import static com.android.tradefed.device.TestDevice.MicrodroidBuilder;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assume.assumeTrue;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.microdroid.test.host.CommandRunner;
+import com.android.microdroid.test.host.MicrodroidHostTestCaseBase;
+import com.android.microdroid.test.host.Pvmfw;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.TestDevice;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.util.FileUtil;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.util.Objects;
+import java.io.FileNotFoundException;
+
+/** Tests debug policy of pvmfw.bin with custom debug policy */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class PvmfwDebugPolicyHostTests extends MicrodroidHostTestCaseBase {
+    @NonNull private static final String PVMFW_FILE_NAME = "pvmfw_test.bin";
+    @NonNull private static final String BCC_FILE_NAME = "bcc.dat";
+    @NonNull private static final String PACKAGE_FILE_NAME = "MicrodroidTestApp.apk";
+    @NonNull private static final String PACKAGE_NAME = "com.android.microdroid.test";
+    @NonNull private static final String MICRODROID_DEBUG_LEVEL = "full";
+    @NonNull private static final String MICRODROID_CONFIG_PATH = "assets/vm_config_apex.json";
+    private static final int BOOT_COMPLETE_TIMEOUT = 30000; // 30 seconds
+
+    @NonNull private static final String CUSTOM_PVMFW_FILE_PREFIX = "pvmfw";
+    @NonNull private static final String CUSTOM_PVMFW_FILE_SUFFIX = ".bin";
+    @NonNull private static final String CUSTOM_PVMFW_IMG_PATH = TEST_ROOT + "/" + PVMFW_FILE_NAME;
+    @NonNull private static final String CUSTOM_PVMFW_IMG_PATH_PROP = "hypervisor.pvmfw.path";
+
+    @NonNull private static final String MICRODROID_CMDLINE_PATH = "/proc/cmdline";
+    @NonNull private static final String MICRODROID_DT_ROOT_PATH = "/proc/device-tree";
+
+    @NonNull
+    private static final String MICRODROID_DT_BOOTARGS_PATH =
+            MICRODROID_DT_ROOT_PATH + "/chosen/bootargs";
+
+    @NonNull
+    private static final String MICRODROID_DT_RAMDUMP_PATH =
+            MICRODROID_DT_ROOT_PATH + "/avf/guest/common/ramdump";
+
+    @NonNull private static final String HEX_STRING_ZERO = "00000000";
+    @NonNull private static final String HEX_STRING_ONE = "00000001";
+
+    @Nullable private static File mPvmfwBinFileOnHost;
+    @Nullable private static File mBccFileOnHost;
+
+    @Nullable private TestDevice mAndroidDevice;
+    @Nullable private ITestDevice mMicrodroidDevice;
+    @Nullable private File mCustomPvmfwBinFileOnHost;
+
+    @Before
+    public void setUp() throws Exception {
+        mAndroidDevice = (TestDevice) Objects.requireNonNull(getDevice());
+        assumeTrue(
+                "Skip if protected VMs are not supported",
+                mAndroidDevice.supportsMicrodroid(/* protectedVm= */ true));
+
+        mAndroidDevice.enableAdbRoot();
+
+        // tradefed copies the test artfacts under /tmp when running tests,
+        // so we should *find* the artifacts with the file name.
+        mPvmfwBinFileOnHost =
+                getTestInformation().getDependencyFile(PVMFW_FILE_NAME, /* targetFirst= */ false);
+        mBccFileOnHost =
+                getTestInformation().getDependencyFile(BCC_FILE_NAME, /* targetFirst= */ false);
+
+        // Check device capability
+        testIfDeviceIsCapable(mAndroidDevice);
+        assumeTrue(
+                "Protected VMs are not supported",
+                mAndroidDevice.supportsMicrodroid(/*protectedVm=*/ true));
+
+        // Prepare for loading pvmfw.bin
+        // File will be setup in individual test,
+        // and then pushed to device in launchProtectedVmAndWaitForBootCompleted.
+        mCustomPvmfwBinFileOnHost =
+                FileUtil.createTempFile(CUSTOM_PVMFW_FILE_PREFIX, CUSTOM_PVMFW_FILE_SUFFIX);
+        mAndroidDevice.setProperty(CUSTOM_PVMFW_IMG_PATH_PROP, CUSTOM_PVMFW_IMG_PATH);
+
+        // Prepare for launching microdroid
+        mAndroidDevice.installPackage(findTestFile(PACKAGE_FILE_NAME), /* reinstall */ false);
+        prepareVirtualizationTestSetup(mAndroidDevice);
+        mMicrodroidDevice = null;
+    }
+
+    @After
+    public void shutdown() throws Exception {
+        if (!mAndroidDevice.supportsMicrodroid(/* protectedVm= */ true)) {
+            return;
+        }
+        if (mMicrodroidDevice != null) {
+            mAndroidDevice.shutdownMicrodroid(mMicrodroidDevice);
+            mMicrodroidDevice = null;
+        }
+        mAndroidDevice.uninstallPackage(PACKAGE_NAME);
+
+        // Cleanup for custom pvmfw.bin
+        mAndroidDevice.setProperty(CUSTOM_PVMFW_IMG_PATH_PROP, "");
+        FileUtil.deleteFile(mCustomPvmfwBinFileOnHost);
+
+        cleanUpVirtualizationTestSetup(mAndroidDevice);
+
+        mAndroidDevice.disableAdbRoot();
+    }
+
+    @Test
+    public void testRamdump() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_with_ramdump.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+        mMicrodroidDevice = launchProtectedVmAndWaitForBootCompleted();
+
+        assertThat(readMicrodroidFileAsString(MICRODROID_CMDLINE_PATH)).contains("crashkernel=");
+        assertThat(readMicrodroidFileAsString(MICRODROID_DT_BOOTARGS_PATH))
+                .contains("crashkernel=");
+        assertThat(readMicrodroidFileAsHexString(MICRODROID_DT_RAMDUMP_PATH))
+                .isEqualTo(HEX_STRING_ONE);
+    }
+
+    @Test
+    public void testNoRamdump() throws Exception {
+        Pvmfw pvmfw = createPvmfw("avf_debug_policy_without_ramdump.dtbo");
+        pvmfw.serialize(mCustomPvmfwBinFileOnHost);
+        mMicrodroidDevice = launchProtectedVmAndWaitForBootCompleted();
+
+        assertThat(readMicrodroidFileAsString(MICRODROID_CMDLINE_PATH))
+                .doesNotContain("crashkernel=");
+        assertThat(readMicrodroidFileAsString(MICRODROID_DT_BOOTARGS_PATH))
+                .doesNotContain("crashkernel=");
+        assertThat(readMicrodroidFileAsHexString(MICRODROID_DT_RAMDUMP_PATH))
+                .isEqualTo(HEX_STRING_ZERO);
+    }
+
+    @NonNull
+    private String readMicrodroidFileAsString(@NonNull String path)
+            throws DeviceNotAvailableException {
+        return new CommandRunner(mMicrodroidDevice).run("cat", path);
+    }
+
+    @NonNull
+    private String readMicrodroidFileAsHexString(@NonNull String path)
+            throws DeviceNotAvailableException {
+        return new CommandRunner(mMicrodroidDevice).run("xxd", "-p", path);
+    }
+
+    @NonNull
+    private Pvmfw createPvmfw(@NonNull String debugPolicyFileName) throws FileNotFoundException {
+        File file =
+                getTestInformation()
+                        .getDependencyFile(debugPolicyFileName, /* targetFirst= */ false);
+        return new Pvmfw.Builder(mPvmfwBinFileOnHost, mBccFileOnHost)
+                .setDebugPolicyOverlay(file)
+                .build();
+    }
+
+    private ITestDevice launchProtectedVmAndWaitForBootCompleted()
+            throws DeviceNotAvailableException {
+        mMicrodroidDevice =
+                MicrodroidBuilder.fromDevicePath(
+                                getPathForPackage(PACKAGE_NAME), MICRODROID_CONFIG_PATH)
+                        .debugLevel(MICRODROID_DEBUG_LEVEL)
+                        .protectedVm(/* protectedVm= */ true)
+                        .addBootFile(mCustomPvmfwBinFileOnHost, PVMFW_FILE_NAME)
+                        .build(mAndroidDevice);
+        assertThat(mMicrodroidDevice.waitForBootComplete(BOOT_COMPLETE_TIMEOUT)).isTrue();
+        assertThat(mMicrodroidDevice.enableAdbRoot()).isTrue();
+
+        return mMicrodroidDevice;
+    }
+}