1use crate::attach::attach;
5use crate::platform::PlatformServices;
6use fidl_fuchsia_virtualization::{GuestConfig, GuestManagerError, GuestMarker, GuestProxy};
7use guest_cli_args as arguments;
8use std::fmt;
9
10#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
11pub enum LaunchResult {
12 LaunchCompleted,
13 AttachFailed(String),
14 RoutingError(arguments::GuestType),
15 FidlError(String),
16 LaunchFailure(u32),
17}
18
19impl fmt::Display for LaunchResult {
20 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21 match self {
22 LaunchResult::LaunchCompleted => write!(f, "Successfully launched the guest"),
23 LaunchResult::AttachFailed(error) => {
24 write!(f, "Failed to attach to a running guest: {}", error)
25 }
26 LaunchResult::FidlError(error) => write!(f, "Failed FIDL call: {}", error),
27 LaunchResult::LaunchFailure(err) => write!(
28 f,
29 "Failed to launch guest: {:?}",
30 GuestManagerError::from_primitive(*err).expect("expected a valid error")
31 ),
32 LaunchResult::RoutingError(guest_type) => {
33 writeln!(f, "")?;
34 writeln!(f, "Unable to connect to start the guest.")?;
35 writeln!(
36 f,
37 " Ensure you have the guest and core shards available on in your build:"
38 )?;
39 writeln!(f, " fx set ... \\")?;
40 writeln!(f, " --with-base {} \\", guest_type.gn_target_label())?;
41 writeln!(
42 f,
43 " --args='core_realm_shards += [ \"{}\" ]'",
44 guest_type.gn_core_shard_label()
45 )?;
46 writeln!(f, "")
47 }
48 }
49 }
50}
51
52pub async fn handle_launch<P: PlatformServices>(
53 services: &P,
54 args: &arguments::launch_args::LaunchArgs,
55) -> LaunchResult {
56 let config = parse_vmm_args(args);
57 let guest = launch(services, args.guest_type, config).await;
58 if let Err(err) = guest {
59 return err;
60 }
61
62 if !args.detach {
63 if let Err(err) = attach(guest.unwrap(), false).await {
64 return LaunchResult::AttachFailed(format!("{}", err));
65 }
66 }
67
68 LaunchResult::LaunchCompleted
69}
70
71fn parse_vmm_args(arguments: &arguments::launch_args::LaunchArgs) -> GuestConfig {
72 let mut guest_config = GuestConfig::default();
74
75 if !arguments.cmdline_add.is_empty() {
76 guest_config.cmdline_add = Some(arguments.cmdline_add.clone())
77 };
78
79 guest_config.guest_memory = arguments.memory;
80 guest_config.cpus = arguments.cpus;
81 guest_config.default_net = arguments.default_net;
82 guest_config.virtio_balloon = arguments.virtio_balloon;
83 guest_config.virtio_console = arguments.virtio_console;
84 guest_config.virtio_gpu = arguments.virtio_gpu;
85 guest_config.virtio_rng = arguments.virtio_rng;
86 guest_config.virtio_sound = arguments.virtio_sound;
87 guest_config.virtio_sound_input = arguments.virtio_sound_input;
88 guest_config.virtio_vsock = arguments.virtio_vsock;
89 guest_config.virtio_mem = arguments.virtio_mem;
90 guest_config.virtio_mem_region_size = arguments.virtio_mem_region_size;
91 guest_config.virtio_mem_region_alignment = arguments.virtio_mem_region_alignment;
92 guest_config.virtio_mem_block_size = arguments.virtio_mem_block_size;
93
94 guest_config
95}
96
97async fn launch<P: PlatformServices>(
99 services: &P,
100 guest_type: arguments::GuestType,
101 config: GuestConfig,
102) -> Result<GuestProxy, LaunchResult> {
103 let (guest, guest_server_end) = fidl::endpoints::create_proxy::<GuestMarker>();
104
105 println!("Starting {}", guest_type);
106 let manager = services
107 .connect_to_manager(guest_type)
108 .await
109 .map_err(|err| LaunchResult::FidlError(format!("Connect to manager - {}", err)))?;
110
111 match manager.launch(config, guest_server_end).await {
112 Err(fidl::Error::ClientChannelClosed { .. }) => Err(LaunchResult::RoutingError(guest_type)),
113 Err(err) => Err(LaunchResult::FidlError(format!("Send launch message - {}", err))),
114 Ok(launch_result) => match launch_result {
115 Ok(()) => Ok(guest),
116 Err(error) => Err(LaunchResult::LaunchFailure(error.into_primitive())),
117 },
118 }
119}