blob: 31a0c556db95b6bd5fe9d28f57c7e820e79b3662 [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};
Alice Wang4e082c32023-07-11 07:41:50 +000025use anyhow::{anyhow, bail, Context, Error};
David Brazdil66fc1202022-07-04 21:48:45 +010026use log::info;
27use std::fs::File;
Alice Wang4e082c32023-07-11 07:41:50 +000028use std::io::{self, BufRead, BufReader, Read, Write};
David Brazdil66fc1202022-07-04 21:48:45 +010029use 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};
Alice Wang4e082c32023-07-11 07:41:50 +000034use vsock::{VsockListener, VMADDR_CID_HOST};
35
36// TODO(b/291732060): Move the port numbers to the common library shared between the host
37// and rialto.
38const PROTECTED_VM_PORT: u32 = 5679;
39const NON_PROTECTED_VM_PORT: u32 = 5680;
David Brazdil66fc1202022-07-04 21:48:45 +010040
Alice Wang9a8b39f2023-04-12 15:31:48 +000041const SIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto.bin";
42const UNSIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto_unsigned.bin";
43const INSTANCE_IMG_PATH: &str = "/data/local/tmp/rialto_test/arm64/instance.img";
44const INSTANCE_IMG_SIZE: i64 = 1024 * 1024; // 1MB
David Brazdil66fc1202022-07-04 21:48:45 +010045
David Brazdil66fc1202022-07-04 21:48:45 +010046#[test]
Alice Wang9a8b39f2023-04-12 15:31:48 +000047fn boot_rialto_in_protected_vm_successfully() -> Result<(), Error> {
48 boot_rialto_successfully(
49 SIGNED_RIALTO_PATH,
50 true, // protected_vm
51 )
52}
53
54#[test]
55fn boot_rialto_in_unprotected_vm_successfully() -> Result<(), Error> {
56 boot_rialto_successfully(
57 UNSIGNED_RIALTO_PATH,
58 false, // protected_vm
59 )
60}
61
62fn boot_rialto_successfully(rialto_path: &str, protected_vm: bool) -> Result<(), Error> {
David Brazdil66fc1202022-07-04 21:48:45 +010063 android_logger::init_once(
64 android_logger::Config::default().with_tag("rialto").with_min_level(log::Level::Debug),
65 );
66
67 // Redirect panic messages to logcat.
68 panic::set_hook(Box::new(|panic_info| {
69 log::error!("{}", panic_info);
70 }));
71
72 // We need to start the thread pool for Binder to work properly, especially link_to_death.
73 ProcessState::start_thread_pool();
74
David Brazdil4b4c5102022-12-19 22:56:20 +000075 let virtmgr =
76 vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
77 let service = virtmgr.connect().context("Failed to connect to VirtualizationService")?;
78
Alice Wang9a8b39f2023-04-12 15:31:48 +000079 let rialto = File::open(rialto_path).context("Failed to open Rialto kernel binary")?;
David Brazdil66fc1202022-07-04 21:48:45 +010080 let console = android_log_fd()?;
81 let log = android_log_fd()?;
82
Alice Wang9a8b39f2023-04-12 15:31:48 +000083 let disks = if protected_vm {
84 let instance_img = File::options()
85 .create(true)
86 .read(true)
87 .write(true)
88 .truncate(true)
89 .open(INSTANCE_IMG_PATH)?;
90 let instance_img = ParcelFileDescriptor::new(instance_img);
91
92 service
93 .initializeWritablePartition(
94 &instance_img,
95 INSTANCE_IMG_SIZE,
96 PartitionType::ANDROID_VM_INSTANCE,
97 )
98 .context("Failed to initialize instange.img")?;
99 let writable_partitions = vec![Partition {
100 label: "vm-instance".to_owned(),
101 image: Some(instance_img),
102 writable: true,
103 }];
104 vec![DiskImage { image: None, partitions: writable_partitions, writable: true }]
105 } else {
106 vec![]
107 };
108
David Brazdil66fc1202022-07-04 21:48:45 +0100109 let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
Seungjae Yoo62085c02022-08-12 04:44:52 +0000110 name: String::from("RialtoTest"),
David Brazdil66fc1202022-07-04 21:48:45 +0100111 kernel: None,
112 initrd: None,
113 params: None,
114 bootloader: Some(ParcelFileDescriptor::new(rialto)),
Alice Wang9a8b39f2023-04-12 15:31:48 +0000115 disks,
116 protectedVm: protected_vm,
David Brazdil66fc1202022-07-04 21:48:45 +0100117 memoryMib: 300,
David Brazdil7d1e5ec2023-02-06 17:56:29 +0000118 cpuTopology: CpuTopology::ONE_CPU,
David Brazdil66fc1202022-07-04 21:48:45 +0100119 platformVersion: "~1.0".to_string(),
120 taskProfiles: vec![],
Nikita Ioffe5776f082023-02-10 21:38:26 +0000121 gdbPort: 0, // No gdb
David Brazdil66fc1202022-07-04 21:48:45 +0100122 });
Jiyong Parke6fb1672023-06-26 16:45:55 +0900123 let vm = VmInstance::create(
124 service.as_ref(),
125 &config,
126 Some(console),
127 /* consoleIn */ None,
128 Some(log),
129 None,
130 )
131 .context("Failed to create VM")?;
David Brazdil66fc1202022-07-04 21:48:45 +0100132
Alice Wang4e082c32023-07-11 07:41:50 +0000133 let port = if protected_vm { PROTECTED_VM_PORT } else { NON_PROTECTED_VM_PORT };
134 let check_socket_handle = thread::spawn(move || try_check_socket_connection(port).unwrap());
135
David Brazdil66fc1202022-07-04 21:48:45 +0100136 vm.start().context("Failed to start VM")?;
137
138 // Wait for VM to finish, and check that it shut down cleanly.
Alan Stokesdfca76c2022-08-03 13:31:47 +0100139 let death_reason = vm
140 .wait_for_death_with_timeout(Duration::from_secs(10))
141 .ok_or_else(|| anyhow!("Timed out waiting for VM exit"))?;
David Brazdil66fc1202022-07-04 21:48:45 +0100142 assert_eq!(death_reason, DeathReason::Shutdown);
143
Alice Wang4e082c32023-07-11 07:41:50 +0000144 match check_socket_handle.join() {
145 Ok(_) => {
146 info!(
147 "Received the echoed message. \
148 The socket connection between the host and the service VM works correctly."
149 )
150 }
151 Err(_) => bail!("The socket connection check failed."),
152 }
David Brazdil66fc1202022-07-04 21:48:45 +0100153 Ok(())
154}
155
156fn android_log_fd() -> io::Result<File> {
157 let (reader_fd, writer_fd) = nix::unistd::pipe()?;
158
159 // SAFETY: These are new FDs with no previous owner.
160 let reader = unsafe { File::from_raw_fd(reader_fd) };
161 let writer = unsafe { File::from_raw_fd(writer_fd) };
162
163 thread::spawn(|| {
164 for line in BufReader::new(reader).lines() {
165 info!("{}", line.unwrap());
166 }
167 });
168 Ok(writer)
169}
Alice Wang4e082c32023-07-11 07:41:50 +0000170
171fn try_check_socket_connection(port: u32) -> Result<(), Error> {
172 info!("Setting up the listening socket on port {port}...");
173 let listener = VsockListener::bind_with_cid_port(VMADDR_CID_HOST, port)?;
174 info!("Listening on port {port}...");
175
176 let Some(Ok(mut vsock_stream)) = listener.incoming().next() else {
177 bail!("Failed to get vsock_stream");
178 };
179 info!("Accepted connection {:?}", vsock_stream);
180
181 let message = "Hello from host";
182 vsock_stream.write_all(message.as_bytes())?;
183 vsock_stream.flush()?;
184 info!("Sent message: {:?}.", message);
185
186 let mut buffer = vec![0u8; 30];
187 vsock_stream.set_read_timeout(Some(Duration::from_millis(1_000)))?;
188 let len = vsock_stream.read(&mut buffer)?;
189
190 assert_eq!(message.len(), len);
191 buffer[..len].reverse();
192 assert_eq!(message.as_bytes(), &buffer[..len]);
193 Ok(())
194}