proc_init/
lib.rs

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