blob: 2bd896876be3c0f3fe028ae269e95138b012c75f [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 Wang748b0322023-07-24 12:51:18 +000025use anyhow::{anyhow, bail, Context, Result};
David Brazdil66fc1202022-07-04 21:48:45 +010026use log::info;
Alice Wang748b0322023-07-24 12:51:18 +000027use service_vm_comm::{Request, Response};
David Brazdil66fc1202022-07-04 21:48:45 +010028use std::fs::File;
Alice Wang748b0322023-07-24 12:51:18 +000029use std::io::{self, BufRead, BufReader, BufWriter, Write};
David Brazdil66fc1202022-07-04 21:48:45 +010030use std::os::unix::io::FromRawFd;
31use std::panic;
32use std::thread;
Alan Stokesdfca76c2022-08-03 13:31:47 +010033use std::time::Duration;
David Brazdil66fc1202022-07-04 21:48:45 +010034use vmclient::{DeathReason, VmInstance};
Alice Wang4e082c32023-07-11 07:41:50 +000035use vsock::{VsockListener, VMADDR_CID_HOST};
36
37// TODO(b/291732060): Move the port numbers to the common library shared between the host
38// and rialto.
39const PROTECTED_VM_PORT: u32 = 5679;
40const NON_PROTECTED_VM_PORT: u32 = 5680;
David Brazdil66fc1202022-07-04 21:48:45 +010041
Alice Wang9a8b39f2023-04-12 15:31:48 +000042const SIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto.bin";
43const UNSIGNED_RIALTO_PATH: &str = "/data/local/tmp/rialto_test/arm64/rialto_unsigned.bin";
44const INSTANCE_IMG_PATH: &str = "/data/local/tmp/rialto_test/arm64/instance.img";
45const INSTANCE_IMG_SIZE: i64 = 1024 * 1024; // 1MB
David Brazdil66fc1202022-07-04 21:48:45 +010046
David Brazdil66fc1202022-07-04 21:48:45 +010047#[test]
Alice Wang748b0322023-07-24 12:51:18 +000048fn boot_rialto_in_protected_vm_successfully() -> Result<()> {
Alice Wang9a8b39f2023-04-12 15:31:48 +000049 boot_rialto_successfully(
50 SIGNED_RIALTO_PATH,
51 true, // protected_vm
52 )
53}
54
55#[test]
Alice Wang748b0322023-07-24 12:51:18 +000056fn boot_rialto_in_unprotected_vm_successfully() -> Result<()> {
Alice Wang9a8b39f2023-04-12 15:31:48 +000057 boot_rialto_successfully(
58 UNSIGNED_RIALTO_PATH,
59 false, // protected_vm
60 )
61}
62
Alice Wang748b0322023-07-24 12:51:18 +000063fn boot_rialto_successfully(rialto_path: &str, protected_vm: bool) -> Result<()> {
David Brazdil66fc1202022-07-04 21:48:45 +010064 android_logger::init_once(
65 android_logger::Config::default().with_tag("rialto").with_min_level(log::Level::Debug),
66 );
67
68 // Redirect panic messages to logcat.
69 panic::set_hook(Box::new(|panic_info| {
70 log::error!("{}", panic_info);
71 }));
72
73 // We need to start the thread pool for Binder to work properly, especially link_to_death.
74 ProcessState::start_thread_pool();
75
David Brazdil4b4c5102022-12-19 22:56:20 +000076 let virtmgr =
77 vmclient::VirtualizationService::new().context("Failed to spawn VirtualizationService")?;
78 let service = virtmgr.connect().context("Failed to connect to VirtualizationService")?;
79
Alice Wang9a8b39f2023-04-12 15:31:48 +000080 let rialto = File::open(rialto_path).context("Failed to open Rialto kernel binary")?;
David Brazdil66fc1202022-07-04 21:48:45 +010081 let console = android_log_fd()?;
82 let log = android_log_fd()?;
83
Alice Wang9a8b39f2023-04-12 15:31:48 +000084 let disks = if protected_vm {
85 let instance_img = File::options()
86 .create(true)
87 .read(true)
88 .write(true)
89 .truncate(true)
90 .open(INSTANCE_IMG_PATH)?;
91 let instance_img = ParcelFileDescriptor::new(instance_img);
92
93 service
94 .initializeWritablePartition(
95 &instance_img,
96 INSTANCE_IMG_SIZE,
97 PartitionType::ANDROID_VM_INSTANCE,
98 )
99 .context("Failed to initialize instange.img")?;
100 let writable_partitions = vec![Partition {
101 label: "vm-instance".to_owned(),
102 image: Some(instance_img),
103 writable: true,
104 }];
105 vec![DiskImage { image: None, partitions: writable_partitions, writable: true }]
106 } else {
107 vec![]
108 };
109
David Brazdil66fc1202022-07-04 21:48:45 +0100110 let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
Seungjae Yoo62085c02022-08-12 04:44:52 +0000111 name: String::from("RialtoTest"),
David Brazdil66fc1202022-07-04 21:48:45 +0100112 kernel: None,
113 initrd: None,
114 params: None,
115 bootloader: Some(ParcelFileDescriptor::new(rialto)),
Alice Wang9a8b39f2023-04-12 15:31:48 +0000116 disks,
117 protectedVm: protected_vm,
David Brazdil66fc1202022-07-04 21:48:45 +0100118 memoryMib: 300,
David Brazdil7d1e5ec2023-02-06 17:56:29 +0000119 cpuTopology: CpuTopology::ONE_CPU,
David Brazdil66fc1202022-07-04 21:48:45 +0100120 platformVersion: "~1.0".to_string(),
Nikita Ioffe5776f082023-02-10 21:38:26 +0000121 gdbPort: 0, // No gdb
Inseob Kim6ef80972023-07-20 17:23:36 +0900122 ..Default::default()
David Brazdil66fc1202022-07-04 21:48:45 +0100123 });
Jiyong Parke6fb1672023-06-26 16:45:55 +0900124 let vm = VmInstance::create(
125 service.as_ref(),
126 &config,
127 Some(console),
128 /* consoleIn */ None,
129 Some(log),
130 None,
131 )
132 .context("Failed to create VM")?;
David Brazdil66fc1202022-07-04 21:48:45 +0100133
Alice Wang4e082c32023-07-11 07:41:50 +0000134 let port = if protected_vm { PROTECTED_VM_PORT } else { NON_PROTECTED_VM_PORT };
135 let check_socket_handle = thread::spawn(move || try_check_socket_connection(port).unwrap());
136
David Brazdil66fc1202022-07-04 21:48:45 +0100137 vm.start().context("Failed to start VM")?;
138
139 // Wait for VM to finish, and check that it shut down cleanly.
Alan Stokesdfca76c2022-08-03 13:31:47 +0100140 let death_reason = vm
141 .wait_for_death_with_timeout(Duration::from_secs(10))
142 .ok_or_else(|| anyhow!("Timed out waiting for VM exit"))?;
David Brazdil66fc1202022-07-04 21:48:45 +0100143 assert_eq!(death_reason, DeathReason::Shutdown);
144
Alice Wang4e082c32023-07-11 07:41:50 +0000145 match check_socket_handle.join() {
146 Ok(_) => {
147 info!(
148 "Received the echoed message. \
149 The socket connection between the host and the service VM works correctly."
150 )
151 }
152 Err(_) => bail!("The socket connection check failed."),
153 }
David Brazdil66fc1202022-07-04 21:48:45 +0100154 Ok(())
155}
156
157fn android_log_fd() -> io::Result<File> {
158 let (reader_fd, writer_fd) = nix::unistd::pipe()?;
159
160 // SAFETY: These are new FDs with no previous owner.
161 let reader = unsafe { File::from_raw_fd(reader_fd) };
Andrew Walbranae3350d2023-07-21 19:01:18 +0100162 // SAFETY: These are new FDs with no previous owner.
David Brazdil66fc1202022-07-04 21:48:45 +0100163 let writer = unsafe { File::from_raw_fd(writer_fd) };
164
165 thread::spawn(|| {
166 for line in BufReader::new(reader).lines() {
167 info!("{}", line.unwrap());
168 }
169 });
170 Ok(writer)
171}
Alice Wang4e082c32023-07-11 07:41:50 +0000172
Alice Wang748b0322023-07-24 12:51:18 +0000173fn try_check_socket_connection(port: u32) -> Result<()> {
Alice Wang4e082c32023-07-11 07:41:50 +0000174 info!("Setting up the listening socket on port {port}...");
175 let listener = VsockListener::bind_with_cid_port(VMADDR_CID_HOST, port)?;
176 info!("Listening on port {port}...");
177
Alice Wang748b0322023-07-24 12:51:18 +0000178 let mut vsock_stream =
179 listener.incoming().next().ok_or_else(|| anyhow!("Failed to get vsock_stream"))??;
Alice Wang4e082c32023-07-11 07:41:50 +0000180 info!("Accepted connection {:?}", vsock_stream);
Alice Wang4e082c32023-07-11 07:41:50 +0000181 vsock_stream.set_read_timeout(Some(Duration::from_millis(1_000)))?;
Alice Wang4e082c32023-07-11 07:41:50 +0000182
Alice Wang748b0322023-07-24 12:51:18 +0000183 const WRITE_BUFFER_CAPACITY: usize = 512;
184 let mut buffer = BufWriter::with_capacity(WRITE_BUFFER_CAPACITY, vsock_stream.clone());
185
186 // TODO(b/292080257): Test with message longer than the receiver's buffer capacity
187 // 1024 bytes once the guest virtio-vsock driver fixes the credit update in recv().
188 let message = "abc".repeat(166);
189 let request = Request::Reverse(message.as_bytes().to_vec());
190 ciborium::into_writer(&request, &mut buffer)?;
191 buffer.flush()?;
192 info!("Sent request: {request:?}.");
193
194 let response: Response = ciborium::from_reader(&mut vsock_stream)?;
195 info!("Received response: {response:?}.");
196
197 let expected_response: Vec<u8> = message.as_bytes().iter().rev().cloned().collect();
198 assert_eq!(Response::Reverse(expected_response), response);
Alice Wang4e082c32023-07-11 07:41:50 +0000199 Ok(())
200}