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