blob: cfb0225637fb31f0ec5d72bea3b39cf2f4287fe7 [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::{
David Brazdil7d1e5ec2023-02-06 17:56:29 +000019 CpuTopology::CpuTopology, DiskImage::DiskImage, VirtualMachineConfig::VirtualMachineConfig,
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000020 VirtualMachineRawConfig::VirtualMachineRawConfig,
21 },
22 binder::{ParcelFileDescriptor, ProcessState},
23};
24use anyhow::{Context, Error};
25use log::info;
26use std::{
27 fs::File,
Andrew Walbranb713baa2022-12-07 14:34:49 +000028 io::{self, BufRead, BufReader, Write},
Pierre-Clément Tosi0d1aed02022-11-17 17:06:28 +000029 os::unix::io::FromRawFd,
30 panic, thread,
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000031};
32use vmclient::{DeathReason, VmInstance};
33
34const VMBASE_EXAMPLE_PATH: &str =
35 "/data/local/tmp/vmbase_example.integration_test/arm64/vmbase_example.bin";
Andrew Walbranb713baa2022-12-07 14:34:49 +000036const TEST_DISK_IMAGE_PATH: &str = "/data/local/tmp/vmbase_example.integration_test/test_disk.img";
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000037
38/// Runs the vmbase_example VM as an unprotected VM via VirtualizationService.
39#[test]
40fn test_run_example_vm() -> Result<(), Error> {
Pierre-Clément Tosi0d1aed02022-11-17 17:06:28 +000041 android_logger::init_once(
42 android_logger::Config::default().with_tag("vmbase").with_min_level(log::Level::Debug),
43 );
44
45 // Redirect panic messages to logcat.
46 panic::set_hook(Box::new(|panic_info| {
47 log::error!("{}", panic_info);
48 }));
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000049
50 // We need to start the thread pool for Binder to work properly, especially link_to_death.
51 ProcessState::start_thread_pool();
52
David Brazdil4b4c5102022-12-19 22:56:20 +000053 let virtmgr =
54 vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
55 let service = virtmgr.connect().context("Failed to connect to VirtualizationService")?;
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000056
57 // Start example VM.
58 let bootloader = ParcelFileDescriptor::new(
59 File::open(VMBASE_EXAMPLE_PATH)
60 .with_context(|| format!("Failed to open VM image {}", VMBASE_EXAMPLE_PATH))?,
61 );
Seungjae Yoo62085c02022-08-12 04:44:52 +000062
Andrew Walbranb713baa2022-12-07 14:34:49 +000063 // Make file for test disk image.
64 let mut test_image = File::options()
65 .create(true)
66 .read(true)
67 .write(true)
68 .truncate(true)
69 .open(TEST_DISK_IMAGE_PATH)
70 .with_context(|| format!("Failed to open test disk image {}", TEST_DISK_IMAGE_PATH))?;
71 // Write 4 sectors worth of 4-byte numbers counting up.
72 for i in 0u32..512 {
73 test_image.write_all(&i.to_le_bytes())?;
74 }
75 let test_image = ParcelFileDescriptor::new(test_image);
76 let disk_image = DiskImage { image: Some(test_image), writable: false, partitions: vec![] };
77
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000078 let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
Seungjae Yoo62085c02022-08-12 04:44:52 +000079 name: String::from("VmBaseTest"),
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000080 kernel: None,
81 initrd: None,
82 params: None,
83 bootloader: Some(bootloader),
Andrew Walbranb713baa2022-12-07 14:34:49 +000084 disks: vec![disk_image],
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000085 protectedVm: false,
86 memoryMib: 300,
David Brazdil7d1e5ec2023-02-06 17:56:29 +000087 cpuTopology: CpuTopology::ONE_CPU,
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000088 platformVersion: "~1.0".to_string(),
89 taskProfiles: vec![],
90 });
Pierre-Clément Tosi0d1aed02022-11-17 17:06:28 +000091 let console = android_log_fd()?;
92 let log = android_log_fd()?;
Alan Stokes0e82b502022-08-08 14:44:48 +010093 let vm = VmInstance::create(service.as_ref(), &config, Some(console), Some(log), None)
Andrew Walbran94bbf2f2022-05-12 18:35:42 +000094 .context("Failed to create VM")?;
95 vm.start().context("Failed to start VM")?;
96 info!("Started example VM.");
97
98 // Wait for VM to finish, and check that it shut down cleanly.
99 let death_reason = vm.wait_for_death();
100 assert_eq!(death_reason, DeathReason::Shutdown);
101
102 Ok(())
103}
104
Pierre-Clément Tosi0d1aed02022-11-17 17:06:28 +0000105fn android_log_fd() -> io::Result<File> {
106 let (reader_fd, writer_fd) = nix::unistd::pipe()?;
107
108 // SAFETY: These are new FDs with no previous owner.
109 let reader = unsafe { File::from_raw_fd(reader_fd) };
110 let writer = unsafe { File::from_raw_fd(writer_fd) };
111
112 thread::spawn(|| {
113 for line in BufReader::new(reader).lines() {
114 info!("{}", line.unwrap());
115 }
116 });
117 Ok(writer)
Andrew Walbran94bbf2f2022-05-12 18:35:42 +0000118}