Add test to run vmbase example VM.
Bug: 223166344
Test: atest vmbase_example.integration_test
Change-Id: Idef13afb2466a920c1ead9626c81e7a36f6f67c5
diff --git a/vmbase/example/Android.bp b/vmbase/example/Android.bp
index 9c19693..0acef2b 100644
--- a/vmbase/example/Android.bp
+++ b/vmbase/example/Android.bp
@@ -61,3 +61,29 @@
},
},
}
+
+rust_test {
+ name: "vmbase_example.integration_test",
+ crate_name: "vmbase_example_test",
+ srcs: ["tests/test.rs"],
+ prefer_rlib: true,
+ edition: "2021",
+ rustlibs: [
+ "android.system.virtualizationservice-rust",
+ "libanyhow",
+ "libenv_logger",
+ "liblibc",
+ "liblog_rust",
+ "libvmclient",
+ ],
+ data: [
+ ":vmbase_example",
+ ],
+ test_suites: ["general-tests"],
+ enabled: false,
+ target: {
+ android_arm64: {
+ enabled: true,
+ },
+ },
+}
diff --git a/vmbase/example/tests/test.rs b/vmbase/example/tests/test.rs
new file mode 100644
index 0000000..4928846
--- /dev/null
+++ b/vmbase/example/tests/test.rs
@@ -0,0 +1,91 @@
+// Copyright 2022, 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.
+
+//! Integration test for VM bootloader.
+
+use android_system_virtualizationservice::{
+ aidl::android::system::virtualizationservice::{
+ VirtualMachineConfig::VirtualMachineConfig,
+ VirtualMachineRawConfig::VirtualMachineRawConfig,
+ },
+ binder::{ParcelFileDescriptor, ProcessState},
+};
+use anyhow::{Context, Error};
+use log::info;
+use std::{
+ fs::File,
+ io,
+ os::unix::io::{AsRawFd, FromRawFd},
+};
+use vmclient::{DeathReason, VmInstance};
+
+const VMBASE_EXAMPLE_PATH: &str =
+ "/data/local/tmp/vmbase_example.integration_test/arm64/vmbase_example.bin";
+
+/// Runs the vmbase_example VM as an unprotected VM via VirtualizationService.
+#[test]
+fn test_run_example_vm() -> Result<(), Error> {
+ env_logger::init();
+
+ // We need to start the thread pool for Binder to work properly, especially link_to_death.
+ ProcessState::start_thread_pool();
+
+ let service = vmclient::connect().context("Failed to find VirtualizationService")?;
+
+ // Start example VM.
+ let bootloader = ParcelFileDescriptor::new(
+ File::open(VMBASE_EXAMPLE_PATH)
+ .with_context(|| format!("Failed to open VM image {}", VMBASE_EXAMPLE_PATH))?,
+ );
+ let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
+ kernel: None,
+ initrd: None,
+ params: None,
+ bootloader: Some(bootloader),
+ disks: vec![],
+ protectedVm: false,
+ memoryMib: 300,
+ numCpus: 1,
+ cpuAffinity: None,
+ platformVersion: "~1.0".to_string(),
+ taskProfiles: vec![],
+ });
+ let console = duplicate_stdout()?;
+ let log = duplicate_stdout()?;
+ let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log))
+ .context("Failed to create VM")?;
+ vm.start().context("Failed to start VM")?;
+ info!("Started example VM.");
+
+ // Wait for VM to finish, and check that it shut down cleanly.
+ let death_reason = vm.wait_for_death();
+ assert_eq!(death_reason, DeathReason::Shutdown);
+
+ Ok(())
+}
+
+/// Safely duplicate the standard output file descriptor.
+fn duplicate_stdout() -> io::Result<File> {
+ let stdout_fd = io::stdout().as_raw_fd();
+ // Safe because this just duplicates a file descriptor which we know to be valid, and we check
+ // for an error.
+ let dup_fd = unsafe { libc::dup(stdout_fd) };
+ if dup_fd < 0 {
+ Err(io::Error::last_os_error())
+ } else {
+ // Safe because we have just duplicated the file descriptor so we own it, and `from_raw_fd`
+ // takes ownership of it.
+ Ok(unsafe { File::from_raw_fd(dup_fd) })
+ }
+}