xref: /aosp_15_r20/external/crosvm/e2e_tests/fixture/src/vm.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::env;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::io::Write;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
8*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
9*bb4ee6a4SAndroid Build Coastguard Worker use std::process::Command;
10*bb4ee6a4SAndroid Build Coastguard Worker use std::sync::Once;
11*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration;
12*bb4ee6a4SAndroid Build Coastguard Worker 
13*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
14*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::bail;
15*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Context;
16*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result;
17*bb4ee6a4SAndroid Build Coastguard Worker use base::syslog;
18*bb4ee6a4SAndroid Build Coastguard Worker use base::test_utils::check_can_sudo;
19*bb4ee6a4SAndroid Build Coastguard Worker use crc32fast::hash;
20*bb4ee6a4SAndroid Build Coastguard Worker use delegate::wire_format::DelegateMessage;
21*bb4ee6a4SAndroid Build Coastguard Worker use delegate::wire_format::ExitStatus;
22*bb4ee6a4SAndroid Build Coastguard Worker use delegate::wire_format::GuestToHostMessage;
23*bb4ee6a4SAndroid Build Coastguard Worker use delegate::wire_format::HostToGuestMessage;
24*bb4ee6a4SAndroid Build Coastguard Worker use delegate::wire_format::ProgramExit;
25*bb4ee6a4SAndroid Build Coastguard Worker use log::info;
26*bb4ee6a4SAndroid Build Coastguard Worker use log::Level;
27*bb4ee6a4SAndroid Build Coastguard Worker use prebuilts::download_file;
28*bb4ee6a4SAndroid Build Coastguard Worker use readclock::ClockValues;
29*bb4ee6a4SAndroid Build Coastguard Worker use url::Url;
30*bb4ee6a4SAndroid Build Coastguard Worker 
31*bb4ee6a4SAndroid Build Coastguard Worker use crate::sys::SerialArgs;
32*bb4ee6a4SAndroid Build Coastguard Worker use crate::sys::TestVmSys;
33*bb4ee6a4SAndroid Build Coastguard Worker use crate::utils::run_with_timeout;
34*bb4ee6a4SAndroid Build Coastguard Worker 
35*bb4ee6a4SAndroid Build Coastguard Worker const PREBUILT_URL: &str = "https://storage.googleapis.com/crosvm/integration_tests";
36*bb4ee6a4SAndroid Build Coastguard Worker 
37*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "x86_64")]
38*bb4ee6a4SAndroid Build Coastguard Worker const ARCH: &str = "x86_64";
39*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "arm")]
40*bb4ee6a4SAndroid Build Coastguard Worker const ARCH: &str = "arm";
41*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "aarch64")]
42*bb4ee6a4SAndroid Build Coastguard Worker const ARCH: &str = "aarch64";
43*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(target_arch = "riscv64")]
44*bb4ee6a4SAndroid Build Coastguard Worker const ARCH: &str = "riscv64";
45*bb4ee6a4SAndroid Build Coastguard Worker 
46*bb4ee6a4SAndroid Build Coastguard Worker /// Timeout when waiting for pipes that are expected to be ready.
47*bb4ee6a4SAndroid Build Coastguard Worker const COMMUNICATION_TIMEOUT: Duration = Duration::from_secs(5);
48*bb4ee6a4SAndroid Build Coastguard Worker 
49*bb4ee6a4SAndroid Build Coastguard Worker /// Timeout for the VM to boot and the delegate to report that it's ready.
50*bb4ee6a4SAndroid Build Coastguard Worker const BOOT_TIMEOUT: Duration = Duration::from_secs(60);
51*bb4ee6a4SAndroid Build Coastguard Worker 
52*bb4ee6a4SAndroid Build Coastguard Worker /// Default timeout when waiting for guest commands to execute
53*bb4ee6a4SAndroid Build Coastguard Worker const DEFAULT_COMMAND_TIMEOUT: Duration = Duration::from_secs(10);
54*bb4ee6a4SAndroid Build Coastguard Worker 
prebuilt_version() -> &'static str55*bb4ee6a4SAndroid Build Coastguard Worker fn prebuilt_version() -> &'static str {
56*bb4ee6a4SAndroid Build Coastguard Worker     include_str!("../../guest_under_test/PREBUILT_VERSION").trim()
57*bb4ee6a4SAndroid Build Coastguard Worker }
58*bb4ee6a4SAndroid Build Coastguard Worker 
kernel_prebuilt_url_string() -> Url59*bb4ee6a4SAndroid Build Coastguard Worker fn kernel_prebuilt_url_string() -> Url {
60*bb4ee6a4SAndroid Build Coastguard Worker     Url::parse(&format!(
61*bb4ee6a4SAndroid Build Coastguard Worker         "{}/guest-bzimage-{}-{}",
62*bb4ee6a4SAndroid Build Coastguard Worker         PREBUILT_URL,
63*bb4ee6a4SAndroid Build Coastguard Worker         ARCH,
64*bb4ee6a4SAndroid Build Coastguard Worker         prebuilt_version()
65*bb4ee6a4SAndroid Build Coastguard Worker     ))
66*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap()
67*bb4ee6a4SAndroid Build Coastguard Worker }
68*bb4ee6a4SAndroid Build Coastguard Worker 
rootfs_prebuilt_url_string() -> Url69*bb4ee6a4SAndroid Build Coastguard Worker fn rootfs_prebuilt_url_string() -> Url {
70*bb4ee6a4SAndroid Build Coastguard Worker     Url::parse(&format!(
71*bb4ee6a4SAndroid Build Coastguard Worker         "{}/guest-rootfs-{}-{}",
72*bb4ee6a4SAndroid Build Coastguard Worker         PREBUILT_URL,
73*bb4ee6a4SAndroid Build Coastguard Worker         ARCH,
74*bb4ee6a4SAndroid Build Coastguard Worker         prebuilt_version()
75*bb4ee6a4SAndroid Build Coastguard Worker     ))
76*bb4ee6a4SAndroid Build Coastguard Worker     .unwrap()
77*bb4ee6a4SAndroid Build Coastguard Worker }
78*bb4ee6a4SAndroid Build Coastguard Worker 
local_path_from_url(url: &Url) -> PathBuf79*bb4ee6a4SAndroid Build Coastguard Worker pub(super) fn local_path_from_url(url: &Url) -> PathBuf {
80*bb4ee6a4SAndroid Build Coastguard Worker     if url.scheme() == "file" {
81*bb4ee6a4SAndroid Build Coastguard Worker         return url.to_file_path().unwrap();
82*bb4ee6a4SAndroid Build Coastguard Worker     }
83*bb4ee6a4SAndroid Build Coastguard Worker     if url.scheme() != "http" && url.scheme() != "https" {
84*bb4ee6a4SAndroid Build Coastguard Worker         panic!("Only file, http, https URLs are supported for artifacts")
85*bb4ee6a4SAndroid Build Coastguard Worker     }
86*bb4ee6a4SAndroid Build Coastguard Worker     env::current_exe().unwrap().parent().unwrap().join(format!(
87*bb4ee6a4SAndroid Build Coastguard Worker         "e2e_prebuilt-{:x}-{:x}",
88*bb4ee6a4SAndroid Build Coastguard Worker         hash(url.as_str().as_bytes()),
89*bb4ee6a4SAndroid Build Coastguard Worker         hash(url.path().as_bytes())
90*bb4ee6a4SAndroid Build Coastguard Worker     ))
91*bb4ee6a4SAndroid Build Coastguard Worker }
92*bb4ee6a4SAndroid Build Coastguard Worker 
93*bb4ee6a4SAndroid Build Coastguard Worker /// Represents a command running in the guest. See `TestVm::exec_in_guest_async()`
94*bb4ee6a4SAndroid Build Coastguard Worker #[must_use]
95*bb4ee6a4SAndroid Build Coastguard Worker pub struct GuestProcess {
96*bb4ee6a4SAndroid Build Coastguard Worker     command: String,
97*bb4ee6a4SAndroid Build Coastguard Worker     timeout: Duration,
98*bb4ee6a4SAndroid Build Coastguard Worker }
99*bb4ee6a4SAndroid Build Coastguard Worker 
100*bb4ee6a4SAndroid Build Coastguard Worker impl GuestProcess {
with_timeout(self, duration: Duration) -> Self101*bb4ee6a4SAndroid Build Coastguard Worker     pub fn with_timeout(self, duration: Duration) -> Self {
102*bb4ee6a4SAndroid Build Coastguard Worker         Self {
103*bb4ee6a4SAndroid Build Coastguard Worker             timeout: duration,
104*bb4ee6a4SAndroid Build Coastguard Worker             ..self
105*bb4ee6a4SAndroid Build Coastguard Worker         }
106*bb4ee6a4SAndroid Build Coastguard Worker     }
107*bb4ee6a4SAndroid Build Coastguard Worker 
108*bb4ee6a4SAndroid Build Coastguard Worker     /// Waits for the process to finish execution and return ExitStatus.
109*bb4ee6a4SAndroid Build Coastguard Worker     /// Will fail on a non-zero exit code.
wait_ok(self, vm: &mut TestVm) -> Result<ProgramExit>110*bb4ee6a4SAndroid Build Coastguard Worker     pub fn wait_ok(self, vm: &mut TestVm) -> Result<ProgramExit> {
111*bb4ee6a4SAndroid Build Coastguard Worker         let command = self.command.clone();
112*bb4ee6a4SAndroid Build Coastguard Worker         let result = self.wait_result(vm)?;
113*bb4ee6a4SAndroid Build Coastguard Worker 
114*bb4ee6a4SAndroid Build Coastguard Worker         match &result.exit_status {
115*bb4ee6a4SAndroid Build Coastguard Worker             ExitStatus::Code(0) => Ok(result),
116*bb4ee6a4SAndroid Build Coastguard Worker             ExitStatus::Code(code) => {
117*bb4ee6a4SAndroid Build Coastguard Worker                 bail!("Command `{}` terminated with exit code {}", command, code)
118*bb4ee6a4SAndroid Build Coastguard Worker             }
119*bb4ee6a4SAndroid Build Coastguard Worker             ExitStatus::Signal(code) => bail!("Command `{}` stopped with signal {}", command, code),
120*bb4ee6a4SAndroid Build Coastguard Worker             ExitStatus::None => bail!("Command `{}` stopped for unknown reason", command),
121*bb4ee6a4SAndroid Build Coastguard Worker         }
122*bb4ee6a4SAndroid Build Coastguard Worker     }
123*bb4ee6a4SAndroid Build Coastguard Worker 
124*bb4ee6a4SAndroid Build Coastguard Worker     /// Same as `wait_ok` but will return a ExitStatus instead of failing on a non-zero exit code,
125*bb4ee6a4SAndroid Build Coastguard Worker     /// will only fail when cannot receive output from guest.
wait_result(self, vm: &mut TestVm) -> Result<ProgramExit>126*bb4ee6a4SAndroid Build Coastguard Worker     pub fn wait_result(self, vm: &mut TestVm) -> Result<ProgramExit> {
127*bb4ee6a4SAndroid Build Coastguard Worker         let message = vm.read_message_from_guest(self.timeout).with_context(|| {
128*bb4ee6a4SAndroid Build Coastguard Worker             format!(
129*bb4ee6a4SAndroid Build Coastguard Worker                 "Command `{}`: Failed to read response from guest",
130*bb4ee6a4SAndroid Build Coastguard Worker                 self.command
131*bb4ee6a4SAndroid Build Coastguard Worker             )
132*bb4ee6a4SAndroid Build Coastguard Worker         })?;
133*bb4ee6a4SAndroid Build Coastguard Worker         // VM is ready when receiving any message (as for current protocol)
134*bb4ee6a4SAndroid Build Coastguard Worker         match message {
135*bb4ee6a4SAndroid Build Coastguard Worker             GuestToHostMessage::ProgramExit(exit_info) => Ok(exit_info),
136*bb4ee6a4SAndroid Build Coastguard Worker             _ => bail!("Receive other message when anticipating ProgramExit"),
137*bb4ee6a4SAndroid Build Coastguard Worker         }
138*bb4ee6a4SAndroid Build Coastguard Worker     }
139*bb4ee6a4SAndroid Build Coastguard Worker }
140*bb4ee6a4SAndroid Build Coastguard Worker 
141*bb4ee6a4SAndroid Build Coastguard Worker /// Configuration to start `TestVm`.
142*bb4ee6a4SAndroid Build Coastguard Worker pub struct Config {
143*bb4ee6a4SAndroid Build Coastguard Worker     /// Extra arguments for the `run` subcommand.
144*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) extra_args: Vec<String>,
145*bb4ee6a4SAndroid Build Coastguard Worker 
146*bb4ee6a4SAndroid Build Coastguard Worker     /// Use `O_DIRECT` for the rootfs.
147*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) o_direct: bool,
148*bb4ee6a4SAndroid Build Coastguard Worker 
149*bb4ee6a4SAndroid Build Coastguard Worker     /// Log level of `TestVm`
150*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) log_level: Level,
151*bb4ee6a4SAndroid Build Coastguard Worker 
152*bb4ee6a4SAndroid Build Coastguard Worker     /// File to save crosvm log to
153*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) log_file: Option<String>,
154*bb4ee6a4SAndroid Build Coastguard Worker 
155*bb4ee6a4SAndroid Build Coastguard Worker     /// Wrapper command line for executing `TestVM`
156*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) wrapper_cmd: Option<String>,
157*bb4ee6a4SAndroid Build Coastguard Worker 
158*bb4ee6a4SAndroid Build Coastguard Worker     /// Url to kernel image
159*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) kernel_url: Url,
160*bb4ee6a4SAndroid Build Coastguard Worker 
161*bb4ee6a4SAndroid Build Coastguard Worker     /// Url to initrd image
162*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) initrd_url: Option<Url>,
163*bb4ee6a4SAndroid Build Coastguard Worker 
164*bb4ee6a4SAndroid Build Coastguard Worker     /// Url to rootfs image
165*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) rootfs_url: Option<Url>,
166*bb4ee6a4SAndroid Build Coastguard Worker 
167*bb4ee6a4SAndroid Build Coastguard Worker     /// If rootfs image is writable
168*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) rootfs_rw: bool,
169*bb4ee6a4SAndroid Build Coastguard Worker 
170*bb4ee6a4SAndroid Build Coastguard Worker     /// If rootfs image is zstd compressed
171*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) rootfs_compressed: bool,
172*bb4ee6a4SAndroid Build Coastguard Worker 
173*bb4ee6a4SAndroid Build Coastguard Worker     /// Console hardware type
174*bb4ee6a4SAndroid Build Coastguard Worker     pub(super) console_hardware: String,
175*bb4ee6a4SAndroid Build Coastguard Worker }
176*bb4ee6a4SAndroid Build Coastguard Worker 
177*bb4ee6a4SAndroid Build Coastguard Worker impl Default for Config {
default() -> Self178*bb4ee6a4SAndroid Build Coastguard Worker     fn default() -> Self {
179*bb4ee6a4SAndroid Build Coastguard Worker         Self {
180*bb4ee6a4SAndroid Build Coastguard Worker             log_level: Level::Info,
181*bb4ee6a4SAndroid Build Coastguard Worker             extra_args: Default::default(),
182*bb4ee6a4SAndroid Build Coastguard Worker             o_direct: Default::default(),
183*bb4ee6a4SAndroid Build Coastguard Worker             log_file: None,
184*bb4ee6a4SAndroid Build Coastguard Worker             wrapper_cmd: None,
185*bb4ee6a4SAndroid Build Coastguard Worker             kernel_url: kernel_prebuilt_url_string(),
186*bb4ee6a4SAndroid Build Coastguard Worker             initrd_url: None,
187*bb4ee6a4SAndroid Build Coastguard Worker             rootfs_url: Some(rootfs_prebuilt_url_string()),
188*bb4ee6a4SAndroid Build Coastguard Worker             rootfs_rw: false,
189*bb4ee6a4SAndroid Build Coastguard Worker             rootfs_compressed: false,
190*bb4ee6a4SAndroid Build Coastguard Worker             console_hardware: "virtio-console".to_owned(),
191*bb4ee6a4SAndroid Build Coastguard Worker         }
192*bb4ee6a4SAndroid Build Coastguard Worker     }
193*bb4ee6a4SAndroid Build Coastguard Worker }
194*bb4ee6a4SAndroid Build Coastguard Worker 
195*bb4ee6a4SAndroid Build Coastguard Worker impl Config {
196*bb4ee6a4SAndroid Build Coastguard Worker     /// Creates a new `run` command with `extra_args`.
new() -> Self197*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new() -> Self {
198*bb4ee6a4SAndroid Build Coastguard Worker         Self::from_env()
199*bb4ee6a4SAndroid Build Coastguard Worker     }
200*bb4ee6a4SAndroid Build Coastguard Worker 
201*bb4ee6a4SAndroid Build Coastguard Worker     /// Uses extra arguments for `crosvm run`.
extra_args(mut self, args: Vec<String>) -> Self202*bb4ee6a4SAndroid Build Coastguard Worker     pub fn extra_args(mut self, args: Vec<String>) -> Self {
203*bb4ee6a4SAndroid Build Coastguard Worker         let mut args = args;
204*bb4ee6a4SAndroid Build Coastguard Worker         self.extra_args.append(&mut args);
205*bb4ee6a4SAndroid Build Coastguard Worker         self
206*bb4ee6a4SAndroid Build Coastguard Worker     }
207*bb4ee6a4SAndroid Build Coastguard Worker 
208*bb4ee6a4SAndroid Build Coastguard Worker     /// Uses `O_DIRECT` for the rootfs.
o_direct(mut self) -> Self209*bb4ee6a4SAndroid Build Coastguard Worker     pub fn o_direct(mut self) -> Self {
210*bb4ee6a4SAndroid Build Coastguard Worker         self.o_direct = true;
211*bb4ee6a4SAndroid Build Coastguard Worker         self
212*bb4ee6a4SAndroid Build Coastguard Worker     }
213*bb4ee6a4SAndroid Build Coastguard Worker 
214*bb4ee6a4SAndroid Build Coastguard Worker     /// Uses `disable-sandbox` argument for `crosvm run`.
disable_sandbox(mut self) -> Self215*bb4ee6a4SAndroid Build Coastguard Worker     pub fn disable_sandbox(mut self) -> Self {
216*bb4ee6a4SAndroid Build Coastguard Worker         self.extra_args.push("--disable-sandbox".to_string());
217*bb4ee6a4SAndroid Build Coastguard Worker         self
218*bb4ee6a4SAndroid Build Coastguard Worker     }
219*bb4ee6a4SAndroid Build Coastguard Worker 
from_env() -> Self220*bb4ee6a4SAndroid Build Coastguard Worker     pub fn from_env() -> Self {
221*bb4ee6a4SAndroid Build Coastguard Worker         let mut cfg: Config = Default::default();
222*bb4ee6a4SAndroid Build Coastguard Worker         if let Ok(wrapper_cmd) = env::var("CROSVM_CARGO_TEST_E2E_WRAPPER_CMD") {
223*bb4ee6a4SAndroid Build Coastguard Worker             cfg.wrapper_cmd = Some(wrapper_cmd);
224*bb4ee6a4SAndroid Build Coastguard Worker         }
225*bb4ee6a4SAndroid Build Coastguard Worker         if let Ok(log_file) = env::var("CROSVM_CARGO_TEST_LOG_FILE") {
226*bb4ee6a4SAndroid Build Coastguard Worker             cfg.log_file = Some(log_file);
227*bb4ee6a4SAndroid Build Coastguard Worker         }
228*bb4ee6a4SAndroid Build Coastguard Worker         if env::var("CROSVM_CARGO_TEST_LOG_LEVEL_DEBUG").is_ok() {
229*bb4ee6a4SAndroid Build Coastguard Worker             cfg.log_level = Level::Debug;
230*bb4ee6a4SAndroid Build Coastguard Worker         }
231*bb4ee6a4SAndroid Build Coastguard Worker         if let Ok(kernel_url) = env::var("CROSVM_CARGO_TEST_KERNEL_IMAGE") {
232*bb4ee6a4SAndroid Build Coastguard Worker             info!("Using overrided kernel from env CROSVM_CARGO_TEST_KERNEL_IMAGE={kernel_url}");
233*bb4ee6a4SAndroid Build Coastguard Worker             cfg.kernel_url = Url::from_file_path(kernel_url).unwrap();
234*bb4ee6a4SAndroid Build Coastguard Worker         }
235*bb4ee6a4SAndroid Build Coastguard Worker         if let Ok(initrd_url) = env::var("CROSVM_CARGO_TEST_INITRD_IMAGE") {
236*bb4ee6a4SAndroid Build Coastguard Worker             info!("Using overrided kernel from env CROSVM_CARGO_TEST_INITRD_IMAGE={initrd_url}");
237*bb4ee6a4SAndroid Build Coastguard Worker             cfg.initrd_url = Some(Url::from_file_path(initrd_url).unwrap());
238*bb4ee6a4SAndroid Build Coastguard Worker         }
239*bb4ee6a4SAndroid Build Coastguard Worker         if let Ok(rootfs_url) = env::var("CROSVM_CARGO_TEST_ROOTFS_IMAGE") {
240*bb4ee6a4SAndroid Build Coastguard Worker             info!("Using overrided kernel from env CROSVM_CARGO_TEST_ROOTFS_IMAGE={rootfs_url}");
241*bb4ee6a4SAndroid Build Coastguard Worker             cfg.rootfs_url = Some(Url::from_file_path(rootfs_url).unwrap());
242*bb4ee6a4SAndroid Build Coastguard Worker         }
243*bb4ee6a4SAndroid Build Coastguard Worker         cfg
244*bb4ee6a4SAndroid Build Coastguard Worker     }
245*bb4ee6a4SAndroid Build Coastguard Worker 
with_kernel(mut self, url: &str) -> Self246*bb4ee6a4SAndroid Build Coastguard Worker     pub fn with_kernel(mut self, url: &str) -> Self {
247*bb4ee6a4SAndroid Build Coastguard Worker         self.kernel_url = Url::parse(url).unwrap();
248*bb4ee6a4SAndroid Build Coastguard Worker         self
249*bb4ee6a4SAndroid Build Coastguard Worker     }
250*bb4ee6a4SAndroid Build Coastguard Worker 
with_initrd(mut self, url: &str) -> Self251*bb4ee6a4SAndroid Build Coastguard Worker     pub fn with_initrd(mut self, url: &str) -> Self {
252*bb4ee6a4SAndroid Build Coastguard Worker         self.initrd_url = Some(Url::parse(url).unwrap());
253*bb4ee6a4SAndroid Build Coastguard Worker         self
254*bb4ee6a4SAndroid Build Coastguard Worker     }
255*bb4ee6a4SAndroid Build Coastguard Worker 
with_rootfs(mut self, url: &str) -> Self256*bb4ee6a4SAndroid Build Coastguard Worker     pub fn with_rootfs(mut self, url: &str) -> Self {
257*bb4ee6a4SAndroid Build Coastguard Worker         self.rootfs_url = Some(Url::parse(url).unwrap());
258*bb4ee6a4SAndroid Build Coastguard Worker         self
259*bb4ee6a4SAndroid Build Coastguard Worker     }
260*bb4ee6a4SAndroid Build Coastguard Worker 
rootfs_is_rw(mut self) -> Self261*bb4ee6a4SAndroid Build Coastguard Worker     pub fn rootfs_is_rw(mut self) -> Self {
262*bb4ee6a4SAndroid Build Coastguard Worker         self.rootfs_rw = true;
263*bb4ee6a4SAndroid Build Coastguard Worker         self
264*bb4ee6a4SAndroid Build Coastguard Worker     }
265*bb4ee6a4SAndroid Build Coastguard Worker 
rootfs_is_compressed(mut self) -> Self266*bb4ee6a4SAndroid Build Coastguard Worker     pub fn rootfs_is_compressed(mut self) -> Self {
267*bb4ee6a4SAndroid Build Coastguard Worker         self.rootfs_compressed = true;
268*bb4ee6a4SAndroid Build Coastguard Worker         self
269*bb4ee6a4SAndroid Build Coastguard Worker     }
270*bb4ee6a4SAndroid Build Coastguard Worker 
with_stdout_hardware(mut self, hw_type: &str) -> Self271*bb4ee6a4SAndroid Build Coastguard Worker     pub fn with_stdout_hardware(mut self, hw_type: &str) -> Self {
272*bb4ee6a4SAndroid Build Coastguard Worker         self.console_hardware = hw_type.into();
273*bb4ee6a4SAndroid Build Coastguard Worker         self
274*bb4ee6a4SAndroid Build Coastguard Worker     }
275*bb4ee6a4SAndroid Build Coastguard Worker 
with_vhost_user(mut self, device_type: &str, socket_path: &Path) -> Self276*bb4ee6a4SAndroid Build Coastguard Worker     pub fn with_vhost_user(mut self, device_type: &str, socket_path: &Path) -> Self {
277*bb4ee6a4SAndroid Build Coastguard Worker         self.extra_args.push("--vhost-user".to_string());
278*bb4ee6a4SAndroid Build Coastguard Worker         self.extra_args.push(format!(
279*bb4ee6a4SAndroid Build Coastguard Worker             "{},socket={}",
280*bb4ee6a4SAndroid Build Coastguard Worker             device_type,
281*bb4ee6a4SAndroid Build Coastguard Worker             socket_path.to_str().unwrap()
282*bb4ee6a4SAndroid Build Coastguard Worker         ));
283*bb4ee6a4SAndroid Build Coastguard Worker         self
284*bb4ee6a4SAndroid Build Coastguard Worker     }
285*bb4ee6a4SAndroid Build Coastguard Worker 
286*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(any(target_os = "android", target_os = "linux"))]
with_vhost_user_fs(mut self, socket_path: &Path, tag: &str) -> Self287*bb4ee6a4SAndroid Build Coastguard Worker     pub fn with_vhost_user_fs(mut self, socket_path: &Path, tag: &str) -> Self {
288*bb4ee6a4SAndroid Build Coastguard Worker         self.extra_args.push("--vhost-user-fs".to_string());
289*bb4ee6a4SAndroid Build Coastguard Worker         self.extra_args
290*bb4ee6a4SAndroid Build Coastguard Worker             .push(format!("{},tag={}", socket_path.to_str().unwrap(), tag));
291*bb4ee6a4SAndroid Build Coastguard Worker         self
292*bb4ee6a4SAndroid Build Coastguard Worker     }
293*bb4ee6a4SAndroid Build Coastguard Worker }
294*bb4ee6a4SAndroid Build Coastguard Worker 
295*bb4ee6a4SAndroid Build Coastguard Worker static PREP_ONCE: Once = Once::new();
296*bb4ee6a4SAndroid Build Coastguard Worker 
297*bb4ee6a4SAndroid Build Coastguard Worker /// Test fixture to spin up a VM running a guest that can be communicated with.
298*bb4ee6a4SAndroid Build Coastguard Worker ///
299*bb4ee6a4SAndroid Build Coastguard Worker /// After creation, commands can be sent via exec_in_guest. The VM is stopped
300*bb4ee6a4SAndroid Build Coastguard Worker /// when this instance is dropped.
301*bb4ee6a4SAndroid Build Coastguard Worker pub struct TestVm {
302*bb4ee6a4SAndroid Build Coastguard Worker     // Platform-dependent bits
303*bb4ee6a4SAndroid Build Coastguard Worker     sys: TestVmSys,
304*bb4ee6a4SAndroid Build Coastguard Worker     // The guest is ready to receive a command.
305*bb4ee6a4SAndroid Build Coastguard Worker     ready: bool,
306*bb4ee6a4SAndroid Build Coastguard Worker     // True if commands should be ran with `sudo`.
307*bb4ee6a4SAndroid Build Coastguard Worker     sudo: bool,
308*bb4ee6a4SAndroid Build Coastguard Worker }
309*bb4ee6a4SAndroid Build Coastguard Worker 
310*bb4ee6a4SAndroid Build Coastguard Worker impl TestVm {
311*bb4ee6a4SAndroid Build Coastguard Worker     /// Downloads prebuilts if needed.
initialize_once()312*bb4ee6a4SAndroid Build Coastguard Worker     fn initialize_once() {
313*bb4ee6a4SAndroid Build Coastguard Worker         if let Err(e) = syslog::init() {
314*bb4ee6a4SAndroid Build Coastguard Worker             panic!("failed to initiailize syslog: {}", e);
315*bb4ee6a4SAndroid Build Coastguard Worker         }
316*bb4ee6a4SAndroid Build Coastguard Worker 
317*bb4ee6a4SAndroid Build Coastguard Worker         // It's possible the prebuilts downloaded by crosvm-9999.ebuild differ
318*bb4ee6a4SAndroid Build Coastguard Worker         // from the version that crosvm was compiled for.
319*bb4ee6a4SAndroid Build Coastguard Worker         info!("Prebuilt version to be used: {}", prebuilt_version());
320*bb4ee6a4SAndroid Build Coastguard Worker         if let Ok(value) = env::var("CROSVM_CARGO_TEST_PREBUILT_VERSION") {
321*bb4ee6a4SAndroid Build Coastguard Worker             if value != prebuilt_version() {
322*bb4ee6a4SAndroid Build Coastguard Worker                 panic!(
323*bb4ee6a4SAndroid Build Coastguard Worker                     "Environment provided prebuilts are version {}, but crosvm was compiled \
324*bb4ee6a4SAndroid Build Coastguard Worker                     for prebuilt version {}. Did you update PREBUILT_VERSION everywhere?",
325*bb4ee6a4SAndroid Build Coastguard Worker                     value,
326*bb4ee6a4SAndroid Build Coastguard Worker                     prebuilt_version()
327*bb4ee6a4SAndroid Build Coastguard Worker                 );
328*bb4ee6a4SAndroid Build Coastguard Worker             }
329*bb4ee6a4SAndroid Build Coastguard Worker         }
330*bb4ee6a4SAndroid Build Coastguard Worker     }
331*bb4ee6a4SAndroid Build Coastguard Worker 
initiailize_artifacts(cfg: &Config)332*bb4ee6a4SAndroid Build Coastguard Worker     fn initiailize_artifacts(cfg: &Config) {
333*bb4ee6a4SAndroid Build Coastguard Worker         let kernel_path = local_path_from_url(&cfg.kernel_url);
334*bb4ee6a4SAndroid Build Coastguard Worker         if !kernel_path.exists() && cfg.kernel_url.scheme() != "file" {
335*bb4ee6a4SAndroid Build Coastguard Worker             download_file(cfg.kernel_url.as_str(), &kernel_path).unwrap();
336*bb4ee6a4SAndroid Build Coastguard Worker         }
337*bb4ee6a4SAndroid Build Coastguard Worker         assert!(kernel_path.exists(), "{:?} does not exist", kernel_path);
338*bb4ee6a4SAndroid Build Coastguard Worker 
339*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(initrd_url) = &cfg.initrd_url {
340*bb4ee6a4SAndroid Build Coastguard Worker             let initrd_path = local_path_from_url(initrd_url);
341*bb4ee6a4SAndroid Build Coastguard Worker             if !initrd_path.exists() && initrd_url.scheme() != "file" {
342*bb4ee6a4SAndroid Build Coastguard Worker                 download_file(initrd_url.as_str(), &initrd_path).unwrap();
343*bb4ee6a4SAndroid Build Coastguard Worker             }
344*bb4ee6a4SAndroid Build Coastguard Worker             assert!(initrd_path.exists(), "{:?} does not exist", initrd_path);
345*bb4ee6a4SAndroid Build Coastguard Worker         }
346*bb4ee6a4SAndroid Build Coastguard Worker 
347*bb4ee6a4SAndroid Build Coastguard Worker         if let Some(rootfs_url) = &cfg.rootfs_url {
348*bb4ee6a4SAndroid Build Coastguard Worker             let rootfs_download_path = local_path_from_url(rootfs_url);
349*bb4ee6a4SAndroid Build Coastguard Worker             if !rootfs_download_path.exists() && rootfs_url.scheme() != "file" {
350*bb4ee6a4SAndroid Build Coastguard Worker                 download_file(rootfs_url.as_str(), &rootfs_download_path).unwrap();
351*bb4ee6a4SAndroid Build Coastguard Worker             }
352*bb4ee6a4SAndroid Build Coastguard Worker             assert!(
353*bb4ee6a4SAndroid Build Coastguard Worker                 rootfs_download_path.exists(),
354*bb4ee6a4SAndroid Build Coastguard Worker                 "{:?} does not exist",
355*bb4ee6a4SAndroid Build Coastguard Worker                 rootfs_download_path
356*bb4ee6a4SAndroid Build Coastguard Worker             );
357*bb4ee6a4SAndroid Build Coastguard Worker 
358*bb4ee6a4SAndroid Build Coastguard Worker             if cfg.rootfs_compressed {
359*bb4ee6a4SAndroid Build Coastguard Worker                 let rootfs_raw_path = rootfs_download_path.with_extension("raw");
360*bb4ee6a4SAndroid Build Coastguard Worker                 Command::new("zstd")
361*bb4ee6a4SAndroid Build Coastguard Worker                     .arg("-d")
362*bb4ee6a4SAndroid Build Coastguard Worker                     .arg(&rootfs_download_path)
363*bb4ee6a4SAndroid Build Coastguard Worker                     .arg("-o")
364*bb4ee6a4SAndroid Build Coastguard Worker                     .arg(&rootfs_raw_path)
365*bb4ee6a4SAndroid Build Coastguard Worker                     .arg("-f")
366*bb4ee6a4SAndroid Build Coastguard Worker                     .output()
367*bb4ee6a4SAndroid Build Coastguard Worker                     .expect("Failed to decompress rootfs");
368*bb4ee6a4SAndroid Build Coastguard Worker                 TestVmSys::check_rootfs_file(&rootfs_raw_path);
369*bb4ee6a4SAndroid Build Coastguard Worker             } else {
370*bb4ee6a4SAndroid Build Coastguard Worker                 TestVmSys::check_rootfs_file(&rootfs_download_path);
371*bb4ee6a4SAndroid Build Coastguard Worker             }
372*bb4ee6a4SAndroid Build Coastguard Worker         }
373*bb4ee6a4SAndroid Build Coastguard Worker     }
374*bb4ee6a4SAndroid Build Coastguard Worker 
375*bb4ee6a4SAndroid Build Coastguard Worker     /// Instanciate a new crosvm instance. The first call will trigger the download of prebuilt
376*bb4ee6a4SAndroid Build Coastguard Worker     /// files if necessary.
377*bb4ee6a4SAndroid Build Coastguard Worker     ///
378*bb4ee6a4SAndroid Build Coastguard Worker     /// This generic method takes a `FnOnce` argument which is in charge of completing the `Command`
379*bb4ee6a4SAndroid Build Coastguard Worker     /// with all the relevant options needed to boot the VM.
new_generic<F>(f: F, cfg: Config, sudo: bool) -> Result<TestVm> where F: FnOnce(&mut Command, &SerialArgs, &Config) -> Result<()>,380*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_generic<F>(f: F, cfg: Config, sudo: bool) -> Result<TestVm>
381*bb4ee6a4SAndroid Build Coastguard Worker     where
382*bb4ee6a4SAndroid Build Coastguard Worker         F: FnOnce(&mut Command, &SerialArgs, &Config) -> Result<()>,
383*bb4ee6a4SAndroid Build Coastguard Worker     {
384*bb4ee6a4SAndroid Build Coastguard Worker         PREP_ONCE.call_once(TestVm::initialize_once);
385*bb4ee6a4SAndroid Build Coastguard Worker 
386*bb4ee6a4SAndroid Build Coastguard Worker         TestVm::initiailize_artifacts(&cfg);
387*bb4ee6a4SAndroid Build Coastguard Worker 
388*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = TestVm {
389*bb4ee6a4SAndroid Build Coastguard Worker             sys: TestVmSys::new_generic(f, cfg, sudo).with_context(|| "Could not start crosvm")?,
390*bb4ee6a4SAndroid Build Coastguard Worker             ready: false,
391*bb4ee6a4SAndroid Build Coastguard Worker             sudo,
392*bb4ee6a4SAndroid Build Coastguard Worker         };
393*bb4ee6a4SAndroid Build Coastguard Worker         vm.wait_for_guest_ready(BOOT_TIMEOUT)
394*bb4ee6a4SAndroid Build Coastguard Worker             .with_context(|| "Guest did not become ready after boot")?;
395*bb4ee6a4SAndroid Build Coastguard Worker         Ok(vm)
396*bb4ee6a4SAndroid Build Coastguard Worker     }
397*bb4ee6a4SAndroid Build Coastguard Worker 
new_generic_restore<F>(f: F, cfg: Config, sudo: bool) -> Result<TestVm> where F: FnOnce(&mut Command, &SerialArgs, &Config) -> Result<()>,398*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_generic_restore<F>(f: F, cfg: Config, sudo: bool) -> Result<TestVm>
399*bb4ee6a4SAndroid Build Coastguard Worker     where
400*bb4ee6a4SAndroid Build Coastguard Worker         F: FnOnce(&mut Command, &SerialArgs, &Config) -> Result<()>,
401*bb4ee6a4SAndroid Build Coastguard Worker     {
402*bb4ee6a4SAndroid Build Coastguard Worker         PREP_ONCE.call_once(TestVm::initialize_once);
403*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = TestVm {
404*bb4ee6a4SAndroid Build Coastguard Worker             sys: TestVmSys::new_generic(f, cfg, sudo).with_context(|| "Could not start crosvm")?,
405*bb4ee6a4SAndroid Build Coastguard Worker             ready: false,
406*bb4ee6a4SAndroid Build Coastguard Worker             sudo,
407*bb4ee6a4SAndroid Build Coastguard Worker         };
408*bb4ee6a4SAndroid Build Coastguard Worker         vm.ready = true;
409*bb4ee6a4SAndroid Build Coastguard Worker         // TODO(b/280607404): A cold restored VM cannot respond to cmds from `exec_in_guest_async`.
410*bb4ee6a4SAndroid Build Coastguard Worker         Ok(vm)
411*bb4ee6a4SAndroid Build Coastguard Worker     }
412*bb4ee6a4SAndroid Build Coastguard Worker 
new(cfg: Config) -> Result<TestVm>413*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new(cfg: Config) -> Result<TestVm> {
414*bb4ee6a4SAndroid Build Coastguard Worker         TestVm::new_generic(TestVmSys::append_config_args, cfg, false)
415*bb4ee6a4SAndroid Build Coastguard Worker     }
416*bb4ee6a4SAndroid Build Coastguard Worker 
417*bb4ee6a4SAndroid Build Coastguard Worker     /// Create `TestVm` from a snapshot, using `--restore` but NOT `--suspended`.
new_restore(cfg: Config) -> Result<TestVm>418*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_restore(cfg: Config) -> Result<TestVm> {
419*bb4ee6a4SAndroid Build Coastguard Worker         let mut vm = TestVm::new_generic_restore(TestVmSys::append_config_args, cfg, false)?;
420*bb4ee6a4SAndroid Build Coastguard Worker         // Send a resume request to wait for the restore to finish.
421*bb4ee6a4SAndroid Build Coastguard Worker         // We don't want to return from this function until the restore is complete, otherwise it
422*bb4ee6a4SAndroid Build Coastguard Worker         // will be difficult to differentiate between a slow restore and a slow response from the
423*bb4ee6a4SAndroid Build Coastguard Worker         // guest.
424*bb4ee6a4SAndroid Build Coastguard Worker         let vm = run_with_timeout(
425*bb4ee6a4SAndroid Build Coastguard Worker             move || {
426*bb4ee6a4SAndroid Build Coastguard Worker                 vm.resume_full().expect("failed to resume after VM restore");
427*bb4ee6a4SAndroid Build Coastguard Worker                 vm
428*bb4ee6a4SAndroid Build Coastguard Worker             },
429*bb4ee6a4SAndroid Build Coastguard Worker             Duration::from_secs(60),
430*bb4ee6a4SAndroid Build Coastguard Worker         )
431*bb4ee6a4SAndroid Build Coastguard Worker         .expect("VM restore timeout");
432*bb4ee6a4SAndroid Build Coastguard Worker 
433*bb4ee6a4SAndroid Build Coastguard Worker         Ok(vm)
434*bb4ee6a4SAndroid Build Coastguard Worker     }
435*bb4ee6a4SAndroid Build Coastguard Worker 
436*bb4ee6a4SAndroid Build Coastguard Worker     /// Create `TestVm` from a snapshot, using `--restore` AND `--suspended`.
new_restore_suspended(cfg: Config) -> Result<TestVm>437*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_restore_suspended(cfg: Config) -> Result<TestVm> {
438*bb4ee6a4SAndroid Build Coastguard Worker         TestVm::new_generic_restore(TestVmSys::append_config_args, cfg, false)
439*bb4ee6a4SAndroid Build Coastguard Worker     }
440*bb4ee6a4SAndroid Build Coastguard Worker 
new_sudo(cfg: Config) -> Result<TestVm>441*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_sudo(cfg: Config) -> Result<TestVm> {
442*bb4ee6a4SAndroid Build Coastguard Worker         check_can_sudo();
443*bb4ee6a4SAndroid Build Coastguard Worker 
444*bb4ee6a4SAndroid Build Coastguard Worker         TestVm::new_generic(TestVmSys::append_config_args, cfg, true)
445*bb4ee6a4SAndroid Build Coastguard Worker     }
446*bb4ee6a4SAndroid Build Coastguard Worker 
447*bb4ee6a4SAndroid Build Coastguard Worker     /// Instanciate a new crosvm instance using a configuration file. The first call will trigger
448*bb4ee6a4SAndroid Build Coastguard Worker     /// the download of prebuilt files if necessary.
new_with_config_file(cfg: Config) -> Result<TestVm>449*bb4ee6a4SAndroid Build Coastguard Worker     pub fn new_with_config_file(cfg: Config) -> Result<TestVm> {
450*bb4ee6a4SAndroid Build Coastguard Worker         TestVm::new_generic(TestVmSys::append_config_file_arg, cfg, false)
451*bb4ee6a4SAndroid Build Coastguard Worker     }
452*bb4ee6a4SAndroid Build Coastguard Worker 
453*bb4ee6a4SAndroid Build Coastguard Worker     /// Executes the provided command in the guest.
454*bb4ee6a4SAndroid Build Coastguard Worker     /// Returns command output as Ok(ProgramExit), or an Error if the program did not exit with 0.
exec_in_guest(&mut self, command: &str) -> Result<ProgramExit>455*bb4ee6a4SAndroid Build Coastguard Worker     pub fn exec_in_guest(&mut self, command: &str) -> Result<ProgramExit> {
456*bb4ee6a4SAndroid Build Coastguard Worker         self.exec_in_guest_async(command)?.wait_ok(self)
457*bb4ee6a4SAndroid Build Coastguard Worker     }
458*bb4ee6a4SAndroid Build Coastguard Worker 
459*bb4ee6a4SAndroid Build Coastguard Worker     /// Same as `exec_in_guest` but will return Ok(ProgramExit) instead of failing on a
460*bb4ee6a4SAndroid Build Coastguard Worker     /// non-zero exit code.
exec_in_guest_unchecked(&mut self, command: &str) -> Result<ProgramExit>461*bb4ee6a4SAndroid Build Coastguard Worker     pub fn exec_in_guest_unchecked(&mut self, command: &str) -> Result<ProgramExit> {
462*bb4ee6a4SAndroid Build Coastguard Worker         self.exec_in_guest_async(command)?.wait_result(self)
463*bb4ee6a4SAndroid Build Coastguard Worker     }
464*bb4ee6a4SAndroid Build Coastguard Worker 
465*bb4ee6a4SAndroid Build Coastguard Worker     /// Executes the provided command in the guest asynchronously.
466*bb4ee6a4SAndroid Build Coastguard Worker     /// The command will be run in the guest, but output will not be read until
467*bb4ee6a4SAndroid Build Coastguard Worker     /// GuestProcess::wait_ok() or GuestProcess::wait_result() is called.
exec_in_guest_async(&mut self, command: &str) -> Result<GuestProcess>468*bb4ee6a4SAndroid Build Coastguard Worker     pub fn exec_in_guest_async(&mut self, command: &str) -> Result<GuestProcess> {
469*bb4ee6a4SAndroid Build Coastguard Worker         assert!(self.ready);
470*bb4ee6a4SAndroid Build Coastguard Worker         self.ready = false;
471*bb4ee6a4SAndroid Build Coastguard Worker 
472*bb4ee6a4SAndroid Build Coastguard Worker         // Send command to guest
473*bb4ee6a4SAndroid Build Coastguard Worker         self.write_message_to_guest(
474*bb4ee6a4SAndroid Build Coastguard Worker             &HostToGuestMessage::RunCommand {
475*bb4ee6a4SAndroid Build Coastguard Worker                 command: command.to_owned(),
476*bb4ee6a4SAndroid Build Coastguard Worker             },
477*bb4ee6a4SAndroid Build Coastguard Worker             COMMUNICATION_TIMEOUT,
478*bb4ee6a4SAndroid Build Coastguard Worker         )
479*bb4ee6a4SAndroid Build Coastguard Worker         .with_context(|| format!("Command `{}`: Failed to write to guest pipe", command))?;
480*bb4ee6a4SAndroid Build Coastguard Worker 
481*bb4ee6a4SAndroid Build Coastguard Worker         Ok(GuestProcess {
482*bb4ee6a4SAndroid Build Coastguard Worker             command: command.to_owned(),
483*bb4ee6a4SAndroid Build Coastguard Worker             timeout: DEFAULT_COMMAND_TIMEOUT,
484*bb4ee6a4SAndroid Build Coastguard Worker         })
485*bb4ee6a4SAndroid Build Coastguard Worker     }
486*bb4ee6a4SAndroid Build Coastguard Worker 
487*bb4ee6a4SAndroid Build Coastguard Worker     // Waits for the guest to be ready to receive commands
wait_for_guest_ready(&mut self, timeout: Duration) -> Result<()>488*bb4ee6a4SAndroid Build Coastguard Worker     fn wait_for_guest_ready(&mut self, timeout: Duration) -> Result<()> {
489*bb4ee6a4SAndroid Build Coastguard Worker         assert!(!self.ready);
490*bb4ee6a4SAndroid Build Coastguard Worker         let message: GuestToHostMessage = self.read_message_from_guest(timeout)?;
491*bb4ee6a4SAndroid Build Coastguard Worker         match message {
492*bb4ee6a4SAndroid Build Coastguard Worker             GuestToHostMessage::Ready => {
493*bb4ee6a4SAndroid Build Coastguard Worker                 self.ready = true;
494*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(())
495*bb4ee6a4SAndroid Build Coastguard Worker             }
496*bb4ee6a4SAndroid Build Coastguard Worker             _ => Err(anyhow!("Recevied unexpected data from delegate")),
497*bb4ee6a4SAndroid Build Coastguard Worker         }
498*bb4ee6a4SAndroid Build Coastguard Worker     }
499*bb4ee6a4SAndroid Build Coastguard Worker 
500*bb4ee6a4SAndroid Build Coastguard Worker     /// Reads one line via the `from_guest` pipe from the guest delegate.
read_message_from_guest(&mut self, timeout: Duration) -> Result<GuestToHostMessage>501*bb4ee6a4SAndroid Build Coastguard Worker     fn read_message_from_guest(&mut self, timeout: Duration) -> Result<GuestToHostMessage> {
502*bb4ee6a4SAndroid Build Coastguard Worker         let reader = self.sys.from_guest_reader.clone();
503*bb4ee6a4SAndroid Build Coastguard Worker 
504*bb4ee6a4SAndroid Build Coastguard Worker         let result = run_with_timeout(
505*bb4ee6a4SAndroid Build Coastguard Worker             move || loop {
506*bb4ee6a4SAndroid Build Coastguard Worker                 let message = { reader.lock().unwrap().next() };
507*bb4ee6a4SAndroid Build Coastguard Worker 
508*bb4ee6a4SAndroid Build Coastguard Worker                 if let Some(message_result) = message {
509*bb4ee6a4SAndroid Build Coastguard Worker                     if let Ok(msg) = message_result {
510*bb4ee6a4SAndroid Build Coastguard Worker                         match msg {
511*bb4ee6a4SAndroid Build Coastguard Worker                             DelegateMessage::GuestToHost(guest_to_host) => {
512*bb4ee6a4SAndroid Build Coastguard Worker                                 return Ok(guest_to_host);
513*bb4ee6a4SAndroid Build Coastguard Worker                             }
514*bb4ee6a4SAndroid Build Coastguard Worker                             // Guest will send an echo of the message sent from host, ignore it
515*bb4ee6a4SAndroid Build Coastguard Worker                             DelegateMessage::HostToGuest(_) => {
516*bb4ee6a4SAndroid Build Coastguard Worker                                 continue;
517*bb4ee6a4SAndroid Build Coastguard Worker                             }
518*bb4ee6a4SAndroid Build Coastguard Worker                         }
519*bb4ee6a4SAndroid Build Coastguard Worker                     } else {
520*bb4ee6a4SAndroid Build Coastguard Worker                         bail!(format!(
521*bb4ee6a4SAndroid Build Coastguard Worker                             "Failed to receive message from guest: {:?}",
522*bb4ee6a4SAndroid Build Coastguard Worker                             message_result.unwrap_err()
523*bb4ee6a4SAndroid Build Coastguard Worker                         ))
524*bb4ee6a4SAndroid Build Coastguard Worker                     };
525*bb4ee6a4SAndroid Build Coastguard Worker                 };
526*bb4ee6a4SAndroid Build Coastguard Worker             },
527*bb4ee6a4SAndroid Build Coastguard Worker             timeout,
528*bb4ee6a4SAndroid Build Coastguard Worker         );
529*bb4ee6a4SAndroid Build Coastguard Worker         match result {
530*bb4ee6a4SAndroid Build Coastguard Worker             Ok(x) => {
531*bb4ee6a4SAndroid Build Coastguard Worker                 self.ready = true;
532*bb4ee6a4SAndroid Build Coastguard Worker                 x
533*bb4ee6a4SAndroid Build Coastguard Worker             }
534*bb4ee6a4SAndroid Build Coastguard Worker             Err(x) => Err(x),
535*bb4ee6a4SAndroid Build Coastguard Worker         }
536*bb4ee6a4SAndroid Build Coastguard Worker     }
537*bb4ee6a4SAndroid Build Coastguard Worker 
538*bb4ee6a4SAndroid Build Coastguard Worker     /// Send one line via the `to_guest` pipe to the guest delegate.
write_message_to_guest( &mut self, data: &HostToGuestMessage, timeout: Duration, ) -> Result<()>539*bb4ee6a4SAndroid Build Coastguard Worker     fn write_message_to_guest(
540*bb4ee6a4SAndroid Build Coastguard Worker         &mut self,
541*bb4ee6a4SAndroid Build Coastguard Worker         data: &HostToGuestMessage,
542*bb4ee6a4SAndroid Build Coastguard Worker         timeout: Duration,
543*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<()> {
544*bb4ee6a4SAndroid Build Coastguard Worker         let writer = self.sys.to_guest.clone();
545*bb4ee6a4SAndroid Build Coastguard Worker         let data_str = serde_json::to_string_pretty(&DelegateMessage::HostToGuest(data.clone()))?;
546*bb4ee6a4SAndroid Build Coastguard Worker         run_with_timeout(
547*bb4ee6a4SAndroid Build Coastguard Worker             move || -> Result<()> {
548*bb4ee6a4SAndroid Build Coastguard Worker                 println!("-> {}", &data_str);
549*bb4ee6a4SAndroid Build Coastguard Worker                 {
550*bb4ee6a4SAndroid Build Coastguard Worker                     writeln!(writer.lock().unwrap(), "{}", &data_str)?;
551*bb4ee6a4SAndroid Build Coastguard Worker                 }
552*bb4ee6a4SAndroid Build Coastguard Worker                 Ok(())
553*bb4ee6a4SAndroid Build Coastguard Worker             },
554*bb4ee6a4SAndroid Build Coastguard Worker             timeout,
555*bb4ee6a4SAndroid Build Coastguard Worker         )?
556*bb4ee6a4SAndroid Build Coastguard Worker     }
557*bb4ee6a4SAndroid Build Coastguard Worker 
558*bb4ee6a4SAndroid Build Coastguard Worker     /// Hotplug a tap device.
hotplug_tap(&mut self, tap_name: &str) -> Result<()>559*bb4ee6a4SAndroid Build Coastguard Worker     pub fn hotplug_tap(&mut self, tap_name: &str) -> Result<()> {
560*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
561*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command(
562*bb4ee6a4SAndroid Build Coastguard Worker                 "virtio-net",
563*bb4ee6a4SAndroid Build Coastguard Worker                 vec!["add".to_owned(), tap_name.to_owned()],
564*bb4ee6a4SAndroid Build Coastguard Worker                 self.sudo,
565*bb4ee6a4SAndroid Build Coastguard Worker             )
566*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
567*bb4ee6a4SAndroid Build Coastguard Worker     }
568*bb4ee6a4SAndroid Build Coastguard Worker 
569*bb4ee6a4SAndroid Build Coastguard Worker     /// Remove hotplugged device on bus.
remove_pci_device(&mut self, bus_num: u8) -> Result<()>570*bb4ee6a4SAndroid Build Coastguard Worker     pub fn remove_pci_device(&mut self, bus_num: u8) -> Result<()> {
571*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
572*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command(
573*bb4ee6a4SAndroid Build Coastguard Worker                 "virtio-net",
574*bb4ee6a4SAndroid Build Coastguard Worker                 vec!["remove".to_owned(), bus_num.to_string()],
575*bb4ee6a4SAndroid Build Coastguard Worker                 self.sudo,
576*bb4ee6a4SAndroid Build Coastguard Worker             )
577*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
578*bb4ee6a4SAndroid Build Coastguard Worker     }
579*bb4ee6a4SAndroid Build Coastguard Worker 
stop(&mut self) -> Result<()>580*bb4ee6a4SAndroid Build Coastguard Worker     pub fn stop(&mut self) -> Result<()> {
581*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
582*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command("stop", vec![], self.sudo)
583*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
584*bb4ee6a4SAndroid Build Coastguard Worker     }
585*bb4ee6a4SAndroid Build Coastguard Worker 
suspend(&mut self) -> Result<()>586*bb4ee6a4SAndroid Build Coastguard Worker     pub fn suspend(&mut self) -> Result<()> {
587*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
588*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command("suspend", vec![], self.sudo)
589*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
590*bb4ee6a4SAndroid Build Coastguard Worker     }
591*bb4ee6a4SAndroid Build Coastguard Worker 
suspend_full(&mut self) -> Result<()>592*bb4ee6a4SAndroid Build Coastguard Worker     pub fn suspend_full(&mut self) -> Result<()> {
593*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
594*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command("suspend", vec!["--full".to_string()], self.sudo)
595*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
596*bb4ee6a4SAndroid Build Coastguard Worker     }
597*bb4ee6a4SAndroid Build Coastguard Worker 
resume(&mut self) -> Result<()>598*bb4ee6a4SAndroid Build Coastguard Worker     pub fn resume(&mut self) -> Result<()> {
599*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
600*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command("resume", vec![], self.sudo)
601*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
602*bb4ee6a4SAndroid Build Coastguard Worker     }
603*bb4ee6a4SAndroid Build Coastguard Worker 
resume_full(&mut self) -> Result<()>604*bb4ee6a4SAndroid Build Coastguard Worker     pub fn resume_full(&mut self) -> Result<()> {
605*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
606*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command("resume", vec!["--full".to_string()], self.sudo)
607*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
608*bb4ee6a4SAndroid Build Coastguard Worker     }
609*bb4ee6a4SAndroid Build Coastguard Worker 
disk(&mut self, args: Vec<String>) -> Result<()>610*bb4ee6a4SAndroid Build Coastguard Worker     pub fn disk(&mut self, args: Vec<String>) -> Result<()> {
611*bb4ee6a4SAndroid Build Coastguard Worker         self.sys.crosvm_command("disk", args, self.sudo).map(|_| ())
612*bb4ee6a4SAndroid Build Coastguard Worker     }
613*bb4ee6a4SAndroid Build Coastguard Worker 
snapshot(&mut self, filename: &std::path::Path) -> Result<()>614*bb4ee6a4SAndroid Build Coastguard Worker     pub fn snapshot(&mut self, filename: &std::path::Path) -> Result<()> {
615*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
616*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command(
617*bb4ee6a4SAndroid Build Coastguard Worker                 "snapshot",
618*bb4ee6a4SAndroid Build Coastguard Worker                 vec!["take".to_string(), String::from(filename.to_str().unwrap())],
619*bb4ee6a4SAndroid Build Coastguard Worker                 self.sudo,
620*bb4ee6a4SAndroid Build Coastguard Worker             )
621*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
622*bb4ee6a4SAndroid Build Coastguard Worker     }
623*bb4ee6a4SAndroid Build Coastguard Worker 
624*bb4ee6a4SAndroid Build Coastguard Worker     // No argument is passed in restore as we will always restore snapshot.bkp for testing.
restore(&mut self, filename: &std::path::Path) -> Result<()>625*bb4ee6a4SAndroid Build Coastguard Worker     pub fn restore(&mut self, filename: &std::path::Path) -> Result<()> {
626*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
627*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command(
628*bb4ee6a4SAndroid Build Coastguard Worker                 "snapshot",
629*bb4ee6a4SAndroid Build Coastguard Worker                 vec![
630*bb4ee6a4SAndroid Build Coastguard Worker                     "restore".to_string(),
631*bb4ee6a4SAndroid Build Coastguard Worker                     String::from(filename.to_str().unwrap()),
632*bb4ee6a4SAndroid Build Coastguard Worker                 ],
633*bb4ee6a4SAndroid Build Coastguard Worker                 self.sudo,
634*bb4ee6a4SAndroid Build Coastguard Worker             )
635*bb4ee6a4SAndroid Build Coastguard Worker             .map(|_| ())
636*bb4ee6a4SAndroid Build Coastguard Worker     }
637*bb4ee6a4SAndroid Build Coastguard Worker 
swap_command(&mut self, command: &str) -> Result<Vec<u8>>638*bb4ee6a4SAndroid Build Coastguard Worker     pub fn swap_command(&mut self, command: &str) -> Result<Vec<u8>> {
639*bb4ee6a4SAndroid Build Coastguard Worker         self.sys
640*bb4ee6a4SAndroid Build Coastguard Worker             .crosvm_command("swap", vec![command.to_string()], self.sudo)
641*bb4ee6a4SAndroid Build Coastguard Worker     }
642*bb4ee6a4SAndroid Build Coastguard Worker 
guest_clock_values(&mut self) -> Result<ClockValues>643*bb4ee6a4SAndroid Build Coastguard Worker     pub fn guest_clock_values(&mut self) -> Result<ClockValues> {
644*bb4ee6a4SAndroid Build Coastguard Worker         let output = self
645*bb4ee6a4SAndroid Build Coastguard Worker             .exec_in_guest("readclock")
646*bb4ee6a4SAndroid Build Coastguard Worker             .context("Failed to execute readclock binary")?;
647*bb4ee6a4SAndroid Build Coastguard Worker         serde_json::from_str(&output.stdout).context("Failed to parse result")
648*bb4ee6a4SAndroid Build Coastguard Worker     }
649*bb4ee6a4SAndroid Build Coastguard Worker }
650*bb4ee6a4SAndroid Build Coastguard Worker 
651*bb4ee6a4SAndroid Build Coastguard Worker impl Drop for TestVm {
drop(&mut self)652*bb4ee6a4SAndroid Build Coastguard Worker     fn drop(&mut self) {
653*bb4ee6a4SAndroid Build Coastguard Worker         self.stop().unwrap();
654*bb4ee6a4SAndroid Build Coastguard Worker         let status = self.sys.process.take().unwrap().wait().unwrap();
655*bb4ee6a4SAndroid Build Coastguard Worker         if !status.success() {
656*bb4ee6a4SAndroid Build Coastguard Worker             panic!("VM exited illegally: {}", status);
657*bb4ee6a4SAndroid Build Coastguard Worker         }
658*bb4ee6a4SAndroid Build Coastguard Worker     }
659*bb4ee6a4SAndroid Build Coastguard Worker }
660