xref: /aosp_15_r20/external/crosvm/src/crosvm/sys/windows/broker.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 //! Contains the multi-process broker for crosvm. This is a work in progress, and some example
6 //! structs here are dead code.
7 #![allow(dead_code)]
8 use std::boxed::Box;
9 use std::collections::HashMap;
10 use std::env::current_exe;
11 use std::ffi::OsStr;
12 use std::fmt;
13 use std::fmt::Debug;
14 use std::fmt::Display;
15 use std::fmt::Formatter;
16 use std::fs::OpenOptions;
17 use std::os::windows::io::AsRawHandle;
18 use std::os::windows::io::RawHandle;
19 use std::path::Path;
20 use std::path::PathBuf;
21 use std::process;
22 use std::process::Command;
23 use std::time::Duration;
24 
25 use anyhow::anyhow;
26 use anyhow::Context;
27 use anyhow::Result;
28 use base::enable_high_res_timers;
29 use base::error;
30 use base::generate_uuid;
31 use base::info;
32 use base::named_pipes;
33 use base::syslog;
34 use base::syslog::LogArgs;
35 use base::syslog::LogConfig;
36 use base::warn;
37 use base::AsRawDescriptor;
38 use base::BlockingMode;
39 use base::Descriptor;
40 use base::DuplicateHandleRequest;
41 use base::DuplicateHandleResponse;
42 use base::Event;
43 use base::EventToken;
44 use base::FramingMode;
45 use base::RawDescriptor;
46 use base::ReadNotifier;
47 use base::RecvTube;
48 use base::SafeDescriptor;
49 use base::SendTube;
50 #[cfg(feature = "gpu")]
51 use base::StreamChannel;
52 use base::Timer;
53 use base::TimerTrait;
54 use base::Tube;
55 use base::WaitContext;
56 #[cfg(feature = "process-invariants")]
57 use broker_ipc::init_broker_process_invariants;
58 use broker_ipc::CommonChildStartupArgs;
59 #[cfg(feature = "process-invariants")]
60 use broker_ipc::EmulatorProcessInvariants;
61 #[cfg(feature = "crash-report")]
62 use crash_report::product_type;
63 #[cfg(feature = "crash-report")]
64 use crash_report::CrashReportAttributes;
65 use crosvm_cli::bail_exit_code;
66 use crosvm_cli::ensure_exit_code;
67 use crosvm_cli::sys::windows::exit::to_process_type_error;
68 use crosvm_cli::sys::windows::exit::Exit;
69 use crosvm_cli::sys::windows::exit::ExitCode;
70 use crosvm_cli::sys::windows::exit::ExitCodeWrapper;
71 use crosvm_cli::sys::windows::exit::ExitContext;
72 use crosvm_cli::sys::windows::exit::ExitContextAnyhow;
73 #[cfg(feature = "audio")]
74 use devices::virtio::gpu::AudioDeviceMode;
75 #[cfg(feature = "audio")]
76 use devices::virtio::snd::parameters::Parameters as SndParameters;
77 #[cfg(feature = "gpu")]
78 use devices::virtio::vhost::user::device::gpu::sys::windows::GpuBackendConfig;
79 #[cfg(feature = "gpu")]
80 use devices::virtio::vhost::user::device::gpu::sys::windows::GpuVmmConfig;
81 #[cfg(feature = "gpu")]
82 use devices::virtio::vhost::user::device::gpu::sys::windows::InputEventBackendConfig;
83 #[cfg(feature = "gpu")]
84 use devices::virtio::vhost::user::device::gpu::sys::windows::InputEventSplitConfig;
85 #[cfg(feature = "gpu")]
86 use devices::virtio::vhost::user::device::gpu::sys::windows::InputEventVmmConfig;
87 #[cfg(feature = "gpu")]
88 use devices::virtio::vhost::user::device::gpu::sys::windows::WindowProcedureThreadSplitConfig;
89 #[cfg(feature = "gpu")]
90 use devices::virtio::vhost::user::device::gpu::sys::windows::WindowProcedureThreadVmmConfig;
91 #[cfg(feature = "audio")]
92 use devices::virtio::vhost::user::device::snd::sys::windows::SndBackendConfig;
93 #[cfg(feature = "audio")]
94 use devices::virtio::vhost::user::device::snd::sys::windows::SndSplitConfig;
95 #[cfg(feature = "audio")]
96 use devices::virtio::vhost::user::device::snd::sys::windows::SndVmmConfig;
97 #[cfg(feature = "net")]
98 use devices::virtio::vhost::user::device::NetBackendConfig;
99 use devices::virtio::DeviceType;
100 #[cfg(feature = "gpu")]
101 use gpu_display::EventDevice;
102 #[cfg(feature = "gpu")]
103 use gpu_display::WindowProcedureThread;
104 #[cfg(feature = "gpu")]
105 use gpu_display::WindowProcedureThreadBuilder;
106 use metrics::MetricEventType;
107 #[cfg(all(feature = "net", feature = "slirp"))]
108 use net_util::slirp::sys::windows::SlirpStartupConfig;
109 #[cfg(all(feature = "net", feature = "slirp"))]
110 use net_util::slirp::sys::windows::SLIRP_BUFFER_SIZE;
111 use serde::Deserialize;
112 use serde::Serialize;
113 use tube_transporter::TubeToken;
114 use tube_transporter::TubeTransferData;
115 use tube_transporter::TubeTransporter;
116 use win_util::get_exit_code_process;
117 use win_util::ProcessType;
118 use winapi::shared::winerror::ERROR_ACCESS_DENIED;
119 use winapi::um::processthreadsapi::TerminateProcess;
120 
121 use crate::crosvm::config::InputDeviceOption;
122 #[cfg(feature = "gpu")]
123 use crate::sys::windows::get_gpu_product_configs;
124 #[cfg(feature = "audio")]
125 use crate::sys::windows::get_snd_product_configs;
126 #[cfg(feature = "gpu")]
127 use crate::sys::windows::get_window_procedure_thread_product_configs;
128 #[cfg(feature = "audio")]
129 use crate::sys::windows::num_input_sound_devices;
130 #[cfg(feature = "audio")]
131 use crate::sys::windows::num_input_sound_streams;
132 use crate::Config;
133 
134 const KILL_CHILD_EXIT_CODE: u32 = 1;
135 
136 /// Tubes created by the broker and sent to child processes via the bootstrap tube.
137 #[derive(Serialize, Deserialize)]
138 pub struct BrokerTubes {
139     pub vm_evt_wrtube: SendTube,
140     pub vm_evt_rdtube: RecvTube,
141 }
142 
143 /// This struct represents a configured "disk" device as returned by the platform's API. There will
144 /// be two instances of it for each disk device, with the Tubes connected appropriately. The broker
145 /// will send one of these to the main process, and the other to the vhost user disk backend.
146 struct DiskDeviceEnd {
147     bootstrap_tube: Tube,
148     vhost_user: Tube,
149 }
150 
151 /// Example of the function that would be in linux.rs.
platform_create_disks(_cfg: Config) -> Vec<(DiskDeviceEnd, DiskDeviceEnd)>152 fn platform_create_disks(_cfg: Config) -> Vec<(DiskDeviceEnd, DiskDeviceEnd)> {
153     unimplemented!()
154 }
155 
156 /// Time to wait after a process failure for the remaining processes to exit. When exceeded, all
157 /// remaining processes, except metrics, will be terminated.
158 const EXIT_TIMEOUT: Duration = Duration::from_secs(3);
159 /// Time to wait for the metrics process to flush and upload all logs.
160 const METRICS_TIMEOUT: Duration = Duration::from_secs(3);
161 
162 /// DLLs that are known to interfere with crosvm.
163 #[cfg(feature = "sandbox")]
164 const BLOCKLIST_DLLS: &[&str] = &[
165     "action_x64.dll",
166     "AudioDevProps2.dll",
167     "GridWndHook.dll",
168     "Nahimic2OSD.dll",
169     "NahimicOSD.dll",
170     "TwitchNativeOverlay64.dll",
171     "XSplitGameSource64.dll",
172     "SS2OSD.dll",
173     "nhAsusStrixOSD.dll",
174 ];
175 
176 /// Maps a process type to its sandbox policy configuration.
177 #[cfg(feature = "sandbox")]
process_policy(process_type: ProcessType, cfg: &Config) -> sandbox::policy::Policy178 fn process_policy(process_type: ProcessType, cfg: &Config) -> sandbox::policy::Policy {
179     #[allow(unused_mut)]
180     let mut policy = match process_type {
181         ProcessType::Block => sandbox::policy::BLOCK,
182         ProcessType::Main => main_process_policy(cfg),
183         ProcessType::Metrics => sandbox::policy::METRICS,
184         ProcessType::Net => sandbox::policy::NET,
185         ProcessType::Slirp => slirp_process_policy(cfg),
186         ProcessType::Gpu => sandbox::policy::GPU,
187         ProcessType::Snd => sandbox::policy::SND,
188         ProcessType::Broker => unimplemented!("No broker policy"),
189         ProcessType::Spu => unimplemented!("No SPU policy"),
190     };
191 
192     for dll in BLOCKLIST_DLLS.iter() {
193         policy.dll_blocklist.push(dll.to_string());
194     }
195 
196     #[cfg(feature = "asan")]
197     adjust_asan_policy(&mut policy);
198     #[cfg(feature = "cperfetto")]
199     adjust_perfetto_policy(&mut policy);
200     policy
201 }
202 
203 /// Dynamically appends rules to the main process's policy.
204 #[cfg(feature = "sandbox")]
main_process_policy(cfg: &Config) -> sandbox::policy::Policy205 fn main_process_policy(cfg: &Config) -> sandbox::policy::Policy {
206     let mut policy = sandbox::policy::MAIN;
207     if let Some(host_guid) = &cfg.host_guid {
208         let rule = sandbox::policy::Rule {
209             subsystem: sandbox::SubSystem::SUBSYS_FILES,
210             semantics: sandbox::Semantics::FILES_ALLOW_ANY,
211             pattern: format!("\\??\\pipe\\{}\\vsock-*", host_guid),
212         };
213         policy.exceptions.push(rule);
214     }
215     policy
216 }
217 
218 #[cfg(feature = "sandbox")]
slirp_process_policy(#[allow(unused)] cfg: &Config) -> sandbox::policy::Policy219 fn slirp_process_policy(#[allow(unused)] cfg: &Config) -> sandbox::policy::Policy {
220     #[allow(unused_mut)]
221     let mut policy = sandbox::policy::SLIRP;
222 
223     #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))]
224     if let Some(path) = &cfg.slirp_capture_file {
225         policy.exceptions.push(sandbox::policy::Rule {
226             subsystem: sandbox::SubSystem::SUBSYS_FILES,
227             semantics: sandbox::Semantics::FILES_ALLOW_ANY,
228             pattern: path.to_owned(),
229         });
230     }
231 
232     policy
233 }
234 
235 /// Adjust a policy to allow ASAN builds to write output files.
236 #[cfg(feature = "sandbox")]
adjust_asan_policy(policy: &mut sandbox::policy::Policy)237 fn adjust_asan_policy(policy: &mut sandbox::policy::Policy) {
238     if (policy.initial_token_level as i32) < (sandbox::TokenLevel::USER_RESTRICTED_NON_ADMIN as i32)
239     {
240         policy.initial_token_level = sandbox::TokenLevel::USER_RESTRICTED_NON_ADMIN;
241     }
242     if (policy.integrity_level as i32) > (sandbox::IntegrityLevel::INTEGRITY_LEVEL_MEDIUM as i32) {
243         policy.integrity_level = sandbox::IntegrityLevel::INTEGRITY_LEVEL_MEDIUM;
244     }
245 }
246 
247 /// Adjust a policy to allow perfetto tracing to open shared memory and use WASAPI.
248 #[cfg(feature = "sandbox")]
adjust_perfetto_policy(policy: &mut sandbox::policy::Policy)249 fn adjust_perfetto_policy(policy: &mut sandbox::policy::Policy) {
250     if (policy.initial_token_level as i32)
251         < (sandbox::TokenLevel::USER_RESTRICTED_SAME_ACCESS as i32)
252     {
253         policy.initial_token_level = sandbox::TokenLevel::USER_RESTRICTED_SAME_ACCESS;
254     }
255 
256     if (policy.lockdown_token_level as i32)
257         < (sandbox::TokenLevel::USER_RESTRICTED_SAME_ACCESS as i32)
258     {
259         policy.lockdown_token_level = sandbox::TokenLevel::USER_RESTRICTED_SAME_ACCESS;
260     }
261 
262     if (policy.integrity_level as i32) > (sandbox::IntegrityLevel::INTEGRITY_LEVEL_MEDIUM as i32) {
263         policy.integrity_level = sandbox::IntegrityLevel::INTEGRITY_LEVEL_MEDIUM;
264     }
265 
266     if (policy.delayed_integrity_level as i32)
267         > (sandbox::IntegrityLevel::INTEGRITY_LEVEL_MEDIUM as i32)
268     {
269         policy.delayed_integrity_level = sandbox::IntegrityLevel::INTEGRITY_LEVEL_MEDIUM;
270     }
271 }
272 
273 /// Wrapper that terminates a child process (if running) when dropped.
274 struct ChildCleanup {
275     process_type: ProcessType,
276     child: Box<dyn Child>,
277     dh_tube: Option<Tube>,
278 }
279 
280 #[derive(Debug)]
281 struct UnsandboxedChild(process::Child);
282 #[derive(Debug)]
283 struct SandboxedChild(SafeDescriptor);
284 
285 impl AsRawDescriptor for UnsandboxedChild {
as_raw_descriptor(&self) -> RawDescriptor286     fn as_raw_descriptor(&self) -> RawDescriptor {
287         self.0.as_raw_handle()
288     }
289 }
290 
291 impl AsRawDescriptor for SandboxedChild {
as_raw_descriptor(&self) -> RawDescriptor292     fn as_raw_descriptor(&self) -> RawDescriptor {
293         self.0.as_raw_descriptor()
294     }
295 }
296 
297 impl Display for ChildCleanup {
fmt(&self, f: &mut Formatter) -> fmt::Result298     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
299         write!(f, "{:?} {:?}", self.process_type, self.child)
300     }
301 }
302 
303 trait Child: std::fmt::Debug + AsRawDescriptor {
wait(&mut self) -> std::io::Result<Option<ExitCode>>304     fn wait(&mut self) -> std::io::Result<Option<ExitCode>>;
try_wait(&mut self) -> std::io::Result<Option<ExitCode>>305     fn try_wait(&mut self) -> std::io::Result<Option<ExitCode>>;
kill(&mut self) -> std::io::Result<()>306     fn kill(&mut self) -> std::io::Result<()>;
307     // Necessary to upcast dyn Child to dyn AsRawDescriptor
as_descriptor(&self) -> &dyn AsRawDescriptor308     fn as_descriptor(&self) -> &dyn AsRawDescriptor;
309 }
310 
311 impl Child for UnsandboxedChild {
wait(&mut self) -> std::io::Result<Option<ExitCode>>312     fn wait(&mut self) -> std::io::Result<Option<ExitCode>> {
313         Ok(self.0.wait()?.code())
314     }
315 
try_wait(&mut self) -> std::io::Result<Option<ExitCode>>316     fn try_wait(&mut self) -> std::io::Result<Option<ExitCode>> {
317         if let Some(status) = self.0.try_wait()? {
318             Ok(status.code())
319         } else {
320             Ok(None)
321         }
322     }
323 
kill(&mut self) -> std::io::Result<()>324     fn kill(&mut self) -> std::io::Result<()> {
325         self.0.kill()
326     }
327 
as_descriptor(&self) -> &dyn AsRawDescriptor328     fn as_descriptor(&self) -> &dyn AsRawDescriptor {
329         self
330     }
331 }
332 
333 impl Child for SandboxedChild {
wait(&mut self) -> std::io::Result<Option<ExitCode>>334     fn wait(&mut self) -> std::io::Result<Option<ExitCode>> {
335         let wait_ctx = WaitContext::<u32>::new()?;
336         wait_ctx.add(&self.0, 0)?;
337         let _events = wait_ctx.wait()?;
338         self.try_wait()
339     }
340 
try_wait(&mut self) -> std::io::Result<Option<ExitCode>>341     fn try_wait(&mut self) -> std::io::Result<Option<ExitCode>> {
342         get_exit_code_process(self.0.as_raw_descriptor()).map(|code| code.map(|c| c as i32))
343     }
344 
kill(&mut self) -> std::io::Result<()>345     fn kill(&mut self) -> std::io::Result<()> {
346         // TODO(b/315998194): Add safety comment
347         #[allow(clippy::undocumented_unsafe_blocks)]
348         if unsafe { TerminateProcess(self.0.as_raw_descriptor(), KILL_CHILD_EXIT_CODE) == 0 } {
349             Err(std::io::Error::last_os_error())
350         } else {
351             Ok(())
352         }
353     }
354 
as_descriptor(&self) -> &dyn AsRawDescriptor355     fn as_descriptor(&self) -> &dyn AsRawDescriptor {
356         self
357     }
358 }
359 
360 impl Drop for ChildCleanup {
drop(&mut self)361     fn drop(&mut self) {
362         let kill_process = match self.child.try_wait() {
363             Ok(None) => true,
364             Ok(_) => false,
365             Err(_) => true,
366         };
367         if kill_process {
368             if let Err(e) = self.child.kill() {
369                 const ACCESS_DENIED: Option<i32> = Some(ERROR_ACCESS_DENIED as i32);
370                 if !matches!(e.raw_os_error(), ACCESS_DENIED) {
371                     error!("Failed to clean up child process {}: {}", self, e);
372                 }
373             }
374 
375             // Sending a kill signal does NOT imply the process has exited. Wait for it to exit.
376             let wait_res = self.child.wait();
377             if let Ok(Some(code)) = wait_res.as_ref() {
378                 warn!(
379                     "child process {} killed, exited {}",
380                     self,
381                     ExitCodeWrapper(*code)
382                 );
383             } else {
384                 error!(
385                     "failed to wait for child process {} that was terminated: {:?}",
386                     self, wait_res
387                 );
388             }
389         } else {
390             info!("child process {} already terminated", self);
391         }
392 
393         // Log child exit code regardless of whether we killed it or it exited
394         // on its own.
395         {
396             // Don't even attempt to log metrics process, it doesn't exist to log
397             // itself.
398             if self.process_type != ProcessType::Metrics {
399                 let exit_code = self.child.wait();
400                 if let Ok(Some(exit_code)) = exit_code {
401                     metrics::log_event(MetricEventType::ChildProcessExit {
402                         exit_code: exit_code as u32,
403                         process_type: self.process_type,
404                     });
405                 } else {
406                     error!(
407                         "Failed to log exit code for process: {:?}, couldn't get exit code",
408                         self.process_type
409                     );
410                 }
411             }
412         }
413     }
414 }
415 
416 /// Represents a child process spawned by the broker.
417 struct ChildProcess {
418     // This is unused, but we hold it open to avoid an EPIPE in the child if it doesn't
419     // immediately read its startup information. We don't use FlushFileBuffers to avoid this
420     // because that would require blocking the startup sequence.
421     tube_transporter: TubeTransporter,
422 
423     // Used to set up the child process. Unused in steady state.
424     bootstrap_tube: Tube,
425     // Child process PID.
426     process_id: u32,
427     alias_pid: u32,
428 }
429 
430 /// Wrapper to start the broker.
run(cfg: Config, log_args: LogArgs) -> Result<()>431 pub fn run(cfg: Config, log_args: LogArgs) -> Result<()> {
432     // This wrapper exists because errors that are returned up to the caller aren't logged, though
433     // they are used to generate the return code. For practical debugging though, we want to log the
434     // errors.
435     let res = run_internal(cfg, log_args);
436     if let Err(e) = &res {
437         error!("Broker encountered an error: {}", e);
438     }
439     res
440 }
441 
442 #[derive(EventToken)]
443 enum Token {
444     Sigterm,
445     Process(u32),
446     MainExitTimeout,
447     DeviceExitTimeout,
448     MetricsExitTimeout,
449     SigtermTimeout,
450     DuplicateHandle(u32),
451 }
452 
get_log_path(cfg: &Config, file_name: &str) -> Option<PathBuf>453 fn get_log_path(cfg: &Config, file_name: &str) -> Option<PathBuf> {
454     cfg.logs_directory
455         .as_ref()
456         .map(|dir| Path::new(dir).join(file_name))
457 }
458 
459 /// Creates a metrics tube pair for communication with the metrics process.
460 /// The returned Tube will be used by the process producing logs, while
461 /// the metric_tubes list is sent to the metrics process to receive logs.
462 ///
463 /// IMPORTANT NOTE: The metrics process must receive the client (second) end
464 /// of the Tube pair in order to allow the connection to be properly shut
465 /// down without data loss.
metrics_tube_pair(metric_tubes: &mut Vec<RecvTube>) -> Result<SendTube>466 fn metrics_tube_pair(metric_tubes: &mut Vec<RecvTube>) -> Result<SendTube> {
467     // TODO(nkgold): as written, this Tube pair won't handle ancillary data properly because the
468     // PIDs are not set properly at each end; however, we don't plan to send ancillary data.
469     let (t1, t2) =
470         Tube::directional_pair().exit_context(Exit::CreateTube, "failed to create tube")?;
471     metric_tubes.push(t2);
472     Ok(t1)
473 }
474 
475 #[cfg(feature = "crash-report")]
create_crash_report_attrs(cfg: &Config, product_type: &str) -> CrashReportAttributes476 pub fn create_crash_report_attrs(cfg: &Config, product_type: &str) -> CrashReportAttributes {
477     crash_report::CrashReportAttributes {
478         product_type: product_type.to_owned(),
479         pipe_name: cfg.crash_pipe_name.clone(),
480         report_uuid: cfg.crash_report_uuid.clone(),
481         product_name: cfg.product_name.clone(),
482         product_version: cfg.product_version.clone(),
483     }
484 }
485 
486 /// Setup crash reporting for a process. Each process MUST provide a unique `product_type` to avoid
487 /// making crash reports incomprehensible.
488 #[cfg(feature = "crash-report")]
setup_emulator_crash_reporting(cfg: &Config) -> Result<String>489 pub fn setup_emulator_crash_reporting(cfg: &Config) -> Result<String> {
490     crash_report::setup_crash_reporting(create_crash_report_attrs(
491         cfg,
492         crash_report::product_type::EMULATOR,
493     ))
494     .exit_context(
495         Exit::CrashReportingInit,
496         "failed to initialize crash reporting",
497     )
498 }
499 
500 /// Starts the broker, which in turn spawns the main process & vhost user devices.
501 /// General data flow for device & main process spawning:
502 ///   Each platform (e.g. linux.rs) will provide create_inputs/gpus/nets.
503 ///
504 ///   Those functions will return a list of pairs of structs (containing the pipes and other
505 ///   process specific configuration) for the VMM & backend sides of the device. These structs
506 ///   should be minimal, and not duplicate information that is otherwise available in the Config
507 ///   struct. There MAY be two different types per device, one for the VMM side, and another for
508 ///   the backend.
509 ///
510 ///   The broker will send all the VMM structs to the main process, and the other structs
511 ///   to the vhost user backends. Every process will get a copy of the Config struct.
512 ///
513 ///   Finally, the broker will wait on the child processes to exit, and handle errors.
514 ///
515 /// Refrain from using platform specific code within this function. It will eventually be cross
516 /// platform.
run_internal(mut cfg: Config, log_args: LogArgs) -> Result<()>517 fn run_internal(mut cfg: Config, log_args: LogArgs) -> Result<()> {
518     #[cfg(feature = "sandbox")]
519     if sandbox::is_sandbox_broker() {
520         // Get the BrokerServices pointer so that it gets initialized.
521         sandbox::BrokerServices::get()
522             .exit_context(Exit::SandboxError, "sandbox operation failed")?;
523     }
524     // Note that parsing args causes syslog's log file to be set to the log file for the "main"
525     // process. We don't want broker logs going there, so we fetch our own log file and set it here.
526     let mut log_cfg = LogConfig {
527         log_args: log_args.clone(),
528         ..Default::default()
529     };
530 
531     if let Some(log_path) = get_log_path(&cfg, "broker_syslog.log") {
532         log_cfg.pipe = Some(Box::new(
533             OpenOptions::new()
534                 .append(true)
535                 .create(true)
536                 .open(log_path.as_path())
537                 .with_exit_context(Exit::LogFile, || {
538                     format!("failed to open log file {}", log_path.display())
539                 })?,
540         ));
541         log_cfg.log_args.stderr = false;
542     } else {
543         log_cfg.log_args.stderr = true;
544     }
545     syslog::init_with(log_cfg)?;
546 
547     #[cfg(feature = "process-invariants")]
548     let process_invariants = init_broker_process_invariants(
549         &cfg.process_invariants_data_handle,
550         &cfg.process_invariants_data_size,
551     )
552     .exit_context(
553         Exit::ProcessInvariantsInit,
554         "failed to initialize process invariants",
555     )?;
556 
557     #[cfg(feature = "crash-report")]
558     init_broker_crash_reporting(&mut cfg)?;
559 
560     let _raise_timer_resolution = enable_high_res_timers()
561         .exit_context(Exit::EnableHighResTimer, "failed to enable high res timers")?;
562 
563     // Note: in case of an error / scope exit, any children still in this map will be automatically
564     // closed.
565     let mut children: HashMap<u32, ChildCleanup> = HashMap::new();
566 
567     let mut exit_events = Vec::new();
568     let mut wait_ctx: WaitContext<Token> = WaitContext::new()
569         .exit_context(Exit::CreateWaitContext, "failed to create event context")?;
570 
571     // Hook ^C / SIGTERM so we can handle it gracefully.
572     let sigterm_event = Event::new().exit_context(Exit::CreateEvent, "failed to create event")?;
573     let sigterm_event_ctrlc = sigterm_event
574         .try_clone()
575         .exit_context(Exit::CloneEvent, "failed to clone event")?;
576     ctrlc::set_handler(move || {
577         sigterm_event_ctrlc.signal().unwrap();
578     })
579     .exit_context(Exit::SetSigintHandler, "failed to set sigint handler")?;
580     wait_ctx.add(&sigterm_event, Token::Sigterm).exit_context(
581         Exit::WaitContextAdd,
582         "failed to add trigger to event context",
583     )?;
584 
585     let mut metric_tubes = Vec::new();
586     let metrics_controller = spawn_child(
587         current_exe().unwrap().to_str().unwrap(),
588         ["run-metrics"],
589         get_log_path(&cfg, "metrics_stdout.log"),
590         get_log_path(&cfg, "metrics_stderr.log"),
591         ProcessType::Metrics,
592         &mut children,
593         &mut wait_ctx,
594         /* skip_bootstrap= */
595         #[cfg(test)]
596         false,
597         /* use_sandbox= */
598         cfg.jail_config.is_some(),
599         vec![],
600         &[],
601         &cfg,
602     )?;
603     metrics_controller
604         .tube_transporter
605         .serialize_and_transport(metrics_controller.process_id)
606         .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
607 
608     let mut main_child = spawn_child(
609         current_exe().unwrap().to_str().unwrap(),
610         ["run-main"],
611         get_log_path(&cfg, "main_stdout.log"),
612         get_log_path(&cfg, "main_stderr.log"),
613         ProcessType::Main,
614         &mut children,
615         &mut wait_ctx,
616         /* skip_bootstrap= */
617         #[cfg(test)]
618         false,
619         /* use_sandbox= */
620         cfg.jail_config.is_some(),
621         vec![],
622         &[],
623         &cfg,
624     )?;
625 
626     // Save block children `ChildProcess` so TubeTransporter and Tubes don't get closed.
627     let _block_children = start_up_block_backends(
628         &mut cfg,
629         &log_args,
630         &mut children,
631         &mut exit_events,
632         &mut wait_ctx,
633         &mut main_child,
634         &mut metric_tubes,
635         #[cfg(feature = "process-invariants")]
636         &process_invariants,
637     )?;
638 
639     #[cfg(all(feature = "net", feature = "slirp"))]
640     let (_slirp_child, _net_children) = start_up_net_backend(
641         &mut main_child,
642         &mut children,
643         &mut exit_events,
644         &mut wait_ctx,
645         &mut cfg,
646         &log_args,
647         &mut metric_tubes,
648         #[cfg(feature = "process-invariants")]
649         &process_invariants,
650     )?;
651 
652     #[cfg(feature = "audio")]
653     let num_audio_devices = if let Some(gpu_params) = cfg.gpu_parameters.as_ref() {
654         match gpu_params.audio_device_mode {
655             AudioDeviceMode::PerSurface => gpu_params.max_num_displays,
656             AudioDeviceMode::OneGlobal => 1,
657         }
658     } else {
659         1
660     };
661 
662     #[cfg(feature = "audio")]
663     let mut snd_cfgs = Vec::new();
664     #[cfg(feature = "audio")]
665     {
666         for card_index in 0..num_audio_devices {
667             snd_cfgs.push(platform_create_snd(
668                 &cfg,
669                 card_index as usize,
670                 &mut main_child,
671                 &mut exit_events,
672             )?);
673         }
674     }
675 
676     #[cfg(feature = "audio")]
677     let _snd_child = if !cfg
678         .vhost_user
679         .iter()
680         .any(|opt| opt.type_ == DeviceType::Sound)
681     {
682         // Pass both backend and frontend configs to main process.
683         cfg.snd_split_configs = snd_cfgs;
684         None
685     } else {
686         Some(start_up_snd(
687             &mut cfg,
688             &log_args,
689             snd_cfgs,
690             &mut children,
691             &mut wait_ctx,
692             &mut metric_tubes,
693             #[cfg(feature = "process-invariants")]
694             &process_invariants,
695         )?)
696     };
697 
698     let (vm_evt_wrtube, vm_evt_rdtube) =
699         Tube::directional_pair().context("failed to create vm event tube")?;
700 
701     #[cfg(feature = "gpu")]
702     let mut input_event_split_config = platform_create_input_event_config(&cfg)
703         .context("create input event devices for virtio-gpu device")?;
704 
705     #[cfg(feature = "gpu")]
706     let mut window_procedure_thread_builder = Some(WindowProcedureThread::builder());
707 
708     #[cfg(feature = "gpu")]
709     let gpu_cfg = platform_create_gpu(
710         &cfg,
711         &mut main_child,
712         &mut exit_events,
713         vm_evt_wrtube
714             .try_clone()
715             .exit_context(Exit::CloneEvent, "failed to clone event")?,
716     )?;
717 
718     #[cfg(feature = "gpu")]
719     let _gpu_child = if let Some(mut gpu_cfg) = gpu_cfg {
720         if !cfg
721             .vhost_user
722             .iter()
723             .any(|opt| opt.type_ == DeviceType::Gpu)
724         {
725             // Pass both backend and frontend configs to main process.
726             cfg.gpu_backend_config = Some(gpu_cfg.0);
727             cfg.gpu_vmm_config = Some(gpu_cfg.1);
728             None
729         } else {
730             // If we are running in a separate process, turn on external blobs (memory will be
731             // exported, sent to VMM for import, then mapped).
732             gpu_cfg.0.params.external_blob = true;
733 
734             Some(start_up_gpu(
735                 &mut cfg,
736                 &log_args,
737                 gpu_cfg,
738                 &mut input_event_split_config,
739                 &mut main_child,
740                 &mut children,
741                 &mut wait_ctx,
742                 &mut metric_tubes,
743                 window_procedure_thread_builder
744                     .take()
745                     .ok_or_else(|| anyhow!("window_procedure_thread_builder is missing."))?,
746                 #[cfg(feature = "process-invariants")]
747                 &process_invariants,
748             )?)
749         }
750     } else {
751         None
752     };
753 
754     #[cfg(feature = "gpu")]
755     {
756         cfg.input_event_split_config = Some(input_event_split_config);
757         if let Some(window_procedure_thread_builder) = window_procedure_thread_builder {
758             cfg.window_procedure_thread_split_config = Some(
759                 platform_create_window_procedure_thread_configs(
760                     &cfg,
761                     window_procedure_thread_builder,
762                     main_child.alias_pid,
763                     main_child.alias_pid,
764                 )
765                 .context("Failed to create window procedure thread configs")?,
766             );
767         }
768     }
769 
770     // Wait until all device processes are spun up so main TubeTransporter will have all the
771     // device control and Vhost tubes.
772     main_child
773         .tube_transporter
774         .serialize_and_transport(main_child.process_id)
775         .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
776     main_child.bootstrap_tube.send(&cfg).unwrap();
777 
778     let main_startup_args = CommonChildStartupArgs::new(
779         &log_args,
780         get_log_path(&cfg, "main_syslog.log"),
781         #[cfg(feature = "crash-report")]
782         create_crash_report_attrs(&cfg, product_type::EMULATOR),
783         #[cfg(feature = "process-invariants")]
784         process_invariants.clone(),
785         Some(metrics_tube_pair(&mut metric_tubes)?),
786     )?;
787     main_child.bootstrap_tube.send(&main_startup_args).unwrap();
788 
789     let exit_event = Event::new().exit_context(Exit::CreateEvent, "failed to create event")?;
790     main_child.bootstrap_tube.send(&exit_event).unwrap();
791     exit_events.push(exit_event);
792 
793     let broker_tubes = BrokerTubes {
794         vm_evt_wrtube,
795         vm_evt_rdtube,
796     };
797     main_child.bootstrap_tube.send(&broker_tubes).unwrap();
798 
799     // Setup our own metrics agent
800     {
801         let broker_metrics = metrics_tube_pair(&mut metric_tubes)?;
802         metrics::initialize(broker_metrics);
803 
804         #[cfg(feature = "gpu")]
805         let use_vulkan = match &cfg.gpu_parameters {
806             Some(params) => Some(params.use_vulkan),
807             None => {
808                 warn!("No GPU parameters set on crosvm config.");
809                 None
810             }
811         };
812         #[cfg(not(feature = "gpu"))]
813         let use_vulkan = None;
814 
815         anti_tamper::setup_common_metric_invariants(
816             &cfg.product_version,
817             &cfg.product_channel,
818             &use_vulkan.unwrap_or_default(),
819         );
820     }
821 
822     // We have all the metrics tubes from other children, so give them to the metrics controller
823     // along with a startup configuration.
824     let metrics_startup_args = CommonChildStartupArgs::new(
825         &log_args,
826         get_log_path(&cfg, "metrics_syslog.log"),
827         #[cfg(feature = "crash-report")]
828         create_crash_report_attrs(&cfg, product_type::METRICS),
829         #[cfg(feature = "process-invariants")]
830         process_invariants.clone(),
831         None,
832     )?;
833     metrics_controller
834         .bootstrap_tube
835         .send(&metrics_startup_args)
836         .unwrap();
837 
838     metrics_controller
839         .bootstrap_tube
840         .send(&metric_tubes)
841         .unwrap();
842 
843     Supervisor::broker_supervise_loop(children, wait_ctx, exit_events)
844 }
845 
846 /// Shuts down the metrics process, waiting for it to close to ensure
847 /// all logs are flushed.
clean_up_metrics(metrics_child: ChildCleanup) -> Result<()>848 fn clean_up_metrics(metrics_child: ChildCleanup) -> Result<()> {
849     // This will close the final metrics connection, triggering a metrics
850     // process shutdown.
851     metrics::get_destructor().cleanup();
852 
853     // However, we still want to wait for the metrics process to finish
854     // flushing any pending logs before exiting.
855     let metrics_cleanup_wait = WaitContext::<u32>::new().exit_context(
856         Exit::CreateWaitContext,
857         "failed to create metrics wait context",
858     )?;
859     let mut metrics_timeout =
860         Timer::new().exit_context(Exit::CreateTimer, "failed to create metrics timeout timer")?;
861     metrics_timeout
862         .reset_oneshot(EXIT_TIMEOUT)
863         .exit_context(Exit::ResetTimer, "failed to reset timer")?;
864     metrics_cleanup_wait.add(&metrics_timeout, 0).exit_context(
865         Exit::WaitContextAdd,
866         "failed to add metrics timout to wait context",
867     )?;
868     metrics_cleanup_wait
869         .add(metrics_child.child.as_descriptor(), 1)
870         .exit_context(
871             Exit::WaitContextAdd,
872             "failed to add metrics process to wait context",
873         )?;
874     let events = metrics_cleanup_wait
875         .wait()
876         .context("failed to wait for metrics context")?;
877 
878     let mut process_exited = false;
879     if events.iter().any(|e| e.is_readable && e.token == 1) {
880         process_exited = true;
881     }
882 
883     if !process_exited {
884         warn!(
885             "broker: Metrics process timed out before cleanly exiting.
886             This may indicate some logs remain unsent."
887         );
888         // Process will be force-killed on drop
889     }
890 
891     Ok(())
892 }
893 
894 #[cfg(feature = "crash-report")]
init_broker_crash_reporting(cfg: &mut Config) -> Result<()>895 fn init_broker_crash_reporting(cfg: &mut Config) -> Result<()> {
896     cfg.crash_report_uuid = Some(generate_uuid());
897     if cfg.crash_pipe_name.is_none() {
898         // We weren't started by the service. Spin up a crash reporter to be shared with all
899         // children.
900         cfg.crash_pipe_name = Some(
901             crash_report::setup_crash_reporting(create_crash_report_attrs(
902                 cfg,
903                 product_type::BROKER,
904             ))
905             .exit_context(Exit::CrashReportingInit, "failed to init crash reporting")?,
906         );
907     } else {
908         crash_report::setup_crash_reporting(create_crash_report_attrs(cfg, product_type::BROKER))
909             .exit_context(Exit::CrashReportingInit, "failed to init crash reporting")?;
910     }
911 
912     Ok(())
913 }
914 
915 struct Supervisor {
916     children: HashMap<u32, ChildCleanup>,
917     wait_ctx: WaitContext<Token>,
918     exit_events: Vec<Event>,
919     exit_timer: Option<Timer>,
920 }
921 
922 impl Supervisor {
broker_supervise_loop( children: HashMap<u32, ChildCleanup>, wait_ctx: WaitContext<Token>, exit_events: Vec<Event>, ) -> Result<()>923     pub fn broker_supervise_loop(
924         children: HashMap<u32, ChildCleanup>,
925         wait_ctx: WaitContext<Token>,
926         exit_events: Vec<Event>,
927     ) -> Result<()> {
928         let mut supervisor = Supervisor {
929             children,
930             wait_ctx,
931             exit_events,
932             exit_timer: None,
933         };
934         let result = supervisor.broker_loop();
935 
936         // Once supervise loop exits, we are exiting and just need to clean
937         // up. In error cases, there could still be children processes, so we close
938         // those first, and finally drop the metrics process.
939         supervisor.children.retain(|_, child| {
940             match child.process_type {
941                 ProcessType::Metrics => true,
942                 _ => {
943                     warn!(
944                         "broker: Forcibly closing child (type: {:?}). This often means
945                         the child was unable to close within the normal timeout window,
946                         or the broker itself failed with an error.",
947                         child.process_type
948                     );
949                     // Child killed on drop
950                     false
951                 }
952             }
953         });
954 
955         {
956             if supervisor.is_only_metrics_process_running() {
957                 clean_up_metrics(supervisor.children.into_values().next().unwrap())?;
958             } else {
959                 warn!(
960                     "broker: Metrics process not running after cleanup.
961                     This may indicate some exit logs have been dropped."
962                 );
963             }
964         }
965 
966         result
967     }
968 
969     /// We require exactly one main process.
assert_children_sane(&mut self)970     fn assert_children_sane(&mut self) {
971         let main_processes = self
972             .children
973             .iter()
974             .filter(|(_, child)| child.process_type == ProcessType::Main)
975             .count();
976         if main_processes != 1 {
977             // Why do we have to clear children? Well, panic *can* cause destructors not to run,
978             // which means these children won't run. The exact explanation for this isn't clear, but
979             // it reproduced consistently. So since we're panicking, we'll be careful.
980             self.children.clear();
981             panic!(
982                 "Broker must supervise exactly one main process. Got {} main process(es).",
983                 main_processes,
984             )
985         }
986     }
987 
is_only_metrics_process_running(&self) -> bool988     fn is_only_metrics_process_running(&self) -> bool {
989         self.children.len() == 1
990             && self.children.values().next().unwrap().process_type == ProcessType::Metrics
991     }
992 
all_non_metrics_processes_exited(&self) -> bool993     fn all_non_metrics_processes_exited(&self) -> bool {
994         self.children.is_empty() || self.is_only_metrics_process_running()
995     }
996 
start_exit_timer(&mut self, timeout_token: Token) -> Result<()>997     fn start_exit_timer(&mut self, timeout_token: Token) -> Result<()> {
998         if self.exit_timer.is_some() {
999             return Ok(());
1000         }
1001 
1002         let mut et = Timer::new().exit_context(Exit::CreateTimer, "failed to create timer")?;
1003         et.reset_oneshot(EXIT_TIMEOUT)
1004             .exit_context(Exit::ResetTimer, "failed to reset timer")?;
1005         self.wait_ctx.add(&et, timeout_token).exit_context(
1006             Exit::WaitContextAdd,
1007             "failed to add trigger to wait context",
1008         )?;
1009         self.exit_timer = Some(et);
1010 
1011         Ok(())
1012     }
1013 
1014     /// Once children have been spawned, this function is called to run the supervision loop, which
1015     /// waits for processes to exit and handles errors.
broker_loop(&mut self) -> Result<()>1016     fn broker_loop(&mut self) -> Result<()> {
1017         const KILLED_BY_SIGNAL: ExitCode = Exit::KilledBySignal as ExitCode;
1018         self.assert_children_sane();
1019         let mut first_nonzero_exitcode = None;
1020 
1021         while !self.all_non_metrics_processes_exited() {
1022             let events = self
1023                 .wait_ctx
1024                 .wait()
1025                 .context("failed to wait for event context")?;
1026 
1027             for event in events.iter().filter(|e| e.is_readable) {
1028                 match event.token {
1029                     Token::Sigterm => {
1030                         // Signal all children other than metrics to exit.
1031                         for exit_event in &self.exit_events {
1032                             if let Err(e) = exit_event.signal() {
1033                                 error!("failed to signal exit event to child: {}", e);
1034                             }
1035                         }
1036                         first_nonzero_exitcode.get_or_insert(KILLED_BY_SIGNAL);
1037                         self.start_exit_timer(Token::SigtermTimeout)?;
1038                     }
1039                     Token::Process(child_id) => {
1040                         let mut child = self.children.remove(&child_id).unwrap();
1041                         let process_handle = Descriptor(child.child.as_raw_descriptor());
1042                         self.wait_ctx.delete(&process_handle).exit_context(
1043                             Exit::WaitContextDelete,
1044                             "failed to remove trigger from event context",
1045                         )?;
1046                         if let Some(dh_tube) = child.dh_tube.as_ref() {
1047                             self.wait_ctx
1048                                 .delete(dh_tube.get_read_notifier())
1049                                 .exit_context(
1050                                     Exit::WaitContextDelete,
1051                                     "failed to remove trigger from event context",
1052                                 )?;
1053                         }
1054 
1055                         let exit_code = child.child.wait().unwrap().unwrap();
1056                         info!(
1057                             "broker: child (type {:?}) exited {}",
1058                             child.process_type,
1059                             ExitCodeWrapper(exit_code),
1060                         );
1061 
1062                         // Save the child's exit code (to pass through to the broker's exit code) if
1063                         // none has been saved or if the previously saved exit code was
1064                         // KilledBySignal. We overwrite KilledBySignal because the child exit may
1065                         // race with the sigterm from the service, esp if child exit is slowed by a
1066                         // Crashpad dump, and we don't want to lose the child's exit code if it was
1067                         // the initial cause of the emulator failing.
1068                         if exit_code != 0
1069                             && (first_nonzero_exitcode.is_none()
1070                                 || matches!(first_nonzero_exitcode, Some(KILLED_BY_SIGNAL)))
1071                         {
1072                             info!(
1073                                 "setting first_nonzero_exitcode {:?} -> {}",
1074                                 first_nonzero_exitcode, exit_code,
1075                             );
1076                             first_nonzero_exitcode =
1077                                 Some(to_process_type_error(exit_code as u32, child.process_type)
1078                                     as i32);
1079                         }
1080 
1081                         let timeout_token = match child.process_type {
1082                             ProcessType::Main => Token::MainExitTimeout,
1083                             ProcessType::Metrics => Token::MetricsExitTimeout,
1084                             _ => Token::DeviceExitTimeout,
1085                         };
1086                         self.start_exit_timer(timeout_token)?;
1087                     }
1088                     Token::SigtermTimeout => {
1089                         if let Some(exit_code) = first_nonzero_exitcode {
1090                             if exit_code != KILLED_BY_SIGNAL {
1091                                 bail_exit_code!(
1092                                     exit_code,
1093                                     "broker got sigterm, but a child exited with an error.",
1094                                 );
1095                             }
1096                         }
1097                         ensure_exit_code!(
1098                             self.all_non_metrics_processes_exited(),
1099                             Exit::BrokerSigtermTimeout,
1100                             "broker got sigterm, but other broker children did not exit within the \
1101                             timeout",
1102                         );
1103                     }
1104                     Token::MainExitTimeout => {
1105                         if let Some(exit_code) = first_nonzero_exitcode {
1106                             bail_exit_code!(
1107                                 exit_code,
1108                                 "main exited, but a child exited with an error.",
1109                             );
1110                         }
1111                         ensure_exit_code!(
1112                             self.all_non_metrics_processes_exited(),
1113                             Exit::BrokerMainExitedTimeout,
1114                             "main exited, but other broker children did not exit within the \
1115                             timeout",
1116                         );
1117                     }
1118                     Token::DeviceExitTimeout => {
1119                         // A device process exited, but there are still other processes running.
1120                         if let Some(exit_code) = first_nonzero_exitcode {
1121                             bail_exit_code!(
1122                                 exit_code,
1123                                 "a device exited, and either it or another child exited with an \
1124                                 error.",
1125                             );
1126                         }
1127                         ensure_exit_code!(
1128                             self.all_non_metrics_processes_exited(),
1129                             Exit::BrokerDeviceExitedTimeout,
1130                             "device exited, but other broker children did not exit within the \
1131                             timeout",
1132                         );
1133                     }
1134                     Token::MetricsExitTimeout => {
1135                         // The metrics server exited, but there are still other processes running.
1136                         if let Some(exit_code) = first_nonzero_exitcode {
1137                             bail_exit_code!(
1138                                 exit_code,
1139                                 "metrics server exited, and either it or another child exited with \
1140                                 an error.",
1141                             );
1142                         }
1143                         ensure_exit_code!(
1144                             self.children.is_empty(),
1145                             Exit::BrokerMetricsExitedTimeout,
1146                             "metrics exited, but other broker children did not exit within the \
1147                             timeout",
1148                         );
1149                     }
1150                     Token::DuplicateHandle(child_id) => {
1151                         if let Some(tube) = &self.children[&child_id].dh_tube {
1152                             let req: DuplicateHandleRequest = tube
1153                                 .recv()
1154                                 .exit_context(Exit::TubeFailure, "failed operation on tube")?;
1155                             if !self.children.contains_key(&req.target_alias_pid) {
1156                                 error!(
1157                                     "DuplicateHandleRequest contained invalid alias pid: {}",
1158                                     req.target_alias_pid
1159                                 );
1160                                 tube.send(&DuplicateHandleResponse { handle: None })
1161                                     .exit_context(Exit::TubeFailure, "failed operation on tube")?;
1162                             } else {
1163                                 let target = &self.children[&req.target_alias_pid].child;
1164                                 let handle = win_util::duplicate_handle_from_source_process(
1165                                     self.children[&child_id].child.as_raw_descriptor(),
1166                                     req.handle as RawHandle,
1167                                     target.as_raw_descriptor(),
1168                                 );
1169                                 match handle {
1170                                     Ok(handle) => tube
1171                                         .send(&DuplicateHandleResponse {
1172                                             handle: Some(handle as usize),
1173                                         })
1174                                         .exit_context(
1175                                             Exit::TubeFailure,
1176                                             "failed operation on tube",
1177                                         )?,
1178                                     Err(e) => {
1179                                         error!("Failed to duplicate handle: {}", e);
1180                                         tube.send(&DuplicateHandleResponse { handle: None })
1181                                             .exit_context(
1182                                                 Exit::TubeFailure,
1183                                                 "failed operation on tube",
1184                                             )?
1185                                     }
1186                                 };
1187                             }
1188                         }
1189                     }
1190                 }
1191             }
1192         }
1193 
1194         if let Some(exit_code) = first_nonzero_exitcode {
1195             bail_exit_code!(
1196                 exit_code,
1197                 if exit_code == KILLED_BY_SIGNAL {
1198                     "broker got sigterm, and all children exited zero from shutdown event."
1199                 } else {
1200                     "all processes exited, but at least one encountered an error."
1201                 },
1202             );
1203         }
1204 
1205         Ok(())
1206     }
1207 }
1208 
start_up_block_backends( cfg: &mut Config, log_args: &LogArgs, children: &mut HashMap<u32, ChildCleanup>, exit_events: &mut Vec<Event>, wait_ctx: &mut WaitContext<Token>, main_child: &mut ChildProcess, metric_tubes: &mut Vec<RecvTube>, #[cfg(feature = "process-invariants")] process_invariants: &EmulatorProcessInvariants, ) -> Result<Vec<ChildProcess>>1209 fn start_up_block_backends(
1210     cfg: &mut Config,
1211     log_args: &LogArgs,
1212     children: &mut HashMap<u32, ChildCleanup>,
1213     exit_events: &mut Vec<Event>,
1214     wait_ctx: &mut WaitContext<Token>,
1215     main_child: &mut ChildProcess,
1216     metric_tubes: &mut Vec<RecvTube>,
1217     #[cfg(feature = "process-invariants")] process_invariants: &EmulatorProcessInvariants,
1218 ) -> Result<Vec<ChildProcess>> {
1219     let mut block_children = Vec::new();
1220     let disk_options = cfg.disks.clone();
1221     for (index, disk_option) in disk_options.iter().enumerate() {
1222         let block_child = spawn_block_backend(index, main_child, children, wait_ctx, cfg)?;
1223 
1224         let startup_args = CommonChildStartupArgs::new(
1225             log_args,
1226             get_log_path(cfg, &format!("disk_{}_syslog.log", index)),
1227             #[cfg(feature = "crash-report")]
1228             create_crash_report_attrs(cfg, &format!("{}_{}", product_type::DISK, index)),
1229             #[cfg(feature = "process-invariants")]
1230             process_invariants.clone(),
1231             Some(metrics_tube_pair(metric_tubes)?),
1232         )?;
1233         block_child.bootstrap_tube.send(&startup_args).unwrap();
1234 
1235         block_child.bootstrap_tube.send(&disk_option).unwrap();
1236 
1237         let exit_event = Event::new().exit_context(Exit::CreateEvent, "failed to create event")?;
1238         block_child.bootstrap_tube.send(&exit_event).unwrap();
1239         exit_events.push(exit_event);
1240         block_children.push(block_child);
1241     }
1242 
1243     Ok(block_children)
1244 }
1245 
spawn_block_backend( log_index: usize, main_child: &mut ChildProcess, children: &mut HashMap<u32, ChildCleanup>, wait_ctx: &mut WaitContext<Token>, cfg: &mut Config, ) -> Result<ChildProcess>1246 fn spawn_block_backend(
1247     log_index: usize,
1248     main_child: &mut ChildProcess,
1249     children: &mut HashMap<u32, ChildCleanup>,
1250     wait_ctx: &mut WaitContext<Token>,
1251     cfg: &mut Config,
1252 ) -> Result<ChildProcess> {
1253     let (mut vhost_user_main_tube, mut vhost_user_device_tube) =
1254         Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
1255 
1256     let (mut disk_host_tube, mut disk_device_tube) =
1257         Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
1258 
1259     disk_device_tube.set_target_pid(main_child.alias_pid);
1260     vhost_user_device_tube.set_target_pid(main_child.alias_pid);
1261     let block_child = spawn_child(
1262         current_exe().unwrap().to_str().unwrap(),
1263         ["device", "block"],
1264         get_log_path(cfg, &format!("disk_{}_stdout.log", log_index)),
1265         get_log_path(cfg, &format!("disk_{}_stderr.log", log_index)),
1266         ProcessType::Block,
1267         children,
1268         wait_ctx,
1269         /* skip_bootstrap= */
1270         #[cfg(test)]
1271         false,
1272         /* use_sandbox= */
1273         cfg.jail_config.is_some(),
1274         vec![
1275             TubeTransferData {
1276                 tube: disk_device_tube,
1277                 tube_token: TubeToken::Control,
1278             },
1279             TubeTransferData {
1280                 tube: vhost_user_device_tube,
1281                 tube_token: TubeToken::VhostUser,
1282             },
1283         ],
1284         &[],
1285         cfg,
1286     )?;
1287 
1288     block_child
1289         .tube_transporter
1290         .serialize_and_transport(block_child.process_id)
1291         .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
1292 
1293     vhost_user_main_tube.set_target_pid(block_child.alias_pid);
1294     disk_host_tube.set_target_pid(block_child.alias_pid);
1295     cfg.block_control_tube.push(disk_host_tube);
1296     cfg.block_vhost_user_tube.push(vhost_user_main_tube);
1297 
1298     Ok(block_child)
1299 }
1300 
1301 #[cfg(feature = "sandbox")]
spawn_sandboxed_child<I, S>( program: &str, args: I, stdout_file: Option<std::fs::File>, stderr_file: Option<std::fs::File>, handles_to_inherit: Vec<&dyn AsRawDescriptor>, process_policy: sandbox::policy::Policy, ) -> Result<(u32, Box<dyn Child>)> where I: IntoIterator<Item = S>, S: AsRef<OsStr>,1302 fn spawn_sandboxed_child<I, S>(
1303     program: &str,
1304     args: I,
1305     stdout_file: Option<std::fs::File>,
1306     stderr_file: Option<std::fs::File>,
1307     handles_to_inherit: Vec<&dyn AsRawDescriptor>,
1308     process_policy: sandbox::policy::Policy,
1309 ) -> Result<(u32, Box<dyn Child>)>
1310 where
1311     I: IntoIterator<Item = S>,
1312     S: AsRef<OsStr>,
1313 {
1314     let mut broker = sandbox::BrokerServices::get()
1315         .exit_context(Exit::SandboxError, "sandbox operation failed")?
1316         .unwrap();
1317     let mut policy = broker.create_policy();
1318     policy
1319         .set_token_level(
1320             process_policy.initial_token_level,
1321             process_policy.lockdown_token_level,
1322         )
1323         .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1324     policy
1325         .set_job_level(process_policy.job_level, process_policy.ui_exceptions)
1326         .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1327     policy
1328         .set_integrity_level(process_policy.integrity_level)
1329         .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1330     policy
1331         .set_delayed_integrity_level(process_policy.delayed_integrity_level)
1332         .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1333 
1334     if process_policy.alternate_desktop {
1335         policy
1336             .set_alternate_desktop(process_policy.alternate_winstation)
1337             .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1338     }
1339 
1340     for rule in process_policy.exceptions {
1341         policy
1342             .add_rule(rule.subsystem, rule.semantics, rule.pattern)
1343             .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1344     }
1345 
1346     policy.set_lockdown_default_dacl();
1347 
1348     if let Some(file) = stdout_file.as_ref() {
1349         policy
1350             .set_stdout_from_file(file)
1351             .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1352     }
1353 
1354     if let Some(file) = stderr_file.as_ref() {
1355         policy
1356             .set_stderr_from_file(file)
1357             .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1358     }
1359 
1360     for handle in handles_to_inherit.into_iter() {
1361         policy.add_handle_to_share(handle);
1362     }
1363 
1364     for dll in process_policy.dll_blocklist.into_iter() {
1365         policy
1366             .add_dll_to_unload(&dll)
1367             .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1368     }
1369 
1370     // spawn_target uses CreateProcessW to create a new process, which will pass
1371     // the command line arguments verbatim to the new process. Most processes
1372     // expect that argv[0] will be the program name, so provide that before the
1373     // rest of the args.
1374     let command_line = args
1375         .into_iter()
1376         .fold(format!("\"{}\"", program), |mut args, arg| {
1377             args.push(' ');
1378             args.push_str(OsStr::new(&arg).to_str().unwrap());
1379             args
1380         });
1381 
1382     let (target, warning) = broker
1383         .spawn_target(program, &command_line, &policy)
1384         .exit_context(Exit::SandboxError, "sandbox operation failed")?;
1385     if let Some(w) = warning {
1386         warn!("sandbox: got warning spawning target: {}", w);
1387     }
1388     win_util::resume_thread(target.thread.as_raw_descriptor())
1389         .exit_context(Exit::ProcessSpawnFailed, "failed to spawn child process")?;
1390 
1391     Ok((target.process_id, Box::new(SandboxedChild(target.process))))
1392 }
1393 
spawn_unsandboxed_child<I, S>( program: &str, args: I, stdout_file: Option<std::fs::File>, stderr_file: Option<std::fs::File>, handles_to_inherit: Vec<&dyn AsRawDescriptor>, ) -> Result<(u32, Box<dyn Child>)> where I: IntoIterator<Item = S>, S: AsRef<OsStr>,1394 fn spawn_unsandboxed_child<I, S>(
1395     program: &str,
1396     args: I,
1397     stdout_file: Option<std::fs::File>,
1398     stderr_file: Option<std::fs::File>,
1399     handles_to_inherit: Vec<&dyn AsRawDescriptor>,
1400 ) -> Result<(u32, Box<dyn Child>)>
1401 where
1402     I: IntoIterator<Item = S>,
1403     S: AsRef<OsStr>,
1404 {
1405     let mut proc = Command::new(program);
1406 
1407     let proc = proc.args(args);
1408 
1409     for handle in handles_to_inherit.iter() {
1410         win_util::set_handle_inheritance(handle.as_raw_descriptor(), /* inheritable= */ true)
1411             .exit_context(Exit::CreateSocket, "failed to create socket")?;
1412     }
1413 
1414     if let Some(file) = stdout_file {
1415         proc.stdout(file);
1416     }
1417 
1418     if let Some(file) = stderr_file {
1419         proc.stderr(file);
1420     }
1421 
1422     info!("spawning process: {:?}", proc);
1423     let proc = proc
1424         .spawn()
1425         .exit_context(Exit::ProcessSpawnFailed, "failed to spawn child process")?;
1426 
1427     for handle in handles_to_inherit.iter() {
1428         win_util::set_handle_inheritance(handle.as_raw_descriptor(), /* inheritable= */ false)
1429             .exit_context(Exit::CreateSocket, "failed to create socket")?;
1430     }
1431 
1432     let process_id = proc.id();
1433 
1434     Ok((process_id, Box::new(UnsandboxedChild(proc))))
1435 }
1436 
1437 #[cfg(all(feature = "net", feature = "slirp"))]
start_up_net_backend( main_child: &mut ChildProcess, children: &mut HashMap<u32, ChildCleanup>, exit_events: &mut Vec<Event>, wait_ctx: &mut WaitContext<Token>, cfg: &mut Config, log_args: &LogArgs, metric_tubes: &mut Vec<RecvTube>, #[cfg(feature = "process-invariants")] process_invariants: &EmulatorProcessInvariants, ) -> Result<(ChildProcess, ChildProcess)>1438 fn start_up_net_backend(
1439     main_child: &mut ChildProcess,
1440     children: &mut HashMap<u32, ChildCleanup>,
1441     exit_events: &mut Vec<Event>,
1442     wait_ctx: &mut WaitContext<Token>,
1443     cfg: &mut Config,
1444     log_args: &LogArgs,
1445     metric_tubes: &mut Vec<RecvTube>,
1446     #[cfg(feature = "process-invariants")] process_invariants: &EmulatorProcessInvariants,
1447 ) -> Result<(ChildProcess, ChildProcess)> {
1448     let (host_pipe, guest_pipe) = named_pipes::pair_with_buffer_size(
1449         &FramingMode::Message.into(),
1450         &BlockingMode::Blocking.into(),
1451         /* timeout= */ 0,
1452         /* buffer_size= */ SLIRP_BUFFER_SIZE,
1453         /* overlapped= */ true,
1454     )
1455     .expect("Failed to create named pipe pair.");
1456     let slirp_kill_event = Event::new().expect("Failed to create slirp kill event.");
1457 
1458     let slirp_child = spawn_slirp(children, wait_ctx, cfg)?;
1459 
1460     let slirp_child_startup_args = CommonChildStartupArgs::new(
1461         log_args,
1462         get_log_path(cfg, "slirp_syslog.log"),
1463         #[cfg(feature = "crash-report")]
1464         create_crash_report_attrs(cfg, product_type::SLIRP),
1465         #[cfg(feature = "process-invariants")]
1466         process_invariants.clone(),
1467         Some(metrics_tube_pair(metric_tubes)?),
1468     )?;
1469     slirp_child
1470         .bootstrap_tube
1471         .send(&slirp_child_startup_args)
1472         .unwrap();
1473 
1474     let slirp_config = SlirpStartupConfig {
1475         slirp_pipe: host_pipe,
1476         shutdown_event: slirp_kill_event
1477             .try_clone()
1478             .expect("Failed to clone slirp kill event."),
1479         #[cfg(any(feature = "slirp-ring-capture", feature = "slirp-debug"))]
1480         slirp_capture_file: cfg.slirp_capture_file.take(),
1481     };
1482     slirp_child.bootstrap_tube.send(&slirp_config).unwrap();
1483 
1484     let net_child = spawn_net_backend(main_child, children, wait_ctx, cfg)?;
1485 
1486     let net_child_startup_args = CommonChildStartupArgs::new(
1487         log_args,
1488         get_log_path(cfg, "net_syslog.log"),
1489         #[cfg(feature = "crash-report")]
1490         create_crash_report_attrs(cfg, product_type::SLIRP),
1491         #[cfg(feature = "process-invariants")]
1492         process_invariants.clone(),
1493         Some(metrics_tube_pair(metric_tubes)?),
1494     )?;
1495     net_child
1496         .bootstrap_tube
1497         .send(&net_child_startup_args)
1498         .unwrap();
1499 
1500     let net_backend_config = NetBackendConfig {
1501         guest_pipe,
1502         slirp_kill_event,
1503     };
1504     net_child.bootstrap_tube.send(&net_backend_config).unwrap();
1505     let exit_event = Event::new().exit_context(Exit::CreateEvent, "failed to create event")?;
1506     net_child.bootstrap_tube.send(&exit_event).unwrap();
1507     exit_events.push(exit_event);
1508 
1509     Ok((slirp_child, net_child))
1510 }
1511 
spawn_slirp( children: &mut HashMap<u32, ChildCleanup>, wait_ctx: &mut WaitContext<Token>, cfg: &mut Config, ) -> Result<ChildProcess>1512 fn spawn_slirp(
1513     children: &mut HashMap<u32, ChildCleanup>,
1514     wait_ctx: &mut WaitContext<Token>,
1515     cfg: &mut Config,
1516 ) -> Result<ChildProcess> {
1517     let slirp_child = spawn_child(
1518         current_exe().unwrap().to_str().unwrap(),
1519         ["run-slirp"],
1520         get_log_path(cfg, "slirp_stdout.log"),
1521         get_log_path(cfg, "slirp_stderr.log"),
1522         ProcessType::Slirp,
1523         children,
1524         wait_ctx,
1525         /* skip_bootstrap= */
1526         #[cfg(test)]
1527         false,
1528         /* use_sandbox= */ cfg.jail_config.is_some(),
1529         vec![],
1530         &[],
1531         cfg,
1532     )?;
1533 
1534     slirp_child
1535         .tube_transporter
1536         .serialize_and_transport(slirp_child.process_id)
1537         .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
1538 
1539     Ok(slirp_child)
1540 }
1541 
spawn_net_backend( main_child: &mut ChildProcess, children: &mut HashMap<u32, ChildCleanup>, wait_ctx: &mut WaitContext<Token>, cfg: &mut Config, ) -> Result<ChildProcess>1542 fn spawn_net_backend(
1543     main_child: &mut ChildProcess,
1544     children: &mut HashMap<u32, ChildCleanup>,
1545     wait_ctx: &mut WaitContext<Token>,
1546     cfg: &mut Config,
1547 ) -> Result<ChildProcess> {
1548     let (mut vhost_user_main_tube, mut vhost_user_device_tube) =
1549         Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
1550 
1551     vhost_user_device_tube.set_target_pid(main_child.alias_pid);
1552 
1553     let net_child = spawn_child(
1554         current_exe().unwrap().to_str().unwrap(),
1555         ["device", "net"],
1556         get_log_path(cfg, "net_stdout.log"),
1557         get_log_path(cfg, "net_stderr.log"),
1558         ProcessType::Net,
1559         children,
1560         wait_ctx,
1561         /* skip_bootstrap= */
1562         #[cfg(test)]
1563         false,
1564         /* use_sandbox= */ cfg.jail_config.is_some(),
1565         vec![TubeTransferData {
1566             tube: vhost_user_device_tube,
1567             tube_token: TubeToken::VhostUser,
1568         }],
1569         &[],
1570         cfg,
1571     )?;
1572 
1573     net_child
1574         .tube_transporter
1575         .serialize_and_transport(net_child.process_id)
1576         .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
1577 
1578     vhost_user_main_tube.set_target_pid(net_child.alias_pid);
1579     cfg.net_vhost_user_tube = Some(vhost_user_main_tube);
1580 
1581     Ok(net_child)
1582 }
1583 
1584 /// Create backend and VMM configurations for the sound device.
1585 #[cfg(feature = "audio")]
platform_create_snd( cfg: &Config, card_index: usize, main_child: &mut ChildProcess, exit_events: &mut Vec<Event>, ) -> Result<SndSplitConfig>1586 fn platform_create_snd(
1587     cfg: &Config,
1588     card_index: usize,
1589     main_child: &mut ChildProcess,
1590     exit_events: &mut Vec<Event>,
1591 ) -> Result<SndSplitConfig> {
1592     let exit_event = Event::new().exit_context(Exit::CreateEvent, "failed to create exit event")?;
1593     exit_events.push(
1594         exit_event
1595             .try_clone()
1596             .exit_context(Exit::CloneEvent, "failed to clone event")?,
1597     );
1598 
1599     let (mut main_vhost_user_tube, mut device_vhost_user_tube) =
1600         Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
1601     // Start off the vhost-user tube assuming it is in the main process.
1602     main_vhost_user_tube.set_target_pid(main_child.alias_pid);
1603     device_vhost_user_tube.set_target_pid(main_child.alias_pid);
1604 
1605     let (backend_config_product, vmm_config_product) = get_snd_product_configs()?;
1606 
1607     let parameters = SndParameters {
1608         backend: "winaudio".try_into().unwrap(),
1609         num_input_devices: num_input_sound_devices(cfg),
1610         num_input_streams: num_input_sound_streams(cfg),
1611         ..Default::default()
1612     };
1613 
1614     let audio_client_guid = generate_uuid();
1615 
1616     let backend_config = Some(SndBackendConfig {
1617         device_vhost_user_tube: Some(device_vhost_user_tube),
1618         exit_event,
1619         parameters,
1620         product_config: backend_config_product,
1621         audio_client_guid: audio_client_guid.clone(),
1622         card_index,
1623     });
1624 
1625     let vmm_config = Some(SndVmmConfig {
1626         main_vhost_user_tube: Some(main_vhost_user_tube),
1627         product_config: vmm_config_product,
1628         audio_client_guid,
1629         card_index,
1630     });
1631 
1632     Ok(SndSplitConfig {
1633         backend_config,
1634         vmm_config,
1635     })
1636 }
1637 
1638 /// Returns a snd child process for vhost-user sound.
1639 // TODO(b/292128227): This method is deprecated and is not used downstream. The following code
1640 // has not been converted to handle multiple devices. We don't want multiple snd backend processes
1641 // being spun up anyways.
1642 #[cfg(feature = "audio")]
start_up_snd( cfg: &mut Config, log_args: &LogArgs, mut snd_cfgs: Vec<SndSplitConfig>, children: &mut HashMap<u32, ChildCleanup>, wait_ctx: &mut WaitContext<Token>, metric_tubes: &mut Vec<RecvTube>, #[cfg(feature = "process-invariants")] process_invariants: &EmulatorProcessInvariants, ) -> Result<ChildProcess>1643 fn start_up_snd(
1644     cfg: &mut Config,
1645     log_args: &LogArgs,
1646     mut snd_cfgs: Vec<SndSplitConfig>,
1647     children: &mut HashMap<u32, ChildCleanup>,
1648     wait_ctx: &mut WaitContext<Token>,
1649     metric_tubes: &mut Vec<RecvTube>,
1650     #[cfg(feature = "process-invariants")] process_invariants: &EmulatorProcessInvariants,
1651 ) -> Result<ChildProcess> {
1652     // Extract the backend config from the sound config, so it can run elsewhere.
1653     // TODO(b/292128227): Clean up when upstreamed.
1654     let mut snd_cfg = snd_cfgs.swap_remove(0);
1655     let backend_cfg = snd_cfg
1656         .backend_config
1657         .take()
1658         .expect("snd backend config must be set");
1659 
1660     let snd_child = spawn_child(
1661         current_exe().unwrap().to_str().unwrap(),
1662         ["device", "snd"],
1663         get_log_path(cfg, "snd_stdout.log"),
1664         get_log_path(cfg, "snd_stderr.log"),
1665         ProcessType::Snd,
1666         children,
1667         wait_ctx,
1668         /* skip_bootstrap= */
1669         #[cfg(test)]
1670         false,
1671         /* use_sandbox= */
1672         cfg.jail_config.is_some(),
1673         vec![],
1674         &[],
1675         cfg,
1676     )?;
1677 
1678     snd_child
1679         .tube_transporter
1680         .serialize_and_transport(snd_child.process_id)
1681         .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
1682 
1683     // Update target PIDs to new child.
1684     if let Some(vmm_config) = snd_cfg.vmm_config.as_mut() {
1685         if let Some(tube) = vmm_config.main_vhost_user_tube.as_mut() {
1686             tube.set_target_pid(snd_child.alias_pid);
1687         }
1688     }
1689 
1690     // Send VMM config to main process.
1691     cfg.snd_split_configs = snd_cfgs;
1692 
1693     let startup_args = CommonChildStartupArgs::new(
1694         log_args,
1695         get_log_path(cfg, "snd_syslog.log"),
1696         #[cfg(feature = "crash-report")]
1697         create_crash_report_attrs(cfg, product_type::SND),
1698         #[cfg(feature = "process-invariants")]
1699         process_invariants.clone(),
1700         Some(metrics_tube_pair(metric_tubes)?),
1701     )?;
1702     snd_child.bootstrap_tube.send(&startup_args).unwrap();
1703 
1704     // Send backend config to Snd child.
1705     snd_child.bootstrap_tube.send(&backend_cfg).unwrap();
1706 
1707     Ok(snd_child)
1708 }
1709 
1710 #[cfg(feature = "gpu")]
platform_create_input_event_config(cfg: &Config) -> Result<InputEventSplitConfig>1711 fn platform_create_input_event_config(cfg: &Config) -> Result<InputEventSplitConfig> {
1712     let mut event_devices = vec![];
1713     let mut multi_touch_pipes = vec![];
1714     let mut mouse_pipes = vec![];
1715     let mut keyboard_pipes = vec![];
1716 
1717     for input in &cfg.virtio_input {
1718         match input {
1719             InputDeviceOption::MultiTouch { .. } => {
1720                 let (event_device_pipe, virtio_input_pipe) =
1721                     StreamChannel::pair(BlockingMode::Nonblocking, FramingMode::Byte)
1722                         .exit_context(Exit::EventDeviceSetup, "failed to set up EventDevice")?;
1723                 event_devices.push(EventDevice::touchscreen(event_device_pipe));
1724                 multi_touch_pipes.push(virtio_input_pipe);
1725             }
1726             InputDeviceOption::Mouse { .. } => {
1727                 let (event_device_pipe, virtio_input_pipe) =
1728                     StreamChannel::pair(BlockingMode::Nonblocking, FramingMode::Byte)
1729                         .exit_context(Exit::EventDeviceSetup, "failed to set up EventDevice")?;
1730                 event_devices.push(EventDevice::mouse(event_device_pipe));
1731                 mouse_pipes.push(virtio_input_pipe);
1732             }
1733             _ => {}
1734         }
1735     }
1736 
1737     // One keyboard
1738     let (event_device_pipe, virtio_input_pipe) =
1739         StreamChannel::pair(BlockingMode::Nonblocking, FramingMode::Byte)
1740             .exit_context(Exit::EventDeviceSetup, "failed to set up EventDevice")?;
1741     event_devices.push(EventDevice::keyboard(event_device_pipe));
1742     keyboard_pipes.push(virtio_input_pipe);
1743 
1744     Ok(InputEventSplitConfig {
1745         backend_config: Some(InputEventBackendConfig { event_devices }),
1746         vmm_config: InputEventVmmConfig {
1747             multi_touch_pipes,
1748             mouse_pipes,
1749             keyboard_pipes,
1750         },
1751     })
1752 }
1753 
1754 #[cfg(feature = "gpu")]
1755 /// Create Window procedure thread configurations.
platform_create_window_procedure_thread_configs( cfg: &Config, mut wndproc_thread_builder: WindowProcedureThreadBuilder, main_alias_pid: u32, device_alias_pid: u32, ) -> Result<WindowProcedureThreadSplitConfig>1756 fn platform_create_window_procedure_thread_configs(
1757     cfg: &Config,
1758     mut wndproc_thread_builder: WindowProcedureThreadBuilder,
1759     main_alias_pid: u32,
1760     device_alias_pid: u32,
1761 ) -> Result<WindowProcedureThreadSplitConfig> {
1762     if let Some(params) = cfg.gpu_parameters.as_ref() {
1763         wndproc_thread_builder.set_max_num_windows(params.max_num_displays);
1764     }
1765     let product_config = get_window_procedure_thread_product_configs(
1766         cfg,
1767         &mut wndproc_thread_builder,
1768         main_alias_pid,
1769         device_alias_pid,
1770     )
1771     .context("create product window procedure thread configs")?;
1772     Ok(WindowProcedureThreadSplitConfig {
1773         wndproc_thread_builder: Some(wndproc_thread_builder),
1774         vmm_config: WindowProcedureThreadVmmConfig { product_config },
1775     })
1776 }
1777 
1778 #[cfg(feature = "gpu")]
1779 /// Create backend and VMM configurations for the GPU device.
platform_create_gpu( cfg: &Config, #[allow(unused_variables)] main_child: &mut ChildProcess, exit_events: &mut Vec<Event>, exit_evt_wrtube: SendTube, ) -> Result<Option<(GpuBackendConfig, GpuVmmConfig)>>1780 fn platform_create_gpu(
1781     cfg: &Config,
1782     #[allow(unused_variables)] main_child: &mut ChildProcess,
1783     exit_events: &mut Vec<Event>,
1784     exit_evt_wrtube: SendTube,
1785 ) -> Result<Option<(GpuBackendConfig, GpuVmmConfig)>> {
1786     if cfg.gpu_parameters.is_none() {
1787         return Ok(None);
1788     }
1789     let exit_event = Event::new().exit_context(Exit::CreateEvent, "failed to create exit event")?;
1790     exit_events.push(
1791         exit_event
1792             .try_clone()
1793             .exit_context(Exit::CloneEvent, "failed to clone event")?,
1794     );
1795 
1796     let (backend_config_product, vmm_config_product) =
1797         get_gpu_product_configs(cfg, main_child.alias_pid)?;
1798 
1799     let (mut main_vhost_user_tube, mut device_host_user_tube) =
1800         Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
1801     // Start off the vhost-user tube assuming it is in the main process.
1802     main_vhost_user_tube.set_target_pid(main_child.alias_pid);
1803     device_host_user_tube.set_target_pid(main_child.alias_pid);
1804 
1805     let (mut gpu_control_host_tube, mut gpu_control_device_tube) =
1806         Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
1807     gpu_control_host_tube.set_target_pid(main_child.alias_pid);
1808     gpu_control_device_tube.set_target_pid(main_child.alias_pid);
1809 
1810     let backend_config = GpuBackendConfig {
1811         device_vhost_user_tube: Some(device_host_user_tube),
1812         exit_event,
1813         exit_evt_wrtube,
1814         gpu_control_device_tube,
1815         params: cfg
1816             .gpu_parameters
1817             .as_ref()
1818             .expect("missing GpuParameters in config")
1819             .clone(),
1820         product_config: backend_config_product,
1821     };
1822 
1823     let vmm_config = GpuVmmConfig {
1824         main_vhost_user_tube: Some(main_vhost_user_tube),
1825         gpu_control_host_tube: Some(gpu_control_host_tube),
1826         product_config: vmm_config_product,
1827     };
1828 
1829     Ok(Some((backend_config, vmm_config)))
1830 }
1831 
1832 #[cfg(feature = "gpu")]
1833 /// Returns a gpu child process for vhost-user GPU.
start_up_gpu( cfg: &mut Config, log_args: &LogArgs, gpu_cfg: (GpuBackendConfig, GpuVmmConfig), input_event_cfg: &mut InputEventSplitConfig, main_child: &mut ChildProcess, children: &mut HashMap<u32, ChildCleanup>, wait_ctx: &mut WaitContext<Token>, metric_tubes: &mut Vec<RecvTube>, wndproc_thread_builder: WindowProcedureThreadBuilder, #[cfg(feature = "process-invariants")] process_invariants: &EmulatorProcessInvariants, ) -> Result<ChildProcess>1834 fn start_up_gpu(
1835     cfg: &mut Config,
1836     log_args: &LogArgs,
1837     gpu_cfg: (GpuBackendConfig, GpuVmmConfig),
1838     input_event_cfg: &mut InputEventSplitConfig,
1839     main_child: &mut ChildProcess,
1840     children: &mut HashMap<u32, ChildCleanup>,
1841     wait_ctx: &mut WaitContext<Token>,
1842     metric_tubes: &mut Vec<RecvTube>,
1843     wndproc_thread_builder: WindowProcedureThreadBuilder,
1844     #[cfg(feature = "process-invariants")] process_invariants: &EmulatorProcessInvariants,
1845 ) -> Result<ChildProcess> {
1846     let (backend_cfg, mut vmm_cfg) = gpu_cfg;
1847 
1848     let gpu_child = spawn_child(
1849         current_exe().unwrap().to_str().unwrap(),
1850         ["device", "gpu"],
1851         get_log_path(cfg, "gpu_stdout.log"),
1852         get_log_path(cfg, "gpu_stderr.log"),
1853         ProcessType::Gpu,
1854         children,
1855         wait_ctx,
1856         /* skip_bootstrap= */
1857         #[cfg(test)]
1858         false,
1859         /* use_sandbox= */
1860         cfg.jail_config.is_some(),
1861         vec![],
1862         &[],
1863         cfg,
1864     )?;
1865 
1866     gpu_child
1867         .tube_transporter
1868         .serialize_and_transport(gpu_child.process_id)
1869         .exit_context(Exit::TubeTransporterInit, "failed to initialize tube")?;
1870 
1871     let mut wndproc_thread_cfg = platform_create_window_procedure_thread_configs(
1872         cfg,
1873         wndproc_thread_builder,
1874         main_child.alias_pid,
1875         gpu_child.alias_pid,
1876     )
1877     .context("failed to create window procedure thread configs")?;
1878     let wndproc_thread_builder = wndproc_thread_cfg
1879         .wndproc_thread_builder
1880         .take()
1881         .expect("The window procedure thread builder is missing");
1882     cfg.window_procedure_thread_split_config = Some(wndproc_thread_cfg);
1883 
1884     // Update target PIDs to new child.
1885     if let Some(tube) = &mut vmm_cfg.main_vhost_user_tube {
1886         tube.set_target_pid(gpu_child.alias_pid);
1887     }
1888     if let Some(tube) = &mut vmm_cfg.gpu_control_host_tube {
1889         tube.set_target_pid(gpu_child.alias_pid);
1890     }
1891 
1892     // Send VMM config to main process. Note we don't set gpu_backend_config and
1893     // input_event_backend_config, since it is passed to the child.
1894     cfg.gpu_vmm_config = Some(vmm_cfg);
1895     let input_event_backend_config = input_event_cfg
1896         .backend_config
1897         .take()
1898         .context("input event backend config is missing.")?;
1899 
1900     let startup_args = CommonChildStartupArgs::new(
1901         log_args,
1902         get_log_path(cfg, "gpu_syslog.log"),
1903         #[cfg(feature = "crash-report")]
1904         create_crash_report_attrs(cfg, product_type::GPU),
1905         #[cfg(feature = "process-invariants")]
1906         process_invariants.clone(),
1907         Some(metrics_tube_pair(metric_tubes)?),
1908     )?;
1909     gpu_child.bootstrap_tube.send(&startup_args).unwrap();
1910 
1911     // Send backend config to GPU child.
1912     gpu_child
1913         .bootstrap_tube
1914         .send(&(
1915             backend_cfg,
1916             input_event_backend_config,
1917             wndproc_thread_builder,
1918         ))
1919         .unwrap();
1920 
1921     Ok(gpu_child)
1922 }
1923 
1924 /// Spawns a child process, sending it a control tube as the --bootstrap=HANDLE_NUMBER argument.
1925 /// stdout & stderr are redirected to the provided file paths.
spawn_child<I, S>( program: &str, args: I, stdout_path: Option<PathBuf>, stderr_path: Option<PathBuf>, process_type: ProcessType, children: &mut HashMap<u32, ChildCleanup>, wait_ctx: &mut WaitContext<Token>, #[cfg(test)] skip_bootstrap: bool, use_sandbox: bool, mut tubes: Vec<TubeTransferData>, handles_to_inherit: &[&dyn AsRawDescriptor], #[allow(unused_variables)] cfg: &Config, ) -> Result<ChildProcess> where I: IntoIterator<Item = S>, S: AsRef<OsStr>,1926 fn spawn_child<I, S>(
1927     program: &str,
1928     args: I,
1929     stdout_path: Option<PathBuf>,
1930     stderr_path: Option<PathBuf>,
1931     process_type: ProcessType,
1932     children: &mut HashMap<u32, ChildCleanup>,
1933     wait_ctx: &mut WaitContext<Token>,
1934     #[cfg(test)] skip_bootstrap: bool,
1935     use_sandbox: bool,
1936     mut tubes: Vec<TubeTransferData>,
1937     handles_to_inherit: &[&dyn AsRawDescriptor],
1938     #[allow(unused_variables)] cfg: &Config,
1939 ) -> Result<ChildProcess>
1940 where
1941     I: IntoIterator<Item = S>,
1942     S: AsRef<OsStr>,
1943 {
1944     let (tube_transport_pipe, tube_transport_main_child) = named_pipes::pair(
1945         &FramingMode::Message.into(),
1946         &BlockingMode::Blocking.into(),
1947         /* timeout= */ 0,
1948     )
1949     .exit_context(Exit::CreateSocket, "failed to create socket")?;
1950 
1951     let stdout_file = if let Some(path) = stdout_path {
1952         Some(
1953             OpenOptions::new()
1954                 .append(true)
1955                 .create(true)
1956                 .open(path.as_path())
1957                 .with_exit_context(Exit::LogFile, || {
1958                     format!("failed to open log file {}", path.display())
1959                 })?,
1960         )
1961     } else {
1962         None
1963     };
1964 
1965     let stderr_file = if let Some(path) = stderr_path {
1966         Some(
1967             OpenOptions::new()
1968                 .append(true)
1969                 .create(true)
1970                 .open(path.as_path())
1971                 .with_exit_context(Exit::LogFile, || {
1972                     format!("failed to open log file {}", path.display())
1973                 })?,
1974         )
1975     } else {
1976         None
1977     };
1978 
1979     let bootstrap = [
1980         "--bootstrap".to_string(),
1981         (tube_transport_main_child.as_raw_descriptor() as usize).to_string(),
1982     ];
1983 
1984     #[cfg(test)]
1985     let bootstrap: &[String] = if skip_bootstrap { &[] } else { &bootstrap };
1986 
1987     let input_args: Vec<S> = args.into_iter().collect();
1988     let args = input_args
1989         .iter()
1990         .map(|arg| arg.as_ref())
1991         .chain(bootstrap.iter().map(|arg| arg.as_ref()));
1992 
1993     let mut handles_to_inherit = handles_to_inherit.to_vec();
1994     handles_to_inherit.push(&tube_transport_main_child);
1995 
1996     #[cfg(feature = "sandbox")]
1997     let (process_id, child) = if use_sandbox {
1998         spawn_sandboxed_child(
1999             program,
2000             args,
2001             stdout_file,
2002             stderr_file,
2003             handles_to_inherit,
2004             process_policy(process_type, cfg),
2005         )?
2006     } else {
2007         spawn_unsandboxed_child(program, args, stdout_file, stderr_file, handles_to_inherit)?
2008     };
2009     #[cfg(not(feature = "sandbox"))]
2010     let (process_id, child) =
2011         spawn_unsandboxed_child(program, args, stdout_file, stderr_file, handles_to_inherit)?;
2012 
2013     let (mut bootstrap_tube, bootstrap_tube_child) =
2014         Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2015 
2016     // Make sure our end of the Tube knows the PID of the child end.
2017     bootstrap_tube.set_target_pid(process_id);
2018 
2019     tubes.push(TubeTransferData {
2020         tube: bootstrap_tube_child,
2021         tube_token: TubeToken::Bootstrap,
2022     });
2023 
2024     let (dh_tube, dh_tube_child, alias_pid) = if use_sandbox {
2025         let (broker, child) =
2026             Tube::pair().exit_context(Exit::CreateTube, "failed to create tube")?;
2027         (Some(broker), Some(child), rand::random())
2028     } else {
2029         (None, None, process_id)
2030     };
2031 
2032     let tube_transporter =
2033         TubeTransporter::new(tube_transport_pipe, tubes, Some(alias_pid), dh_tube_child);
2034 
2035     // Register this child to be waited upon.
2036     let process_handle = Descriptor(child.as_raw_descriptor());
2037     wait_ctx
2038         .add(&process_handle, Token::Process(alias_pid))
2039         .exit_context(
2040             Exit::WaitContextAdd,
2041             "failed to add trigger to event context",
2042         )?;
2043 
2044     children.insert(
2045         alias_pid,
2046         ChildCleanup {
2047             process_type,
2048             child,
2049             dh_tube,
2050         },
2051     );
2052 
2053     if use_sandbox {
2054         wait_ctx
2055             .add(
2056                 children[&alias_pid]
2057                     .dh_tube
2058                     .as_ref()
2059                     .unwrap()
2060                     .get_read_notifier(),
2061                 Token::DuplicateHandle(alias_pid),
2062             )
2063             .exit_context(
2064                 Exit::WaitContextAdd,
2065                 "failed to add trigger to event context",
2066             )?;
2067     }
2068 
2069     Ok(ChildProcess {
2070         bootstrap_tube,
2071         tube_transporter,
2072         process_id,
2073         alias_pid,
2074     })
2075 }
2076 
2077 #[cfg(test)]
2078 mod tests {
2079     use base::thread::spawn_with_timeout;
2080 
2081     use super::*;
2082 
2083     /// Verifies that the supervisor loop exits normally with a single child that exits.
2084     #[test]
smoke_test()2085     fn smoke_test() {
2086         spawn_with_timeout(|| {
2087             let mut children: HashMap<u32, ChildCleanup> = HashMap::new();
2088             let mut wait_ctx: WaitContext<Token> = WaitContext::new().unwrap();
2089             let exit_events = vec![Event::new().unwrap()];
2090             let _child_main = spawn_child(
2091                 "ping",
2092                 ["127.0.0.1", "-n", "2"],
2093                 None,
2094                 None,
2095                 ProcessType::Main,
2096                 &mut children,
2097                 &mut wait_ctx,
2098                 /* skip_bootstrap= */ true,
2099                 /* use_sandbox= */ false,
2100                 vec![],
2101                 &[],
2102                 &Config::default(),
2103             );
2104 
2105             Supervisor::broker_supervise_loop(children, wait_ctx, exit_events).unwrap();
2106         })
2107         .try_join(Duration::from_secs(5))
2108         .unwrap();
2109     }
2110 
2111     /// Verifies that the supervisor loop exits normally when a device exits first, and then
2112     /// the main loop exits.
2113     #[test]
main_and_device_clean_exit()2114     fn main_and_device_clean_exit() {
2115         spawn_with_timeout(|| {
2116             let mut children: HashMap<u32, ChildCleanup> = HashMap::new();
2117             let mut wait_ctx: WaitContext<Token> = WaitContext::new().unwrap();
2118             let exit_events = vec![Event::new().unwrap()];
2119             let _child_main = spawn_child(
2120                 "ping",
2121                 ["127.0.0.1", "-n", "4"],
2122                 None,
2123                 None,
2124                 ProcessType::Main,
2125                 &mut children,
2126                 &mut wait_ctx,
2127                 /* skip_bootstrap= */ true,
2128                 /* use_sandbox= */ false,
2129                 vec![],
2130                 &[],
2131                 &Config::default(),
2132             );
2133             let _child_device = spawn_child(
2134                 "ping",
2135                 ["127.0.0.1", "-n", "2"],
2136                 None,
2137                 None,
2138                 ProcessType::Block,
2139                 &mut children,
2140                 &mut wait_ctx,
2141                 /* skip_bootstrap= */ true,
2142                 /* use_sandbox= */ false,
2143                 vec![],
2144                 &[],
2145                 &Config::default(),
2146             );
2147 
2148             Supervisor::broker_supervise_loop(children, wait_ctx, exit_events).unwrap();
2149         })
2150         .try_join(Duration::from_secs(5))
2151         .unwrap();
2152     }
2153 
2154     /// Verifies that the supervisor loop ends even if a device takes too long to exit.
2155     #[test]
device_takes_too_long_to_exit()2156     fn device_takes_too_long_to_exit() {
2157         spawn_with_timeout(|| {
2158             let mut children: HashMap<u32, ChildCleanup> = HashMap::new();
2159             let mut wait_ctx: WaitContext<Token> = WaitContext::new().unwrap();
2160             let exit_events = vec![Event::new().unwrap()];
2161             let _child_main = spawn_child(
2162                 "ping",
2163                 ["127.0.0.1", "-n", "2"],
2164                 None,
2165                 None,
2166                 ProcessType::Main,
2167                 &mut children,
2168                 &mut wait_ctx,
2169                 /* skip_bootstrap= */ true,
2170                 /* use_sandbox= */ false,
2171                 vec![],
2172                 &[],
2173                 &Config::default(),
2174             );
2175             let _child_device = spawn_child(
2176                 "ping",
2177                 ["127.0.0.1", "-n", "11"],
2178                 None,
2179                 None,
2180                 ProcessType::Block,
2181                 &mut children,
2182                 &mut wait_ctx,
2183                 /* skip_bootstrap= */ true,
2184                 /* use_sandbox= */ false,
2185                 vec![],
2186                 &[],
2187                 &Config::default(),
2188             );
2189 
2190             assert_eq!(
2191                 Supervisor::broker_supervise_loop(children, wait_ctx, exit_events)
2192                     .to_exit_code()
2193                     .unwrap(),
2194                 ExitCode::from(Exit::BrokerMainExitedTimeout),
2195             );
2196         })
2197         .try_join(Duration::from_secs(10))
2198         .unwrap();
2199     }
2200 
2201     /// Verifies that the supervisor loop ends even if the main process takes too long to exit.
2202     #[test]
main_takes_too_long_to_exit()2203     fn main_takes_too_long_to_exit() {
2204         spawn_with_timeout(|| {
2205             let mut children: HashMap<u32, ChildCleanup> = HashMap::new();
2206             let mut wait_ctx: WaitContext<Token> = WaitContext::new().unwrap();
2207             let exit_events = vec![Event::new().unwrap()];
2208             let _child_main = spawn_child(
2209                 "ping",
2210                 ["127.0.0.1", "-n", "11"],
2211                 None,
2212                 None,
2213                 ProcessType::Main,
2214                 &mut children,
2215                 &mut wait_ctx,
2216                 /* skip_bootstrap= */ true,
2217                 /* use_sandbox= */ false,
2218                 vec![],
2219                 &[],
2220                 &Config::default(),
2221             );
2222             let _child_device = spawn_child(
2223                 "ping",
2224                 ["127.0.0.1", "-n", "2"],
2225                 None,
2226                 None,
2227                 ProcessType::Block,
2228                 &mut children,
2229                 &mut wait_ctx,
2230                 /* skip_bootstrap= */ true,
2231                 /* use_sandbox= */ false,
2232                 vec![],
2233                 &[],
2234                 &Config::default(),
2235             );
2236 
2237             assert_eq!(
2238                 Supervisor::broker_supervise_loop(children, wait_ctx, exit_events)
2239                     .to_exit_code()
2240                     .unwrap(),
2241                 ExitCode::from(Exit::BrokerDeviceExitedTimeout),
2242             );
2243         })
2244         .try_join(Duration::from_secs(10))
2245         .unwrap();
2246     }
2247 
2248     /// Verifies that the supervisor loop ends even if a device takes too long to exit.
2249     #[test]
device_crash_returns_child_error()2250     fn device_crash_returns_child_error() {
2251         spawn_with_timeout(|| {
2252             let mut children: HashMap<u32, ChildCleanup> = HashMap::new();
2253             let mut wait_ctx: WaitContext<Token> = WaitContext::new().unwrap();
2254             let exit_events = vec![Event::new().unwrap()];
2255             let _child_main = spawn_child(
2256                 "ping",
2257                 ["127.0.0.1", "-n", "2"],
2258                 None,
2259                 None,
2260                 ProcessType::Main,
2261                 &mut children,
2262                 &mut wait_ctx,
2263                 /* skip_bootstrap= */ true,
2264                 /* use_sandbox= */ false,
2265                 vec![],
2266                 &[],
2267                 &Config::default(),
2268             );
2269             let _child_device = spawn_child(
2270                 "cmd",
2271                 ["/c", "exit -1"],
2272                 None,
2273                 None,
2274                 ProcessType::Block,
2275                 &mut children,
2276                 &mut wait_ctx,
2277                 /* skip_bootstrap= */ true,
2278                 /* use_sandbox= */ false,
2279                 vec![],
2280                 &[],
2281                 &Config::default(),
2282             );
2283 
2284             assert_eq!(
2285                 Supervisor::broker_supervise_loop(children, wait_ctx, exit_events)
2286                     .to_exit_code()
2287                     .unwrap(),
2288                 (to_process_type_error(-1i32 as u32, ProcessType::Block) as i32),
2289             );
2290         })
2291         .try_join(Duration::from_secs(10))
2292         .unwrap();
2293     }
2294 
2295     /// Verifies that sigterm makes the supervisor loop signal the exit event.
2296     #[test]
sigterm_signals_exit_event()2297     fn sigterm_signals_exit_event() {
2298         let exit_event = Event::new().unwrap();
2299         let exit_event_copy = exit_event.try_clone().unwrap();
2300 
2301         spawn_with_timeout(move || {
2302             let sigterm_event = Event::new().unwrap();
2303             let mut wait_ctx: WaitContext<Token> = WaitContext::new().unwrap();
2304             let mut children: HashMap<u32, ChildCleanup> = HashMap::new();
2305             let _child_main = spawn_child(
2306                 "ping",
2307                 ["127.0.0.1", "-n", "3"],
2308                 None,
2309                 None,
2310                 ProcessType::Main,
2311                 &mut children,
2312                 &mut wait_ctx,
2313                 /* skip_bootstrap= */ true,
2314                 /* use_sandbox= */ false,
2315                 vec![],
2316                 &[],
2317                 &Config::default(),
2318             );
2319             wait_ctx.add(&sigterm_event, Token::Sigterm).unwrap();
2320             sigterm_event.signal().unwrap();
2321 
2322             assert_eq!(
2323                 Supervisor::broker_supervise_loop(children, wait_ctx, vec![exit_event_copy])
2324                     .to_exit_code()
2325                     .unwrap(),
2326                 ExitCode::from(Exit::KilledBySignal),
2327             );
2328         })
2329         .try_join(Duration::from_secs(10))
2330         .unwrap();
2331 
2332         exit_event.wait_timeout(Duration::from_secs(0)).unwrap();
2333     }
2334 }
2335