blob: 2dbd0cb4ecf52158a48ef688dccef030f52719ce [file] [log] [blame]
David Brazdil66fc1202022-07-04 21:48:45 +01001// 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 Rialto.
16
17use android_system_virtualizationservice::{
18 aidl::android::system::virtualizationservice::{
Alice Wang9a8b39f2023-04-12 15:31:48 +000019 CpuTopology::CpuTopology, DiskImage::DiskImage, Partition::Partition,
20 PartitionType::PartitionType, VirtualMachineConfig::VirtualMachineConfig,
David Brazdil66fc1202022-07-04 21:48:45 +010021 VirtualMachineRawConfig::VirtualMachineRawConfig,
22 },
23 binder::{ParcelFileDescriptor, ProcessState},
24};
Alan Stokesdfca76c2022-08-03 13:31:47 +010025use anyhow::{anyhow, Context, Error};
David Brazdil66fc1202022-07-04 21:48:45 +010026use log::info;
27use std::fs::File;
28use std::io::{self, BufRead, BufReader};
29use std::os::unix::io::FromRawFd;
30use std::panic;
31use std::thread;
Alan Stokesdfca76c2022-08-03 13:31:47 +010032use std::time::Duration;
David Brazdil66fc1202022-07-04 21:48:45 +010033use vmclient::{DeathReason, VmInstance};
34
Alice Wang9a8b39f2023-04-12 15:31:48 +000035const SIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto.bin";
36const UNSIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto_unsigned.bin";
37const INSTANCE_IMG_PATH: &str = "/data/local/tmp/rialto_test/arm64/instance.img";
38const INSTANCE_IMG_SIZE: i64 = 1024 * 1024; // 1MB
David Brazdil66fc1202022-07-04 21:48:45 +010039
David Brazdil66fc1202022-07-04 21:48:45 +010040#[test]
Alice Wang9a8b39f2023-04-12 15:31:48 +000041fn boot_rialto_in_protected_vm_successfully() -> Result<(), Error> {
42 boot_rialto_successfully(
43 SIGNED_RIALTO_PATH,
44 true, // protected_vm
45 )
46}
47
48#[test]
49fn boot_rialto_in_unprotected_vm_successfully() -> Result<(), Error> {
50 boot_rialto_successfully(
51 UNSIGNED_RIALTO_PATH,
52 false, // protected_vm
53 )
54}
55
56fn boot_rialto_successfully(rialto_path: &str, protected_vm: bool) -> Result<(), Error> {
David Brazdil66fc1202022-07-04 21:48:45 +010057 android_logger::init_once(
58 android_logger::Config::default().with_tag("rialto").with_min_level(log::Level::Debug),
59 );
60
61 // Redirect panic messages to logcat.
62 panic::set_hook(Box::new(|panic_info| {
63 log::error!("{}", panic_info);
64 }));
65
66 // We need to start the thread pool for Binder to work properly, especially link_to_death.
67 ProcessState::start_thread_pool();
68
David Brazdil4b4c5102022-12-19 22:56:20 +000069 let virtmgr =
70 vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
71 let service = virtmgr.connect().context("Failed to connect to VirtualizationService")?;
72
Alice Wang9a8b39f2023-04-12 15:31:48 +000073 let rialto = File::open(rialto_path).context("Failed to open Rialto kernel binary")?;
David Brazdil66fc1202022-07-04 21:48:45 +010074 let console = android_log_fd()?;
75 let log = android_log_fd()?;
76
Alice Wang9a8b39f2023-04-12 15:31:48 +000077 let disks = if protected_vm {
78 let instance_img = File::options()
79 .create(true)
80 .read(true)
81 .write(true)
82 .truncate(true)
83 .open(INSTANCE_IMG_PATH)?;
84 let instance_img = ParcelFileDescriptor::new(instance_img);
85
86 service
87 .initializeWritablePartition(
88 &instance_img,
89 INSTANCE_IMG_SIZE,
90 PartitionType::ANDROID_VM_INSTANCE,
91 )
92 .context("Failed to initialize instange.img")?;
93 let writable_partitions = vec![Partition {
94 label: "vm-instance".to_owned(),
95 image: Some(instance_img),
96 writable: true,
97 }];
98 vec![DiskImage { image: None, partitions: writable_partitions, writable: true }]
99 } else {
100 vec![]
101 };
102
David Brazdil66fc1202022-07-04 21:48:45 +0100103 let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
Seungjae Yoo62085c02022-08-12 04:44:52 +0000104 name: String::from("RialtoTest"),
David Brazdil66fc1202022-07-04 21:48:45 +0100105 kernel: None,
106 initrd: None,
107 params: None,
108 bootloader: Some(ParcelFileDescriptor::new(rialto)),
Alice Wang9a8b39f2023-04-12 15:31:48 +0000109 disks,
110 protectedVm: protected_vm,
David Brazdil66fc1202022-07-04 21:48:45 +0100111 memoryMib: 300,
David Brazdil7d1e5ec2023-02-06 17:56:29 +0000112 cpuTopology: CpuTopology::ONE_CPU,
David Brazdil66fc1202022-07-04 21:48:45 +0100113 platformVersion: "~1.0".to_string(),
114 taskProfiles: vec![],
Nikita Ioffe5776f082023-02-10 21:38:26 +0000115 gdbPort: 0, // No gdb
David Brazdil66fc1202022-07-04 21:48:45 +0100116 });
Jiyong Parke6fb1672023-06-26 16:45:55 +0900117 let vm = VmInstance::create(
118 service.as_ref(),
119 &config,
120 Some(console),
121 /* consoleIn */ None,
122 Some(log),
123 None,
124 )
125 .context("Failed to create VM")?;
David Brazdil66fc1202022-07-04 21:48:45 +0100126
127 vm.start().context("Failed to start VM")?;
128
129 // Wait for VM to finish, and check that it shut down cleanly.
Alan Stokesdfca76c2022-08-03 13:31:47 +0100130 let death_reason = vm
131 .wait_for_death_with_timeout(Duration::from_secs(10))
132 .ok_or_else(|| anyhow!("Timed out waiting for VM exit"))?;
David Brazdil66fc1202022-07-04 21:48:45 +0100133 assert_eq!(death_reason, DeathReason::Shutdown);
134
135 Ok(())
136}
137
138fn android_log_fd() -> io::Result<File> {
139 let (reader_fd, writer_fd) = nix::unistd::pipe()?;
140
141 // SAFETY: These are new FDs with no previous owner.
142 let reader = unsafe { File::from_raw_fd(reader_fd) };
Andrew Walbranae3350d2023-07-21 19:01:18 +0100143 // SAFETY: These are new FDs with no previous owner.
David Brazdil66fc1202022-07-04 21:48:45 +0100144 let writer = unsafe { File::from_raw_fd(writer_fd) };
145
146 thread::spawn(|| {
147 for line in BufReader::new(reader).lines() {
148 info!("{}", line.unwrap());
149 }
150 });
151 Ok(writer)
152}