xref: /aosp_15_r20/external/crosvm/src/sys/windows/main.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use std::collections::HashSet;
6 use std::ffi::OsString;
7 use std::fs::OpenOptions;
8 
9 use anyhow::anyhow;
10 use anyhow::Result;
11 use argh::CommandInfo;
12 use argh::FromArgs;
13 use argh::SubCommand;
14 use base::info;
15 use base::syslog;
16 use base::syslog::LogArgs;
17 use base::syslog::LogConfig;
18 use base::FromRawDescriptor;
19 use base::RawDescriptor;
20 use broker_ipc::common_child_setup;
21 use broker_ipc::CommonChildStartupArgs;
22 use crosvm_cli::sys::windows::exit::Exit;
23 use crosvm_cli::sys::windows::exit::ExitContext;
24 use crosvm_cli::sys::windows::exit::ExitContextAnyhow;
25 use metrics::MetricEventType;
26 #[cfg(feature = "slirp")]
27 use net_util::slirp::sys::windows::SlirpStartupConfig;
28 use tube_transporter::TubeToken;
29 use tube_transporter::TubeTransporterReader;
30 use win_util::DllNotificationData;
31 use win_util::DllWatcher;
32 
33 use crate::crosvm::cmdline::RunCommand;
34 use crate::crosvm::sys::cmdline::Commands;
35 use crate::crosvm::sys::cmdline::DeviceSubcommand;
36 use crate::crosvm::sys::cmdline::RunMainCommand;
37 #[cfg(feature = "slirp")]
38 use crate::crosvm::sys::cmdline::RunSlirpCommand;
39 use crate::sys::windows::product::run_metrics;
40 use crate::CommandStatus;
41 use crate::Config;
42 
43 #[cfg(feature = "slirp")]
run_slirp(args: RunSlirpCommand) -> Result<()>44 pub(crate) fn run_slirp(args: RunSlirpCommand) -> Result<()> {
45     let raw_transport_tube = args.bootstrap as RawDescriptor;
46 
47     let tube_transporter =
48         // SAFETY:
49         // Safe because we know that raw_transport_tube is valid (passed by inheritance),
50         // and that the blocking & framing modes are accurate because we create them ourselves
51         // in the broker.
52         unsafe { TubeTransporterReader::from_raw_descriptor(raw_transport_tube) };
53 
54     let mut tube_data_list = tube_transporter
55         .read_tubes()
56         .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
57 
58     let bootstrap_tube = tube_data_list.get_tube(TubeToken::Bootstrap).unwrap();
59 
60     let startup_args: CommonChildStartupArgs =
61         bootstrap_tube.recv::<CommonChildStartupArgs>().unwrap();
62     let _child_cleanup = common_child_setup(startup_args).exit_context(
63         Exit::CommonChildSetupError,
64         "failed to perform common child setup",
65     )?;
66 
67     let slirp_config = bootstrap_tube.recv::<SlirpStartupConfig>().unwrap();
68 
69     #[cfg(feature = "sandbox")]
70     if let Some(mut target) = sandbox::TargetServices::get()
71         .exit_context(Exit::SandboxError, "sandbox operation failed")?
72     {
73         target.lower_token();
74     }
75 
76     net_util::Slirp::run_slirp_process(
77         slirp_config.slirp_pipe,
78         slirp_config.shutdown_event,
79         #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))]
80         slirp_config.slirp_capture_file,
81     );
82     Ok(())
83 }
84 
run_broker_impl(cfg: Config, log_args: LogArgs) -> Result<()>85 pub fn run_broker_impl(cfg: Config, log_args: LogArgs) -> Result<()> {
86     cros_tracing::init();
87     crate::crosvm::sys::windows::broker::run(cfg, log_args)
88 }
89 
90 #[cfg(feature = "sandbox")]
initialize_sandbox() -> Result<()>91 pub fn initialize_sandbox() -> Result<()> {
92     if sandbox::is_sandbox_target() {
93         // Get the TargetServices pointer so that it gets initialized.
94         let _ = sandbox::TargetServices::get()
95             .exit_context(Exit::SandboxError, "sandbox operation failed")?;
96     }
97     Ok(())
98 }
99 
100 #[cfg(feature = "sandbox")]
sandbox_lower_token() -> Result<()>101 pub fn sandbox_lower_token() -> Result<()> {
102     if let Some(mut target) = sandbox::TargetServices::get()
103         .exit_context(Exit::SandboxError, "sandbox operation failed")?
104     {
105         target.lower_token();
106     }
107     Ok(())
108 }
109 
report_dll_loaded(dll_name: String)110 fn report_dll_loaded(dll_name: String) {
111     metrics::log_event(MetricEventType::DllLoaded(dll_name));
112 }
113 
get_library_watcher( ) -> std::io::Result<DllWatcher<impl FnMut(DllNotificationData), impl FnMut(DllNotificationData)>>114 pub fn get_library_watcher(
115 ) -> std::io::Result<DllWatcher<impl FnMut(DllNotificationData), impl FnMut(DllNotificationData)>> {
116     let mut dlls: HashSet<OsString> = HashSet::new();
117     DllWatcher::new(
118         move |data| {
119             info!("DLL loaded: {:?}", data.base_dll_name);
120             if !dlls.insert(data.base_dll_name.clone()) && metrics::is_initialized() {
121                 report_dll_loaded(data.base_dll_name.to_string_lossy().into_owned());
122             }
123         },
124         |data| info!("DLL unloaded: {:?}", data.base_dll_name),
125     )
126 }
127 
start_device(command: DeviceSubcommand) -> Result<()>128 pub(crate) fn start_device(command: DeviceSubcommand) -> Result<()> {
129     Err(anyhow!("unknown device name: {:?}", command))
130 }
131 
run_vm_for_broker(args: RunMainCommand) -> Result<()>132 pub(crate) fn run_vm_for_broker(args: RunMainCommand) -> Result<()> {
133     // This is a noop on unix.
134     #[cfg(feature = "sandbox")]
135     initialize_sandbox()?;
136 
137     let raw_transport_tube = args.bootstrap as RawDescriptor;
138 
139     let exit_state = crate::sys::windows::run_config_for_broker(raw_transport_tube)?;
140     info!("{}", CommandStatus::from(exit_state).message());
141     Ok(())
142 }
143 
cleanup()144 pub(crate) fn cleanup() {
145     // We've already cleaned everything up by waiting for all the vcpu threads on windows.
146     // TODO: b/142733266. When we sandbox each device, have a way to terminate the other sandboxed
147     // processes.
148 }
149 
run_broker(cmd: RunCommand, log_args: LogArgs) -> Result<()>150 fn run_broker(cmd: RunCommand, log_args: LogArgs) -> Result<()> {
151     match TryInto::<Config>::try_into(cmd) {
152         Ok(cfg) => run_broker_impl(cfg, log_args),
153         Err(e) => Err(anyhow!("{}", e)),
154     }
155 }
156 
run_command(cmd: Commands, log_args: LogArgs) -> anyhow::Result<()>157 pub(crate) fn run_command(cmd: Commands, log_args: LogArgs) -> anyhow::Result<()> {
158     match cmd {
159         Commands::RunMetrics(cmd) => run_metrics(cmd),
160         Commands::RunMP(cmd) => run_broker(cmd.run, log_args),
161         Commands::RunMain(cmd) => run_vm_for_broker(cmd),
162         #[cfg(feature = "slirp")]
163         Commands::RunSlirp(cmd) => run_slirp(cmd),
164     }
165 }
166 
init_log(log_config: LogConfig, cfg: &Config) -> Result<()>167 pub(crate) fn init_log(log_config: LogConfig, cfg: &Config) -> Result<()> {
168     if let Err(e) = syslog::init_with(LogConfig {
169         log_args: LogArgs {
170             stderr: cfg.log_file.is_none(),
171             ..log_config.log_args
172         },
173         pipe: if let Some(log_file_path) = &cfg.log_file {
174             let file = OpenOptions::new()
175                 .create(true)
176                 .append(true)
177                 .open(log_file_path)
178                 .with_exit_context(Exit::LogFile, || {
179                     format!("failed to open log file {}", log_file_path)
180                 })?;
181             Some(Box::new(file))
182         } else {
183             None
184         },
185         ..log_config
186     }) {
187         eprintln!("failed to initialize syslog: {}", e);
188         return Err(anyhow!("failed to initialize syslog: {}", e));
189     }
190     Ok(())
191 }
192 
error_to_exit_code(res: &std::result::Result<CommandStatus, anyhow::Error>) -> i32193 pub(crate) fn error_to_exit_code(res: &std::result::Result<CommandStatus, anyhow::Error>) -> i32 {
194     res.to_exit_code().unwrap_or(Exit::UnknownError.into())
195 }
196