blob: 69c49a47d0fc3d96596a3e12de59c87f79f648df [file] [log] [blame] [edit]
// Copyright 2021 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.
#![recursion_limit = "256"]
#![allow(clippy::too_many_arguments)]
// TODO(fxbug.dev/122028): Remove this allow once the lint is fixed.
#![allow(unknown_lints, clippy::extra_unused_type_parameters)]
#[macro_use]
extern crate fuchsia_inspect_contrib;
#[macro_use]
extern crate macro_rules_attribute;
use crate::{
execution::{Container, ContainerServiceConfig},
logging::*,
};
use anyhow::Error;
use fidl::endpoints::ControlHandle;
use fidl_fuchsia_component_runner as frunner;
use fidl_fuchsia_process_lifecycle as flifecycle;
use fidl_fuchsia_starnix_container as fstarcontainer;
use fuchsia_async as fasync;
use fuchsia_component::server::ServiceFs;
use fuchsia_inspect::health::Reporter;
use fuchsia_runtime as fruntime;
use futures::{StreamExt, TryStreamExt};
#[macro_use]
mod trace;
mod arch;
mod auth;
mod bpf;
mod device;
mod diagnostics;
mod drop_notifier;
mod dynamic_thread_spawner;
mod execution;
mod fs;
mod loader;
mod lock_ordering;
mod logging;
mod mm;
mod mutable_state;
mod power;
mod selinux;
mod signals;
mod syscalls;
mod task;
mod time;
mod types;
mod vdso;
mod vmex_resource;
#[cfg(test)]
mod testing;
fn maybe_serve_lifecycle() {
if let Some(lifecycle) =
fruntime::take_startup_handle(fruntime::HandleInfo::new(fruntime::HandleType::Lifecycle, 0))
{
fasync::Task::local(async move {
if let Ok(mut stream) =
fidl::endpoints::ServerEnd::<flifecycle::LifecycleMarker>::new(lifecycle.into())
.into_stream()
{
if let Ok(Some(request)) = stream.try_next().await {
match request {
flifecycle::LifecycleRequest::Stop { control_handle } => {
control_handle.shutdown();
std::process::exit(0);
}
}
}
}
})
.detach();
}
}
enum KernelServices {
/// This service lets clients start a single container using this kernel.
///
/// The `starnix_kernel` is capable of running a single container, which can be started using
/// this protocol. Attempts to use this protocol a second time will fail.
///
/// This service uses the `ComponentRunner` protocol but the service is exposed using the name
/// `fuchsia.starnix.container.Runner` to reduce confusion with the instance of the
/// `ComponentRunner` protocol that runs components inside the container.
ContainerRunner(frunner::ComponentRunnerRequestStream),
/// This service lets clients run components inside the container being run by this kernel.
///
/// This service will wait to process any requests until the kernel starts a container.
///
/// This service is also exposed via the container itself.
ComponentRunner(frunner::ComponentRunnerRequestStream),
/// This service lets clients control the container being run by this kernel.
///
/// This service will wait to process any requests until the kernel starts a container.
///
/// This service is also exposed via the container itself.
ContainerController(fstarcontainer::ControllerRequestStream),
}
async fn build_container(
stream: frunner::ComponentRunnerRequestStream,
returned_config: &mut Option<ContainerServiceConfig>,
) -> Result<Container, Error> {
let (container, config) = execution::create_component_from_stream(stream).await?;
*returned_config = Some(config);
Ok(container)
}
#[fuchsia::main(logging_tags = ["starnix"], logging_blocking)]
async fn main() -> Result<(), Error> {
// Because the starnix kernel state is shared among all of the processes in the same job,
// we need to kill those in addition to the process which panicked.
kill_job_on_panic::install_hook("\n\n\n\nSTARNIX KERNEL PANIC\n\n\n\n");
let _inspect_server_task = inspect_runtime::publish(
fuchsia_inspect::component::init_inspector_with_size(1_000_000),
inspect_runtime::PublishOptions::default(),
);
let mut health = fuchsia_inspect::component::health();
health.set_starting_up();
fuchsia_trace_provider::trace_provider_create_with_fdio();
trace_instant!(
trace_category_starnix!(),
trace_name_start_kernel!(),
fuchsia_trace::Scope::Thread
);
let container = async_lock::OnceCell::<Container>::new();
maybe_serve_lifecycle();
let mut fs = ServiceFs::new_local();
fs.dir("svc")
.add_fidl_service_at("fuchsia.starnix.container.Runner", KernelServices::ContainerRunner)
.add_fidl_service(KernelServices::ComponentRunner)
.add_fidl_service(KernelServices::ContainerController);
#[cfg(target_arch = "x86_64")]
{
fuchsia_inspect::component::inspector().root().record_string(
"x86_64_extended_pstate_strategy",
format!("{:?}", *extended_pstate::x86_64::PREFERRED_STRATEGY),
);
}
log_debug!("Serving kernel services on outgoing directory handle.");
fs.take_and_serve_directory_handle()?;
health.set_ok();
fs.for_each_concurrent(None, |request: KernelServices| async {
match request {
KernelServices::ContainerRunner(stream) => {
let mut config: Option<ContainerServiceConfig> = None;
let container = container
.get_or_try_init(|| build_container(stream, &mut config))
.await
.expect("failed to start container");
if let Some(config) = config {
container
.serve(config)
.await
.expect("failed to serve the expected services from the container");
}
}
KernelServices::ComponentRunner(stream) => {
execution::serve_component_runner(stream, container.wait().await)
.await
.expect("failed to start component runner");
}
KernelServices::ContainerController(stream) => {
execution::serve_container_controller(stream, container.wait().await)
.await
.expect("failed to start container controller");
}
}
})
.await;
Ok(())
}