blob: 49288469e5dac36f100354f03e11fd5c2749c8ec [file] [log] [blame]
Andrew Walbran94bbf2f2022-05-12 18:35:42 +00001// Copyright 2022, The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Integration test for VM bootloader.
16
17use android_system_virtualizationservice::{
18 aidl::android::system::virtualizationservice::{
19 VirtualMachineConfig::VirtualMachineConfig,
20 VirtualMachineRawConfig::VirtualMachineRawConfig,
21 },
22 binder::{ParcelFileDescriptor, ProcessState},
23};
24use anyhow::{Context, Error};
25use log::info;
26use std::{
27 fs::File,
28 io,
29 os::unix::io::{AsRawFd, FromRawFd},
30};
31use vmclient::{DeathReason, VmInstance};
32
33const VMBASE_EXAMPLE_PATH: &str =
34 "/data/local/tmp/vmbase_example.integration_test/arm64/vmbase_example.bin";
35
36/// Runs the vmbase_example VM as an unprotected VM via VirtualizationService.
37#[test]
38fn test_run_example_vm() -> Result<(), Error> {
39 env_logger::init();
40
41 // We need to start the thread pool for Binder to work properly, especially link_to_death.
42 ProcessState::start_thread_pool();
43
44 let service = vmclient::connect().context("Failed to find VirtualizationService")?;
45
46 // Start example VM.
47 let bootloader = ParcelFileDescriptor::new(
48 File::open(VMBASE_EXAMPLE_PATH)
49 .with_context(|| format!("Failed to open VM image {}", VMBASE_EXAMPLE_PATH))?,
50 );
51 let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
52 kernel: None,
53 initrd: None,
54 params: None,
55 bootloader: Some(bootloader),
56 disks: vec![],
57 protectedVm: false,
58 memoryMib: 300,
59 numCpus: 1,
60 cpuAffinity: None,
61 platformVersion: "~1.0".to_string(),
62 taskProfiles: vec![],
63 });
64 let console = duplicate_stdout()?;
65 let log = duplicate_stdout()?;
66 let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log))
67 .context("Failed to create VM")?;
68 vm.start().context("Failed to start VM")?;
69 info!("Started example VM.");
70
71 // Wait for VM to finish, and check that it shut down cleanly.
72 let death_reason = vm.wait_for_death();
73 assert_eq!(death_reason, DeathReason::Shutdown);
74
75 Ok(())
76}
77
78/// Safely duplicate the standard output file descriptor.
79fn duplicate_stdout() -> io::Result<File> {
80 let stdout_fd = io::stdout().as_raw_fd();
81 // Safe because this just duplicates a file descriptor which we know to be valid, and we check
82 // for an error.
83 let dup_fd = unsafe { libc::dup(stdout_fd) };
84 if dup_fd < 0 {
85 Err(io::Error::last_os_error())
86 } else {
87 // Safe because we have just duplicated the file descriptor so we own it, and `from_raw_fd`
88 // takes ownership of it.
89 Ok(unsafe { File::from_raw_fd(dup_fd) })
90 }
91}