blob: 5b3f5dcdf782b7da6fc154a9bb35e68a42e176a2 [file] [log] [blame]
// 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.
//! This module is not for production instances of component_manager. It exists to allow a test
//! driver to define a custom realm with realm builder and to then launch a nested component
//! manager which will run that custom realm, for the sole purposes of integration testing
//! component manager behavior.
use {
crate::{
builtin::runner::BuiltinRunnerFactory,
model::resolver::{self, Resolver},
},
::routing::policy::ScopedPolicyChecker,
::routing::resolving::{ComponentAddress, ResolvedComponent, ResolverError},
anyhow::Error,
async_trait::async_trait,
fidl_fuchsia_component_resolution as fresolution, fidl_fuchsia_io as fio,
fuchsia_component::client as fclient,
fuchsia_zircon as zx,
std::sync::Arc,
vfs::{directory::entry::OpenRequest, remote::remote_dir},
};
pub static SCHEME: &str = "realm-builder";
pub static RUNNER_NAME: &str = "realm_builder";
/// Resolves component URLs with the "realm-builder" scheme, which supports loading components from
/// the fuchsia.component.resolution.Resolver protocol in component_manager's namespace.
///
/// Also runs components with the "realm-builder" runner, which supports launching components
/// through the fuchsia.component.runner.ComponentRunner protocol in component manager's namespace.
///
/// Both of these protocols are typically implemented by the realm builder library, for use when
/// integration testing a nested component manager.
#[derive(Debug)]
pub struct RealmBuilderResolver {
resolver_proxy: fresolution::ResolverProxy,
}
impl RealmBuilderResolver {
/// Create a new RealmBuilderResolver. This opens connections to the needed protocols
/// in the namespace.
pub fn new() -> Result<RealmBuilderResolver, Error> {
Ok(RealmBuilderResolver {
resolver_proxy: fclient::connect_to_protocol_at_path::<fresolution::ResolverMarker>(
"/svc/fuchsia.component.resolver.RealmBuilder",
)?,
})
}
async fn resolve_async(
&self,
component_url: &str,
some_incoming_context: Option<&fresolution::Context>,
) -> Result<fresolution::Component, fresolution::ResolverError> {
let res = if let Some(context) = some_incoming_context {
self.resolver_proxy
.resolve_with_context(component_url, &context)
.await
.expect("resolve_with_context failed in realm builder resolver")
} else {
self.resolver_proxy
.resolve(component_url)
.await
.expect("resolve failed in realm builder resolver")
};
res
}
}
#[async_trait]
impl Resolver for RealmBuilderResolver {
async fn resolve(
&self,
component_address: &ComponentAddress,
) -> Result<ResolvedComponent, ResolverError> {
let (component_url, some_context) = component_address.to_url_and_context();
let fresolution::Component {
url,
decl,
package,
config_values,
resolution_context,
abi_revision,
..
} = self
.resolve_async(component_url, some_context.map(|context| context.into()).as_ref())
.await?;
let resolved_url = url.unwrap();
let context_to_resolve_children = resolution_context.map(Into::into);
let decl = resolver::read_and_validate_manifest(&decl.unwrap())?;
let config_values = if let Some(data) = config_values {
Some(resolver::read_and_validate_config_values(&data)?)
} else {
None
};
Ok(ResolvedComponent {
resolved_url,
context_to_resolve_children,
decl,
package: package.map(|p| p.try_into()).transpose()?,
config_values,
abi_revision: abi_revision.map(Into::into),
})
}
}
pub struct RealmBuilderRunnerFactory {}
impl RealmBuilderRunnerFactory {
pub fn new() -> Self {
RealmBuilderRunnerFactory {}
}
}
impl BuiltinRunnerFactory for RealmBuilderRunnerFactory {
fn get_scoped_runner(
self: Arc<Self>,
_checker: ScopedPolicyChecker,
mut open_request: OpenRequest<'_>,
) -> Result<(), zx::Status> {
open_request.prepend_path(&"fuchsia.component.runner.RealmBuilder".try_into().unwrap());
open_request.open_remote(remote_dir(
fuchsia_fs::directory::open_in_namespace("/svc", fio::OpenFlags::RIGHT_READABLE)
.unwrap(),
))
}
}