blob: 0930d9fa5ba75787c6a45d8025f9cbeb1c124b93 [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.
#[cfg(target_arch = "aarch64")]
use builtins::smc_resource::SmcResource;
use crate::{diagnostics, model::component::WeakComponentInstance};
#[cfg(target_arch = "x86_64")]
use builtins::ioport_resource::IoportResource;
use {
crate::{
bootfs::BootfsSvc,
builtin::{
builtin_resolver::{BuiltinResolver, SCHEME as BUILTIN_SCHEME},
crash_introspect::CrashIntrospectSvc,
fuchsia_boot_resolver::{FuchsiaBootResolverBuiltinCapability, SCHEME as BOOT_SCHEME},
log::{ReadOnlyLog, WriteOnlyLog},
realm_builder::{
RealmBuilderResolver, RealmBuilderRunnerFactory,
RUNNER_NAME as REALM_BUILDER_RUNNER_NAME, SCHEME as REALM_BUILDER_SCHEME,
},
runner::{BuiltinRunner, BuiltinRunnerFactory},
svc_stash_provider::SvcStashCapability,
system_controller::SystemController,
time::{create_utc_clock, UtcTimeMaintainer},
},
capability::{BuiltinCapability, CapabilitySource, DerivedCapability, FrameworkCapability},
diagnostics::{lifecycle::ComponentLifecycleTimeStats, task_metrics::ComponentTreeStats},
framework::{
binder::BinderFrameworkCapability,
factory::{FactoryCapabilityHost, FactoryFrameworkCapability},
introspector::IntrospectorFrameworkCapability,
lifecycle_controller::{LifecycleController, LifecycleControllerFrameworkCapability},
namespace::NamespaceFrameworkCapability,
pkg_dir::PkgDirectoryFrameworkCapability,
realm::RealmFrameworkCapability,
realm_query::{RealmQuery, RealmQueryFrameworkCapability},
route_validator::RouteValidatorFrameworkCapability,
},
inspect_sink_provider::InspectSinkProvider,
model::events::registry::EventSubscription,
model::{
component::manager::ComponentManagerInstance,
environment::Environment,
event_logger::EventLogger,
events::{
registry::EventRegistry,
serve::serve_event_stream,
source_factory::{EventSourceFactory, EventSourceFactoryCapability},
stream_provider::EventStreamProvider,
},
hooks::EventType,
model::{Model, ModelParams},
resolver::{box_arc_resolver, ResolverRegistry},
storage::admin_protocol::StorageAdminDerivedCapability,
structured_dict::ComponentInput,
token::InstanceRegistry,
},
root_stop_notifier::RootStopNotifier,
sandbox_util::LaunchTaskOnReceive,
},
::routing::{
capability_source::{ComponentCapability, InternalCapability},
component_instance::TopInstanceInterface,
environment::{DebugRegistry, RunnerRegistry},
policy::GlobalPolicyChecker,
},
anyhow::{format_err, Context as _, Error},
builtins::{arguments::Arguments as BootArguments, root_job::RootJob},
builtins::{
cpu_resource::CpuResource, debug_resource::DebugResource,
debuglog_resource::DebuglogResource, energy_info_resource::EnergyInfoResource,
factory_items::FactoryItems, framebuffer_resource::FramebufferResource,
hypervisor_resource::HypervisorResource, info_resource::InfoResource,
iommu_resource::IommuResource, irq_resource::IrqResource, items::Items,
kernel_stats::KernelStats, mexec_resource::MexecResource, mmio_resource::MmioResource,
msi_resource::MsiResource, power_resource::PowerResource,
profile_resource::ProfileResource, root_resource::RootResource,
vmex_resource::VmexResource,
},
cm_config::{RuntimeConfig, VmexSource},
cm_rust::{Availability, RunnerRegistration, UseEventStreamDecl, UseSource},
cm_types::Name,
elf_runner::{
crash_info::CrashRecords,
process_launcher::ProcessLauncher,
vdso_vmo::{get_next_vdso_vmo, get_stable_vdso_vmo, get_vdso_vmo},
},
fidl::endpoints::{DiscoverableProtocolMarker, ProtocolMarker, RequestStream, ServerEnd},
fidl_fuchsia_boot as fboot,
fidl_fuchsia_component_internal::BuiltinBootResolver,
fidl_fuchsia_component_resolution as fresolution,
fidl_fuchsia_diagnostics_types::Task as DiagnosticsTask,
fidl_fuchsia_io as fio, fidl_fuchsia_kernel as fkernel, fidl_fuchsia_process as fprocess,
fidl_fuchsia_sys2 as fsys, fidl_fuchsia_time as ftime, fuchsia_async as fasync,
fuchsia_component::server::*,
fuchsia_inspect::{component, health::Reporter, stats::InspectorExt, Inspector},
fuchsia_runtime::{take_startup_handle, HandleInfo, HandleType},
fuchsia_zbi::{ZbiParser, ZbiType},
fuchsia_zircon::{self as zx, Clock, Resource},
futures::{future::BoxFuture, FutureExt, StreamExt},
moniker::{Moniker, MonikerBase},
std::sync::Arc,
tracing::{info, warn},
vfs::{directory::entry::OpenRequest, path::Path, ToObjectRequest},
};
#[cfg(test)]
use crate::model::resolver::Resolver;
// Allow shutdown to take up to an hour.
pub static SHUTDOWN_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(60 * 60);
// LINT.IfChange
/// Set the size of the inspect VMO to be 350 KiB.
const INSPECTOR_SIZE: usize = 350 * 1024;
// LINT.ThenChange(/src/tests/diagnostics/meta/component_manager_status_tests.cml)
pub struct BuiltinEnvironmentBuilder {
// TODO(60804): Make component manager's namespace injectable here.
runtime_config: Option<RuntimeConfig>,
top_instance: Option<Arc<ComponentManagerInstance>>,
bootfs_svc: Option<BootfsSvc>,
runners: Vec<(Name, Arc<dyn BuiltinRunnerFactory>)>,
resolvers: ResolverRegistry,
utc_clock: Option<Arc<Clock>>,
add_environment_resolvers: bool,
inspector: Option<Inspector>,
crash_records: CrashRecords,
instance_registry: Arc<InstanceRegistry>,
}
impl Default for BuiltinEnvironmentBuilder {
fn default() -> Self {
Self {
runtime_config: None,
top_instance: None,
bootfs_svc: None,
runners: vec![],
resolvers: ResolverRegistry::default(),
utc_clock: None,
add_environment_resolvers: false,
inspector: None,
crash_records: CrashRecords::new(),
instance_registry: InstanceRegistry::new(),
}
}
}
impl BuiltinEnvironmentBuilder {
pub fn new() -> Self {
BuiltinEnvironmentBuilder::default()
}
pub fn set_runtime_config(mut self, runtime_config: RuntimeConfig) -> Self {
assert!(self.runtime_config.is_none());
let top_instance = Arc::new(ComponentManagerInstance::new(
runtime_config.namespace_capabilities.clone(),
runtime_config.builtin_capabilities.clone(),
));
self.runtime_config = Some(runtime_config);
self.top_instance = Some(top_instance);
self
}
pub fn set_bootfs_svc(mut self, bootfs_svc: BootfsSvc) -> Self {
self.bootfs_svc = Some(bootfs_svc);
self
}
#[cfg(test)]
pub fn set_inspector(mut self, inspector: Inspector) -> Self {
self.inspector = Some(inspector);
self
}
/// Create a UTC clock if required.
/// Not every instance of component_manager running on the system maintains a
/// UTC clock. Only the root component_manager should have the `maintain-utc-clock`
/// config flag set.
pub async fn create_utc_clock(mut self, bootfs: &Option<BootfsSvc>) -> Result<Self, Error> {
let runtime_config = self
.runtime_config
.as_ref()
.ok_or(format_err!("Runtime config should be set to create utc clock."))?;
self.utc_clock = if runtime_config.maintain_utc_clock {
Some(Arc::new(create_utc_clock(&bootfs).await.context("failed to create UTC clock")?))
} else {
None
};
Ok(self)
}
pub fn add_builtin_runner(self) -> Result<Self, Error> {
use crate::builtin::builtin_runner::BuiltinRunner;
use crate::builtin::builtin_runner::ElfRunnerResources;
let runtime_config = self
.runtime_config
.as_ref()
.ok_or(format_err!("Runtime config should be set to add builtin runner."))?;
let runner = Arc::new(BuiltinRunner::new(
self.top_instance.clone().unwrap().task_group(),
ElfRunnerResources {
security_policy: runtime_config.security_policy.clone(),
utc_clock: self.utc_clock.clone(),
crash_records: self.crash_records.clone(),
instance_registry: self.instance_registry.clone(),
},
));
Ok(self.add_runner("builtin".parse().unwrap(), runner))
}
pub fn add_runner(mut self, name: Name, runner: Arc<dyn BuiltinRunnerFactory>) -> Self {
// We don't wrap these in a BuiltinRunner immediately because that requires the
// RuntimeConfig, which may be provided after this or may fall back to the default.
self.runners.push((name, runner));
self
}
#[cfg(test)]
pub fn add_resolver(
mut self,
scheme: String,
resolver: Box<dyn Resolver + Send + Sync + 'static>,
) -> Self {
self.resolvers.register(scheme, resolver);
self
}
/// Adds standard resolvers whose dependencies are available in the process's namespace and for
/// whose scheme no resolver is registered through `add_resolver` by the time `build()` is
/// is called. This includes:
/// - A fuchsia-boot resolver if /boot is available.
/// - A fuchsia-pkg resolver, if /svc/fuchsia.sys.Loader is present.
/// - This resolver implementation proxies to that protocol (which is the v1 resolver
/// equivalent). This is used for tests or other scenarios where component_manager runs
/// as a v1 component.
pub fn include_namespace_resolvers(mut self) -> Self {
self.add_environment_resolvers = true;
self
}
pub async fn build(mut self) -> Result<BuiltinEnvironment, Error> {
let runtime_config = self
.runtime_config
.ok_or(format_err!("Runtime config is required for BuiltinEnvironment."))?;
let system_resource_handle =
take_startup_handle(HandleType::SystemResource.into()).map(zx::Resource::from);
if let Some(bootfs_svc) = self.bootfs_svc {
// Set up the Rust bootfs VFS, and bind to the '/boot' namespace. This should
// happen as early as possible when building the component manager as other objects
// may require reading from '/boot' for configuration, etc.
let bootfs_svc = match runtime_config.vmex_source {
VmexSource::SystemResource => bootfs_svc
.ingest_bootfs_vmo_with_system_resource(&system_resource_handle)?
.publish_kernel_vmo(get_stable_vdso_vmo()?)?
.publish_kernel_vmo(get_next_vdso_vmo()?)?
.publish_kernel_vmo(get_vdso_vmo(c"vdso/test1")?)?
.publish_kernel_vmo(get_vdso_vmo(c"vdso/test2")?)?
.publish_kernel_vmos(HandleType::KernelFileVmo, 0)?,
VmexSource::Namespace => {
let mut bootfs_svc = bootfs_svc.ingest_bootfs_vmo_with_namespace_vmex().await?;
// This is a nested component_manager - tolerate missing vdso's.
for kernel_vmo in [
get_stable_vdso_vmo(),
get_next_vdso_vmo(),
get_vdso_vmo(c"vdso/test1"),
get_vdso_vmo(c"vdso/test2"),
]
.into_iter()
.filter_map(|v| v.ok())
{
bootfs_svc = bootfs_svc.publish_kernel_vmo(kernel_vmo)?;
}
bootfs_svc.publish_kernel_vmos(HandleType::KernelFileVmo, 0)?
}
};
bootfs_svc.create_and_bind_vfs()?;
}
let root_component_url = match runtime_config.root_component_url.as_ref() {
Some(url) => url.clone(),
None => {
return Err(format_err!("Root component url is required from RuntimeConfig."));
}
};
register_builtin_resolver(&mut self.resolvers);
let boot_resolver = if self.add_environment_resolvers {
register_boot_resolver(&mut self.resolvers, &runtime_config).await?
} else {
None
};
let realm_builder_resolver = match runtime_config.realm_builder_resolver_and_runner {
fidl_fuchsia_component_internal::RealmBuilderResolverAndRunner::Namespace => {
self.runners.push((
REALM_BUILDER_RUNNER_NAME.parse().unwrap(),
Arc::new(RealmBuilderRunnerFactory::new()),
));
Some(register_realm_builder_resolver(&mut self.resolvers)?)
}
fidl_fuchsia_component_internal::RealmBuilderResolverAndRunner::None => None,
};
let capability_passthrough = match runtime_config.realm_builder_resolver_and_runner {
fidl_fuchsia_component_internal::RealmBuilderResolverAndRunner::Namespace => true,
fidl_fuchsia_component_internal::RealmBuilderResolverAndRunner::None => false,
};
let runner_map = self
.runners
.iter()
.map(|(name, _)| {
(
name.clone(),
RunnerRegistration {
source_name: name.clone(),
target_name: name.clone(),
source: cm_rust::RegistrationSource::Self_,
},
)
})
.collect();
let runtime_config = Arc::new(runtime_config);
let top_instance = self.top_instance.unwrap().clone();
let params = ModelParams {
root_component_url: root_component_url.as_str().to_owned(),
root_environment: Environment::new_root(
&top_instance,
RunnerRegistry::new(runner_map),
self.resolvers,
DebugRegistry::default(),
),
runtime_config: Arc::clone(&runtime_config),
top_instance,
};
let model = Model::new(params, self.instance_registry).await?;
// Wrap BuiltinRunnerFactory in BuiltinRunner now that we have the definite RuntimeConfig.
let builtin_runners = self
.runners
.into_iter()
.map(|(name, runner)| {
BuiltinRunner::new(name, runner, runtime_config.security_policy.clone())
})
.collect();
Ok(BuiltinEnvironment::new(
model,
runtime_config,
system_resource_handle,
builtin_runners,
boot_resolver,
realm_builder_resolver,
self.utc_clock,
self.inspector.unwrap_or(component::init_inspector_with_size(INSPECTOR_SIZE).clone()),
self.crash_records,
capability_passthrough,
)
.await?)
}
}
/// Constructs a [ComponentInput] that contains built-in capabilities.
struct RootComponentInputBuilder {
input: ComponentInput,
top_instance: Arc<ComponentManagerInstance>,
policy_checker: GlobalPolicyChecker,
builtin_capabilities: Vec<cm_rust::CapabilityDecl>,
}
impl RootComponentInputBuilder {
fn new(
top_instance: Arc<ComponentManagerInstance>,
runtime_config: &Arc<RuntimeConfig>,
) -> Self {
Self {
input: ComponentInput::default(),
top_instance,
policy_checker: GlobalPolicyChecker::new(runtime_config.security_policy.clone()),
builtin_capabilities: runtime_config.builtin_capabilities.clone(),
}
}
/// Adds a new builtin protocol to the input that will be given to the root component. If the
/// protocol is not listed in `self.builtin_capabilities`, then it will silently be omitted
/// from the input.
fn add_builtin_protocol_if_enabled<P>(
&mut self,
task_to_launch: impl Fn(P::RequestStream) -> BoxFuture<'static, Result<(), anyhow::Error>>
+ Sync
+ Send
+ 'static,
) where
P: DiscoverableProtocolMarker + ProtocolMarker,
{
let name = Name::new(P::PROTOCOL_NAME).unwrap();
// TODO: check capability type too
// TODO: if we store the capabilities in a hashmap by name, then we can remove them as
// they're added and confirm at the end that we've not been asked to enable something
// unknown.
if self.builtin_capabilities.iter().find(|decl| decl.name() == &name).is_none() {
// This builtin protocol is not enabled based on the runtime config, so don't add the
// capability to the input.
return;
}
let capability_source = CapabilitySource::Builtin {
capability: InternalCapability::Protocol(name.clone()),
top_instance: Arc::downgrade(&self.top_instance),
};
let launch = LaunchTaskOnReceive::new(
self.top_instance.task_group().as_weak(),
name.clone(),
Some((self.policy_checker.clone(), capability_source)),
Arc::new(move |server_end, _| {
task_to_launch(crate::sandbox_util::take_handle_as_stream::<P>(server_end)).boxed()
}),
);
match self.input.insert_capability(
&P::PROTOCOL_NAME.parse::<Name>().unwrap(),
launch.into_router().into(),
) {
Ok(()) => (),
Err(e) => warn!("failed to add {name} to root component input: {e:?}"),
}
}
fn add_namespace_protocol(&mut self, protocol: &cm_rust::ProtocolDecl) {
let path = protocol.source_path.as_ref().unwrap().to_string();
let capability_source = CapabilitySource::Namespace {
capability: ComponentCapability::Protocol(protocol.clone()),
top_instance: Arc::downgrade(&self.top_instance),
};
let launch = LaunchTaskOnReceive::new(
self.top_instance.task_group().as_weak(),
"namespace capability dispatcher",
Some((self.policy_checker.clone(), capability_source)),
Arc::new(move |server_end, _| {
let path = path.clone();
let fut = async move {
fuchsia_fs::node::open_channel_in_namespace(
&path,
fio::OpenFlags::empty(),
ServerEnd::new(server_end),
)
.map_err(|e| {
warn!(
"failed to open capability in component_manager's namespace \
\"{path}\": {e}"
);
format_err!("{e:?}")
})
};
fut.boxed()
}),
);
match self.input.insert_capability(&protocol.name, launch.into_router().into()) {
Ok(()) => (),
Err(e) => warn!("failed to add {} to root component input: {e:?}", protocol.name),
}
}
fn build(self) -> ComponentInput {
self.input
}
}
/// The built-in environment consists of the set of the root services and framework services. Use
/// BuiltinEnvironmentBuilder to construct one.
///
/// The available built-in capabilities depends on the configuration provided in Arguments:
/// * If [RuntimeConfig::use_builtin_process_launcher] is true, a fuchsia.process.Launcher service
/// is available.
/// * If [RuntimeConfig::maintain_utc_clock] is true, a fuchsia.time.Maintenance service is
/// available.
pub struct BuiltinEnvironment {
pub model: Arc<Model>,
pub realm_query: Option<Arc<RealmQuery>>,
pub lifecycle_controller: Option<Arc<LifecycleController>>,
// TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
#[allow(dead_code)]
pub event_registry: Arc<EventRegistry>,
pub event_source_factory: Arc<EventSourceFactory>,
pub factory_capability_host: Arc<FactoryCapabilityHost>,
pub stop_notifier: Arc<RootStopNotifier>,
// TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
#[allow(dead_code)]
pub inspect_sink_provider: Arc<InspectSinkProvider>,
// TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
#[allow(dead_code)]
pub event_stream_provider: Arc<EventStreamProvider>,
// TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
#[allow(dead_code)]
pub event_logger: Option<Arc<EventLogger>>,
// TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
#[allow(dead_code)]
pub component_tree_stats: Arc<ComponentTreeStats<DiagnosticsTask>>,
// Keeps the inspect node alive.
_component_lifecycle_time_stats: Arc<ComponentLifecycleTimeStats>,
// Keeps the inspect node alive.
_component_escrow_duration_status: Arc<diagnostics::escrow::DurationStats>,
pub debug: bool,
// TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
#[allow(dead_code)]
pub num_threads: usize,
// TODO(https://fxbug.dev/332389972): Remove or explain #[allow(dead_code)].
#[allow(dead_code)]
pub realm_builder_resolver: Option<Arc<RealmBuilderResolver>>,
pub root_component_input: ComponentInput,
capability_passthrough: bool,
_service_fs_task: Option<fasync::Task<()>>,
}
impl BuiltinEnvironment {
async fn new(
model: Arc<Model>,
runtime_config: Arc<RuntimeConfig>,
system_resource_handle: Option<Resource>,
builtin_runners: Vec<BuiltinRunner>,
boot_resolver: Option<FuchsiaBootResolverBuiltinCapability>,
realm_builder_resolver: Option<Arc<RealmBuilderResolver>>,
utc_clock: Option<Arc<Clock>>,
inspector: Inspector,
crash_records: CrashRecords,
capability_passthrough: bool,
) -> Result<BuiltinEnvironment, Error> {
let debug = runtime_config.debug;
let num_threads = runtime_config.num_threads.clone();
let event_logger = if runtime_config.log_all_events {
let event_logger = Arc::new(EventLogger::new());
model.root().hooks.install(event_logger.hooks()).await;
Some(event_logger)
} else {
None
};
let mut root_input_builder =
RootComponentInputBuilder::new(model.top_instance().clone(), &runtime_config);
for namespace_capability in model.top_instance().namespace_capabilities() {
match namespace_capability {
cm_rust::CapabilityDecl::Protocol(p) => {
root_input_builder.add_namespace_protocol(&p);
}
_ => {
// Bedrock doesn't support these capability types yet, they'll fall back to
// legacy routing
}
}
}
// Set up ProcessLauncher if available.
if runtime_config.use_builtin_process_launcher {
root_input_builder.add_builtin_protocol_if_enabled::<fprocess::LauncherMarker>(
|stream| {
async move {
ProcessLauncher::serve(stream).await.map_err(|e| format_err!("{:?}", e))
}
.boxed()
},
);
}
// Set up RootJob service.
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::RootJobMarker>(|stream| {
RootJob::serve(stream, zx::Rights::SAME_RIGHTS).boxed()
});
// Set up RootJobForInspect service.
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::RootJobForInspectMarker>(
|stream| {
let stream = stream.cast_stream::<fkernel::RootJobRequestStream>();
let rights = zx::Rights::INSPECT
| zx::Rights::ENUMERATE
| zx::Rights::DUPLICATE
| zx::Rights::TRANSFER
| zx::Rights::GET_PROPERTY;
RootJob::serve(stream, rights).boxed()
},
);
let mmio_resource_handle =
take_startup_handle(HandleType::MmioResource.into()).map(zx::Resource::from);
let irq_resource_handle =
take_startup_handle(HandleType::IrqResource.into()).map(zx::Resource::from);
let root_resource_handle =
take_startup_handle(HandleType::Resource.into()).map(zx::Resource::from);
let zbi_vmo_handle = take_startup_handle(HandleType::BootdataVmo.into()).map(zx::Vmo::from);
let mut zbi_parser = match zbi_vmo_handle {
Some(zbi_vmo) => Some(
ZbiParser::new(zbi_vmo)
.set_store_item(ZbiType::Cmdline)
.set_store_item(ZbiType::ImageArgs)
.set_store_item(ZbiType::Crashlog)
.set_store_item(ZbiType::KernelDriver)
.set_store_item(ZbiType::PlatformId)
.set_store_item(ZbiType::StorageBootfsFactory)
.set_store_item(ZbiType::StorageRamdisk)
.set_store_item(ZbiType::SerialNumber)
.set_store_item(ZbiType::BootloaderFile)
.set_store_item(ZbiType::DeviceTree)
.set_store_item(ZbiType::DriverMetadata)
.set_store_item(ZbiType::CpuTopology)
.parse()?,
),
None => None,
};
// Set up fuchsia.boot.SvcStashProvider service.
let svc_stash_provider = take_startup_handle(HandleInfo::new(HandleType::User0, 0))
.map(zx::Channel::from)
.map(SvcStashCapability::new);
if let Some(svc_stash_provider) = svc_stash_provider {
root_input_builder.add_builtin_protocol_if_enabled::<fboot::SvcStashProviderMarker>(
move |stream| svc_stash_provider.clone().serve(stream).boxed(),
);
}
// Set up BootArguments service.
let boot_args = BootArguments::new(&mut zbi_parser).await?;
root_input_builder.add_builtin_protocol_if_enabled::<fboot::ArgumentsMarker>(
move |stream| boot_args.clone().serve(stream).boxed(),
);
if let Some(mut zbi_parser) = zbi_parser {
let factory_items = FactoryItems::new(&mut zbi_parser)?;
root_input_builder.add_builtin_protocol_if_enabled::<fboot::FactoryItemsMarker>(
move |stream| factory_items.clone().serve(stream).boxed(),
);
let items = Items::new(zbi_parser)?;
root_input_builder.add_builtin_protocol_if_enabled::<fboot::ItemsMarker>(
move |stream| items.clone().serve(stream).boxed(),
);
}
// Set up CrashRecords service.
let crash_records_svc = CrashIntrospectSvc::new(crash_records);
root_input_builder.add_builtin_protocol_if_enabled::<fsys::CrashIntrospectMarker>(
move |stream| crash_records_svc.clone().serve(stream).boxed(),
);
// Set up KernelStats service.
let info_resource_handle = system_resource_handle
.as_ref()
.map(|handle| {
match handle.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_INFO_BASE,
1,
b"info",
) {
Ok(resource) => Some(resource),
Err(_) => None,
}
})
.flatten();
if let Some(kernel_stats) = info_resource_handle.map(KernelStats::new) {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::StatsMarker>(
move |stream| kernel_stats.clone().serve(stream).boxed(),
);
}
// Set up the ReadOnlyLog service.
let debuglog_resource = system_resource_handle
.as_ref()
.map(|handle| {
match handle.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_DEBUGLOG_BASE,
1,
b"debuglog",
) {
Ok(resource) => Some(resource),
Err(_) => None,
}
})
.flatten();
if let Some(debuglog_resource) = debuglog_resource {
let read_only_log = ReadOnlyLog::new(debuglog_resource);
root_input_builder.add_builtin_protocol_if_enabled::<fboot::ReadOnlyLogMarker>(
move |stream| read_only_log.clone().serve(stream).boxed(),
);
}
// Set up WriteOnlyLog service.
let write_only_log = root_resource_handle.as_ref().map(|handle| {
WriteOnlyLog::new(zx::DebugLog::create(handle, zx::DebugLogOpts::empty()).unwrap())
});
if let Some(write_only_log) = write_only_log {
root_input_builder.add_builtin_protocol_if_enabled::<fboot::WriteOnlyLogMarker>(
move |stream| write_only_log.clone().serve(stream).boxed(),
);
}
// Register the UTC time maintainer.
if let Some(clock) = utc_clock {
let utc_time_maintainer = Arc::new(UtcTimeMaintainer::new(clock));
root_input_builder.add_builtin_protocol_if_enabled::<ftime::MaintenanceMarker>(
move |stream| utc_time_maintainer.clone().serve(stream).boxed(),
);
}
// Set up the MmioResource service.
let mmio_resource = mmio_resource_handle.map(MmioResource::new);
if let Some(mmio_resource) = mmio_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::MmioResourceMarker>(
move |stream| mmio_resource.clone().serve(stream).boxed(),
);
}
#[cfg(target_arch = "x86_64")]
if let Some(handle) = take_startup_handle(HandleType::IoportResource.into()) {
let ioport_resource = IoportResource::new(handle.into());
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::IoportResourceMarker>(
move |stream| ioport_resource.clone().serve(stream).boxed(),
);
}
// Set up the IrqResource service.
let irq_resource = irq_resource_handle.map(IrqResource::new);
if let Some(irq_resource) = irq_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::IrqResourceMarker>(
move |stream| irq_resource.clone().serve(stream).boxed(),
);
}
// Set up RootResource service.
let root_resource = root_resource_handle.map(RootResource::new);
if let Some(root_resource) = root_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fboot::RootResourceMarker>(
move |stream| root_resource.clone().serve(stream).boxed(),
);
}
// Set up the SMC resource.
#[cfg(target_arch = "aarch64")]
if let Some(handle) = take_startup_handle(HandleType::SmcResource.into()) {
let smc_resource = SmcResource::new(handle.into());
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::SmcResourceMarker>(
move |stream| smc_resource.clone().serve(stream).boxed(),
);
}
// Set up the CpuResource service.
let cpu_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_CPU_BASE,
1,
b"cpu",
)
.ok()
})
.map(CpuResource::new)
.and_then(Result::ok);
if let Some(cpu_resource) = cpu_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::CpuResourceMarker>(
move |stream| cpu_resource.clone().serve(stream).boxed(),
);
}
// Set up the EnergyInfoResource service.
let energy_info_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_ENERGY_INFO_BASE,
1,
b"energy_info",
)
.ok()
})
.map(EnergyInfoResource::new)
.and_then(Result::ok);
if let Some(energy_info_resource) = energy_info_resource {
root_input_builder
.add_builtin_protocol_if_enabled::<fkernel::EnergyInfoResourceMarker>(
move |stream| energy_info_resource.clone().serve(stream).boxed(),
);
}
// Set up the DebugResource service.
let debug_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_DEBUG_BASE,
1,
b"debug",
)
.ok()
})
.map(DebugResource::new)
.and_then(Result::ok);
if let Some(debug_resource) = debug_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::DebugResourceMarker>(
move |stream| debug_resource.clone().serve(stream).boxed(),
);
}
// Set up the DebuglogResource service.
let debuglog_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_DEBUGLOG_BASE,
1,
b"debuglog",
)
.ok()
})
.map(DebuglogResource::new)
.and_then(Result::ok);
if let Some(debuglog_resource) = debuglog_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::DebuglogResourceMarker>(
move |stream| debuglog_resource.clone().serve(stream).boxed(),
);
}
// Set up the FramebufferResource service.
let framebuffer_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_FRAMEBUFFER_BASE,
1,
b"framebuffer",
)
.ok()
})
.map(FramebufferResource::new)
.and_then(Result::ok);
if let Some(framebuffer_resource) = framebuffer_resource {
root_input_builder
.add_builtin_protocol_if_enabled::<fkernel::FramebufferResourceMarker>(
move |stream| framebuffer_resource.clone().serve(stream).boxed(),
);
}
// Set up the HypervisorResource service.
let hypervisor_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_HYPERVISOR_BASE,
1,
b"hypervisor",
)
.ok()
})
.map(HypervisorResource::new)
.and_then(Result::ok);
if let Some(hypervisor_resource) = hypervisor_resource {
root_input_builder
.add_builtin_protocol_if_enabled::<fkernel::HypervisorResourceMarker>(
move |stream| hypervisor_resource.clone().serve(stream).boxed(),
);
}
// Set up the InfoResource service.
let info_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_INFO_BASE,
1,
b"info",
)
.ok()
})
.map(InfoResource::new)
.and_then(Result::ok);
if let Some(info_resource) = info_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::InfoResourceMarker>(
move |stream| info_resource.clone().serve(stream).boxed(),
);
}
// Set up the IommuResource service.
let iommu_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_IOMMU_BASE,
1,
b"iommu",
)
.ok()
})
.map(IommuResource::new)
.and_then(Result::ok);
if let Some(iommu_resource) = iommu_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::IommuResourceMarker>(
move |stream| iommu_resource.clone().serve(stream).boxed(),
);
}
// Set up the MexecResource service.
let mexec_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_MEXEC_BASE,
1,
b"mexec",
)
.ok()
})
.map(MexecResource::new)
.and_then(Result::ok);
if let Some(mexec_resource) = mexec_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::MexecResourceMarker>(
move |stream| mexec_resource.clone().serve(stream).boxed(),
);
}
// Set up the MsiResource service.
let msi_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_MSI_BASE,
1,
b"msi",
)
.ok()
})
.map(MsiResource::new)
.and_then(Result::ok);
if let Some(msi_resource) = msi_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::MsiResourceMarker>(
move |stream| msi_resource.clone().serve(stream).boxed(),
);
}
// Set up the PowerResource service.
let power_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_POWER_BASE,
1,
b"power",
)
.ok()
})
.map(PowerResource::new)
.and_then(Result::ok);
if let Some(power_resource) = power_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::PowerResourceMarker>(
move |stream| power_resource.clone().serve(stream).boxed(),
);
}
// Set up the ProfileResource service.
let profile_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_PROFILE_BASE,
1,
b"profile",
)
.ok()
})
.map(ProfileResource::new)
.and_then(Result::ok);
if let Some(profile_resource) = profile_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::ProfileResourceMarker>(
move |stream| profile_resource.clone().serve(stream).boxed(),
);
}
// Set up the VmexResource service.
let vmex_resource = system_resource_handle
.as_ref()
.and_then(|handle| {
handle
.create_child(
zx::ResourceKind::SYSTEM,
None,
zx::sys::ZX_RSRC_SYSTEM_VMEX_BASE,
1,
b"vmex",
)
.ok()
})
.map(VmexResource::new)
.and_then(Result::ok);
if let Some(vmex_resource) = vmex_resource {
root_input_builder.add_builtin_protocol_if_enabled::<fkernel::VmexResourceMarker>(
move |stream| vmex_resource.clone().serve(stream).boxed(),
);
}
// Set up System Controller service.
let weak_model = Arc::downgrade(&model);
root_input_builder.add_builtin_protocol_if_enabled::<fsys::SystemControllerMarker>(
move |stream| {
SystemController::new(weak_model.clone(), SHUTDOWN_TIMEOUT).serve(stream).boxed()
},
);
// Set up the Inspect sink provider.
let inspect_sink_provider = Arc::new(InspectSinkProvider::new(inspector));
// Set up the event registry.
let event_registry = {
let mut event_registry = EventRegistry::new(Arc::downgrade(&model));
event_registry.register_synthesis_provider(
EventType::CapabilityRequested,
inspect_sink_provider.clone(),
);
Arc::new(event_registry)
};
model.root().hooks.install(event_registry.hooks()).await;
let event_stream_provider =
Arc::new(EventStreamProvider::new(Arc::downgrade(&event_registry)));
model.root().hooks.install(event_stream_provider.hooks()).await;
let event_source_factory = EventSourceFactory::new(
Arc::downgrade(model.top_instance()),
Arc::downgrade(&event_registry),
Arc::downgrade(&event_stream_provider),
);
let factory_capability_host = Arc::new(FactoryCapabilityHost::new());
let mut builtin_capabilities: Vec<Box<dyn BuiltinCapability>> =
vec![Box::new(EventSourceFactoryCapability::new(event_source_factory.clone()))];
let mut framework_capabilities: Vec<Box<dyn FrameworkCapability>> = vec![
Box::new(RealmFrameworkCapability::new(Arc::downgrade(&model), runtime_config.clone())),
Box::new(IntrospectorFrameworkCapability {
instance_registry: model.context().instance_registry().clone(),
}),
Box::new(BinderFrameworkCapability::new()),
Box::new(FactoryFrameworkCapability::new(factory_capability_host.clone())),
Box::new(NamespaceFrameworkCapability::new()),
Box::new(PkgDirectoryFrameworkCapability::new()),
Box::new(EventSourceFactoryCapability::new(event_source_factory.clone())),
];
let derived_capabilities: Vec<Box<dyn DerivedCapability>> =
vec![Box::new(StorageAdminDerivedCapability::new(Arc::downgrade(&model)))];
// Set up the builtin runners.
for runner in builtin_runners {
builtin_capabilities.push(Box::new(runner));
}
// Set up the boot resolver so it is routable from "above root".
if let Some(boot_resolver) = boot_resolver {
let b = boot_resolver.host().clone();
root_input_builder.add_builtin_protocol_if_enabled::<fresolution::ResolverMarker>(
move |stream| {
let b = b.clone();
async move { b.serve(stream).await.map_err(|e| format_err!("{:?}", e)) }.boxed()
},
);
builtin_capabilities.push(Box::new(boot_resolver));
}
// Set up the root realm stop notifier.
let stop_notifier = Arc::new(RootStopNotifier::new());
model.root().hooks.install(stop_notifier.hooks()).await;
let realm_query = if runtime_config.enable_introspection {
let host = RealmQuery::new(Arc::downgrade(&model));
framework_capabilities.push(Box::new(RealmQueryFrameworkCapability::new(host.clone())));
Some(host)
} else {
None
};
let lifecycle_controller = if runtime_config.enable_introspection {
let host = LifecycleController::new(Arc::downgrade(&model));
framework_capabilities
.push(Box::new(LifecycleControllerFrameworkCapability::new(host.clone())));
Some(host)
} else {
None
};
if runtime_config.enable_introspection {
framework_capabilities
.push(Box::new(RouteValidatorFrameworkCapability::new(Arc::downgrade(&model))));
}
model
.context()
.init_internal_capabilities(
builtin_capabilities,
framework_capabilities,
derived_capabilities,
)
.await;
// Set up the Component Tree Diagnostics runtime statistics.
let inspector = inspect_sink_provider.inspector();
let component_tree_stats =
ComponentTreeStats::new(inspector.root().create_child("stats")).await;
component_tree_stats.track_component_manager_stats().await;
component_tree_stats.start_measuring().await;
model.root().hooks.install(component_tree_stats.hooks()).await;
let component_lifecycle_time_stats =
Arc::new(ComponentLifecycleTimeStats::new(inspector.root().create_child("lifecycle")));
model.root().hooks.install(component_lifecycle_time_stats.hooks()).await;
let component_escrow_duration_status = Arc::new(diagnostics::escrow::DurationStats::new(
inspector.root().create_child("escrow"),
));
model.root().hooks.install(component_escrow_duration_status.hooks()).await;
// Serve stats about inspect in a lazy node.
inspector.record_lazy_stats();
let root_component_input = root_input_builder.build();
Ok(BuiltinEnvironment {
model,
realm_query,
lifecycle_controller,
event_registry,
event_source_factory,
factory_capability_host,
stop_notifier,
inspect_sink_provider,
event_stream_provider,
event_logger,
component_tree_stats,
_component_lifecycle_time_stats: component_lifecycle_time_stats,
_component_escrow_duration_status: component_escrow_duration_status,
debug,
num_threads,
realm_builder_resolver,
root_component_input,
capability_passthrough,
_service_fs_task: None,
})
}
/// Returns a ServiceFs that contains protocols served by component manager.
async fn create_service_fs<'a>(&self) -> Result<ServiceFs<ServiceObj<'a, ()>>, Error> {
// Create the ServiceFs
let mut service_fs = ServiceFs::new();
let scope = self.model.top_instance().task_group().clone();
// Install the root fuchsia.sys2.LifecycleController
if let Some(lifecycle_controller) = &self.lifecycle_controller {
let lifecycle_controller = lifecycle_controller.clone();
let scope = scope.clone();
service_fs.dir("svc").add_fidl_service(move |stream| {
let lifecycle_controller = lifecycle_controller.clone();
// Spawn a short-lived task that adds the lifecycle controller serve to
// component manager's task scope.
scope.spawn(async move {
lifecycle_controller.serve(Moniker::root(), stream).await;
});
});
}
// Install the root fuchsia.sys2.RealmQuery
if let Some(realm_query) = &self.realm_query {
let realm_query = realm_query.clone();
let scope = scope.clone();
service_fs.dir("svc").add_fidl_service(move |stream| {
let realm_query = realm_query.clone();
// Spawn a short-lived task that adds the realm query serve to
// component manager's task scope.
scope.spawn(async move {
realm_query.serve(Moniker::root(), stream).await;
});
});
}
// Install the `fuchsia.component.sandbox.Factory` protocol.
let factory_capability_host = self.factory_capability_host.clone();
{
let scope = scope.clone();
service_fs.dir("svc").add_fidl_service(move |stream| {
let factory_capability_host = factory_capability_host.clone();
scope.spawn(async move {
if let Err(err) = factory_capability_host.serve(stream).await {
warn!(?err, "Failed to serve fuchsia.component.sandbox.Factory");
}
});
});
}
// If capability passthrough is enabled, add a remote directory to proxy
// capabilities exposed by the root component.
if self.capability_passthrough {
let (proxy, server_end) = fidl::endpoints::create_proxy::<fio::DirectoryMarker>()?;
service_fs.add_remote("root-exposed", proxy);
let root = self.model.top_instance().root().await;
let root = WeakComponentInstance::new(&root);
scope.clone().spawn(async move {
let flags = routing::rights::Rights::from(fio::RW_STAR_DIR).into_legacy();
let mut object_request = flags.to_object_request(server_end);
object_request.wait_till_ready().await;
if let Ok(root) = root.upgrade() {
root.lock_resolved_state()
.await
.expect("failed to resolve root component state");
root.open_exposed(OpenRequest::new(
root.execution_scope.clone(),
flags,
Path::dot(),
&mut object_request,
))
.await
.expect("unable to open root exposed dir");
}
});
}
// If component manager is in debug mode, create an event source scoped at the
// root and offer it via ServiceFs to the outside world.
if self.debug {
let event_source = self.event_source_factory.create_for_above_root();
service_fs.dir("svc").add_fidl_service(move |stream| {
let mut event_source = event_source.clone();
// Spawn a short-lived task that adds the EventSource serve to
// component manager's task scope.
fasync::Task::spawn(async move {
serve_event_stream(
event_source
.subscribe(vec![
EventSubscription {
event_name: UseEventStreamDecl {
source_name: EventType::Started.into(),
source: UseSource::Parent,
scope: None,
target_path: "/svc/fuchsia.component.EventStream"
.parse()
.unwrap(),
filter: None,
availability: Availability::Required,
},
},
EventSubscription {
event_name: UseEventStreamDecl {
source_name: EventType::Stopped.into(),
source: UseSource::Parent,
scope: None,
target_path: "/svc/fuchsia.component.EventStream"
.parse()
.unwrap(),
filter: None,
availability: Availability::Required,
},
},
EventSubscription {
event_name: UseEventStreamDecl {
source_name: EventType::Destroyed.into(),
source: UseSource::Parent,
scope: None,
target_path: "/svc/fuchsia.component.EventStream"
.parse()
.unwrap(),
filter: None,
availability: Availability::Required,
},
},
EventSubscription {
event_name: UseEventStreamDecl {
source_name: EventType::Discovered.into(),
source: UseSource::Parent,
scope: None,
target_path: "/svc/fuchsia.component.EventStream"
.parse()
.unwrap(),
filter: None,
availability: Availability::Required,
},
},
EventSubscription {
event_name: UseEventStreamDecl {
source_name: EventType::Resolved.into(),
source: UseSource::Parent,
scope: None,
target_path: "/svc/fuchsia.component.EventStream"
.parse()
.unwrap(),
filter: None,
availability: Availability::Required,
},
},
EventSubscription {
event_name: UseEventStreamDecl {
source_name: EventType::Unresolved.into(),
source: UseSource::Parent,
scope: None,
target_path: "/svc/fuchsia.component.EventStream"
.parse()
.unwrap(),
filter: None,
availability: Availability::Required,
},
},
])
.await
.unwrap(),
stream,
)
.await;
})
.detach();
});
}
Ok(service_fs)
}
/// Bind ServiceFs to a provided channel
async fn bind_service_fs(
&mut self,
channel: fidl::endpoints::ServerEnd<fio::DirectoryMarker>,
) -> Result<(), Error> {
let mut service_fs = self.create_service_fs().await?;
// Bind to the channel
service_fs.serve_connection(channel)?;
// Start up ServiceFs
self._service_fs_task = Some(fasync::Task::spawn(async move {
service_fs.collect::<()>().await;
}));
Ok(())
}
/// Bind ServiceFs to the outgoing directory of this component, if it exists.
pub async fn bind_service_fs_to_out(&mut self) -> Result<(), Error> {
let server_end = match fuchsia_runtime::take_startup_handle(
fuchsia_runtime::HandleType::DirectoryRequest.into(),
) {
Some(handle) => fidl::endpoints::ServerEnd::new(zx::Channel::from(handle)),
None => {
// The component manager running on startup does not get a directory handle. If it was
// to run as a component itself, it'd get one. When we don't have a handle to the out
// directory, create one.
let (_client, server) = fidl::endpoints::create_endpoints();
server
}
};
self.bind_service_fs(server_end).await
}
#[cfg(test)]
/// Adds a protocol to the root dict, replacing prior entries. This must be called before
/// the model is started.
pub async fn add_protocol_to_root_dict<P>(
&mut self,
name: Name,
task_to_launch: impl Fn(P::RequestStream) -> BoxFuture<'static, Result<(), anyhow::Error>>
+ Sync
+ Send
+ 'static,
) where
P: ProtocolMarker,
{
let capability_source = CapabilitySource::Builtin {
capability: InternalCapability::Protocol(name.clone()),
top_instance: Arc::downgrade(self.model.top_instance()),
};
let launch = LaunchTaskOnReceive::new(
self.model.top_instance().task_group().as_weak(),
name.clone(),
Some((self.model.root().context.policy().clone(), capability_source)),
Arc::new(move |server_end, _| {
task_to_launch(crate::sandbox_util::take_handle_as_stream::<P>(server_end)).boxed()
}),
);
self.root_component_input.insert_capability(&name, launch.into_router().into()).unwrap();
}
#[cfg(test)]
/// Causes the root component to be discovered, which provides the root component with the
/// dict from the builtin environment. This is called in some tests because the tests create
/// a new model but do not call `Model::start`.
pub async fn discover_root_component(&self) {
self.model.discover_root_component(self.root_component_input.clone()).await;
}
pub async fn wait_for_root_stop(&self) {
self.stop_notifier.wait_for_root_stop().await;
}
pub async fn run_root(&mut self) -> Result<(), Error> {
self.bind_service_fs_to_out().await?;
self.model.start(self.root_component_input.clone()).await;
component::health().set_ok();
self.wait_for_root_stop().await;
// Stop serving the out directory, so that more connections to debug capabilities
// cannot be made.
drop(self._service_fs_task.take());
Ok(())
}
#[cfg(test)]
pub fn inspector(&self) -> &Inspector {
self.inspect_sink_provider.inspector()
}
}
fn register_builtin_resolver(resolvers: &mut ResolverRegistry) {
resolvers.register(BUILTIN_SCHEME.to_string(), Box::new(BuiltinResolver {}));
}
// Creates a FuchsiaBootResolver if the /boot directory is installed in component_manager's
// namespace, and registers it with the ResolverRegistry. The resolver is returned to so that
// it can be installed as a Builtin capability.
async fn register_boot_resolver(
resolvers: &mut ResolverRegistry,
runtime_config: &RuntimeConfig,
) -> Result<Option<FuchsiaBootResolverBuiltinCapability>, Error> {
let path = match &runtime_config.builtin_boot_resolver {
BuiltinBootResolver::Boot => "/boot",
BuiltinBootResolver::None => return Ok(None),
};
let boot_resolver = FuchsiaBootResolverBuiltinCapability::new(path)
.await
.context("Failed to create boot resolver")?;
match boot_resolver {
None => {
info!(%path, "fuchsia-boot resolver unavailable, not in namespace");
Ok(None)
}
Some(boot_resolver) => {
resolvers.register(BOOT_SCHEME.to_string(), box_arc_resolver(boot_resolver.host()));
Ok(Some(boot_resolver))
}
}
}
fn register_realm_builder_resolver(
resolvers: &mut ResolverRegistry,
) -> Result<Arc<RealmBuilderResolver>, Error> {
let realm_builder_resolver =
RealmBuilderResolver::new().context("Failed to create realm builder resolver")?;
let resolver = Arc::new(realm_builder_resolver);
resolvers.register(REALM_BUILDER_SCHEME.to_string(), box_arc_resolver(&resolver));
Ok(resolver)
}