blob: 26d7d918725b89f06226db79662bb01023c4b7ea [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::{format_err, Context as _, Error},
component_manager_lib::{
builtin_environment::{BuiltinEnvironment, BuiltinEnvironmentBuilder},
config::RuntimeConfig,
klog, startup,
},
fuchsia_async as fasync,
fuchsia_runtime::{job_default, process_self},
fuchsia_trace_provider as trace_provider,
fuchsia_zircon::JobCriticalOptions,
log::*,
std::path::PathBuf,
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();
let runtime_config = build_runtime_config()?;
let num_threads = runtime_config.num_threads;
let fut = async move {
let mut builtin_environment = match build_environment(runtime_config).await {
Ok(environment) => environment,
Err(error) => {
error!("Component manager setup failed: {:?}", error);
process::exit(1);
}
};
if let Err(error) = builtin_environment.run_root().await {
error!("Failed to bind to root component: {:?}", error);
process::exit(1);
}
};
let mut executor = fasync::Executor::new().context("error creating executor")?;
executor.run(fut, num_threads);
Ok(())
}
fn build_runtime_config() -> Result<RuntimeConfig, Error> {
let args = match startup::Arguments::from_args() {
Ok(args) => args,
Err(err) => {
error!("{}\n{}", err, startup::Arguments::usage());
return Err(err);
}
};
let path = PathBuf::from(&args.config);
let mut config = match RuntimeConfig::load_from_file(&path) {
Ok(config) => {
info!("Loaded runtime config from {}", path.display());
config
}
Err(err) => {
return Err(format_err!("Failed to load runtime config: {}", err));
}
};
match (config.root_component_url.as_ref(), args.root_component_url.as_ref()) {
(Some(_url), None) => Ok(config),
(None, Some(url)) => {
config.root_component_url = Some(url.clone());
Ok(config)
}
(None, None) => {
Err(format_err!("`root_component_url` not provided. This field must be provided either as a command line argument or config file parameter."))
}
(Some(_), Some(_)) => {
Err(format_err!("`root_component_url` set in two places: as a command line argument and a config file parameter. This field can only be set in one of those places."))
}
}
}
async fn build_environment(config: RuntimeConfig) -> Result<BuiltinEnvironment, Error> {
BuiltinEnvironmentBuilder::new()
.set_runtime_config(config)
.create_utc_clock()
.await?
.add_elf_runner()?
.include_namespace_resolvers()
.build()
.await
}