blob: 08b6bdebcda6e758b042d0bfa4c20339f17992a3 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// TODO Follow 2018 idioms
#![allow(elided_lifetimes_in_paths)]
use {
anyhow::{Context as _, Error},
component_manager_lib::{
builtin_environment::{BuiltinEnvironment, BuiltinEnvironmentBuilder},
klog, startup,
},
fuchsia_async as fasync,
fuchsia_runtime::{job_default, process_self},
fuchsia_trace_provider as trace_provider,
fuchsia_zircon::JobCriticalOptions,
log::*,
std::cell::Cell,
std::{panic, process, thread, time::Duration},
};
fn main() -> Result<(), Error> {
// Make sure we exit if there is a panic. Add this hook before we init the
// KernelLogger because it installs its own hook and then calls any
// existing hook.
panic::set_hook(Box::new(|_| {
println!("Panic in component_manager, aborting process.");
// TODO remove after 43671 is resolved
std::thread::spawn(move || {
let mut nap_duration = Duration::from_secs(1);
// Do a short sleep, hopefully under "normal" circumstances the
// process will exit before this is printed
thread::sleep(nap_duration);
println!("component manager abort was started");
// set a fairly long duration so we don't spam logs
nap_duration = Duration::from_secs(30);
loop {
thread::sleep(nap_duration);
println!("component manager alive long after abort");
}
});
process::abort();
}));
// Set ourselves as critical to our job. If we do not fail gracefully, our
// job will be killed.
if let Err(err) =
job_default().set_critical(JobCriticalOptions::RETCODE_NONZERO, &process_self())
{
panic!("Component manager failed to set itself as critical: {:?}", err);
}
klog::KernelLogger::init();
info!("Component manager is starting up...");
// Enable tracing in Component Manager
trace_provider::trace_provider_create_with_fdio();
// The following usage of `std::cell::Cell` is brought by the fact that
// we'd like to configure the number of threads to spawn for our executor.
// Unfortunately, the configured value lives in the config files that are
// parsed by `BuiltinEnvironmentBuilder`. This is problematic because
// *building* this object is asynchronous, and thus needs to run in an
// async context. So we first need to build the `BuiltinEnvironment`
// synchronously, and then extract the configured number of threads into
// a local variable before running the root environment using the executor.
// TODO(64534): Fix this dance.
let builtin_environment: Cell<Option<BuiltinEnvironment>> = Cell::new(None);
let mut executor = fasync::Executor::new().context("error creating executor")?;
executor.run_singlethreaded(async {
match build_environment().await {
Ok(environment) => {
builtin_environment.set(Some(environment));
}
Err(error) => {
panic!("Component manager setup failed: {:?}", error);
}
}
});
let builtin_environment = builtin_environment.take().unwrap();
// We store a copy of `num_threads` here so that we can safely move
// `builtin_environment` into async block below.
let num_threads = builtin_environment.num_threads;
let fut = async move {
if let Err(error) = builtin_environment.run_root().await {
error!("Failed to bind to root component: {:?}", error);
process::exit(1);
}
};
executor.run(fut, num_threads);
Ok(())
}
async fn build_environment() -> Result<BuiltinEnvironment, Error> {
let args = match startup::Arguments::from_args() {
Ok(args) => args,
Err(err) => {
error!("{}\n{}", err, startup::Arguments::usage());
return Err(err);
}
};
BuiltinEnvironmentBuilder::new()
.set_args(args)
.populate_config_from_args()
.await?
.create_utc_clock()
.await?
.add_elf_runner()?
.include_namespace_resolvers()
.build()
.await
}