xref: /aosp_15_r20/external/crosvm/broker_ipc/src/lib.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 shared code between the broker & its children, specifically any IPC messages or common
6 //! bootstrapping code.
7 
8 use std::fs::File;
9 use std::fs::OpenOptions;
10 use std::path::PathBuf;
11 
12 use anyhow::Context;
13 use base::enable_high_res_timers;
14 use base::syslog;
15 use base::syslog::LogArgs;
16 use base::EnabledHighResTimer;
17 use base::FromRawDescriptor;
18 use base::IntoRawDescriptor;
19 use base::SafeDescriptor;
20 use base::SendTube;
21 #[cfg(feature = "process-invariants")]
22 pub use broker_ipc_product::init_broker_process_invariants;
23 use broker_ipc_product::init_child_crash_reporting;
24 use broker_ipc_product::product_child_setup;
25 #[cfg(feature = "process-invariants")]
26 pub use broker_ipc_product::EmulatorProcessInvariants;
27 use broker_ipc_product::ProductAttributes;
28 use serde::Deserialize;
29 use serde::Serialize;
30 
31 /// Arguments that are common to all devices & helper processes.
32 #[derive(Serialize, Deserialize)]
33 pub struct CommonChildStartupArgs {
34     log_args: LogArgs,
35     syslog_file: Option<SafeDescriptor>,
36     metrics_tube: Option<SendTube>,
37     product_attrs: ProductAttributes,
38 }
39 
40 impl CommonChildStartupArgs {
41     #[allow(clippy::new_without_default)]
new( log_args: &LogArgs, syslog_path: Option<PathBuf>, #[cfg(feature = "crash-report")] _crash_attrs: crash_report::CrashReportAttributes, #[cfg(feature = "process-invariants")] _process_invariants: EmulatorProcessInvariants, metrics_tube: Option<SendTube>, ) -> anyhow::Result<Self>42     pub fn new(
43         log_args: &LogArgs,
44         syslog_path: Option<PathBuf>,
45         #[cfg(feature = "crash-report")] _crash_attrs: crash_report::CrashReportAttributes,
46         #[cfg(feature = "process-invariants")] _process_invariants: EmulatorProcessInvariants,
47         metrics_tube: Option<SendTube>,
48     ) -> anyhow::Result<Self> {
49         Ok(Self {
50             log_args: log_args.clone(),
51             product_attrs: ProductAttributes {},
52             metrics_tube,
53             syslog_file: log_file_from_path(syslog_path)?,
54         })
55     }
56 }
57 
58 pub struct ChildLifecycleCleanup {
59     _timer_resolution: Box<dyn EnabledHighResTimer>,
60 }
61 
62 /// Initializes crash reporting, metrics, logging, and product specific features
63 /// for a process.
64 ///
65 /// Returns a value that should be dropped when the process exits.
common_child_setup(args: CommonChildStartupArgs) -> anyhow::Result<ChildLifecycleCleanup>66 pub fn common_child_setup(args: CommonChildStartupArgs) -> anyhow::Result<ChildLifecycleCleanup> {
67     // Logging must initialize first in case there are other startup errors.
68     let mut cfg = syslog::LogConfig {
69         log_args: args.log_args,
70         ..Default::default()
71     };
72     if let Some(log_file_descriptor) = args.syslog_file {
73         let log_file =
74             // SAFETY:
75             // Safe because we are taking ownership of a SafeDescriptor.
76             unsafe { File::from_raw_descriptor(log_file_descriptor.into_raw_descriptor()) };
77         cfg.pipe = Some(Box::new(log_file));
78         cfg.log_args.stderr = false;
79     } else {
80         cfg.log_args.stderr = true;
81     }
82     syslog::init_with(cfg)?;
83 
84     // Crash reporting should start as early as possible, in case other startup tasks fail.
85     init_child_crash_reporting(&args.product_attrs);
86 
87     // Initialize anything product specific.
88     product_child_setup(&args.product_attrs)?;
89 
90     if let Some(metrics_tube) = args.metrics_tube {
91         metrics::initialize(metrics_tube);
92     }
93 
94     let timer_resolution = enable_high_res_timers().context("failed to enable high res timer")?;
95 
96     Ok(ChildLifecycleCleanup {
97         _timer_resolution: timer_resolution,
98     })
99 }
100 
log_file_from_path(path: Option<PathBuf>) -> anyhow::Result<Option<SafeDescriptor>>101 pub(crate) fn log_file_from_path(path: Option<PathBuf>) -> anyhow::Result<Option<SafeDescriptor>> {
102     Ok(match path {
103         Some(path) => Some(SafeDescriptor::from(
104             OpenOptions::new()
105                 .append(true)
106                 .create(true)
107                 .open(path.as_path())
108                 .context(format!("failed to open log file {}", path.display()))?,
109         )),
110         None => None,
111     })
112 }
113