blob: 51d1a60264a6780acf4449ae188beae1549d565d [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.
use {
crate::{
component_instance::{ComponentInstanceForAnalyzer, TopInstanceForAnalyzer},
component_model::{BuildAnalyzerModelError, Child},
node_path::NodePath,
},
cm_rust::{EnvironmentDecl, RegistrationSource, ResolverRegistration},
fidl_fuchsia_component_internal as component_internal,
routing::{
component_instance::{
ComponentInstanceInterface, ExtendedInstanceInterface, WeakExtendedInstanceInterface,
},
config::RuntimeConfig,
environment::{DebugRegistry, EnvironmentExtends, EnvironmentInterface, RunnerRegistry},
error::ComponentInstanceError,
},
std::{collections::HashMap, sync::Arc},
};
// Constants used to set up the built-in environment.
pub static BOOT_RESOLVER_NAME: &str = "boot_resolver";
pub static BOOT_SCHEME: &str = "fuchsia-boot";
pub static PKG_RESOLVER_NAME: &str = "package_resolver";
pub static PKG_SCHEME: &str = "fuchsia-pkg";
static REALM_BUILDER_RESOLVER_NAME: &str = "realm_builder_resolver";
static REALM_BUILDER_SCHEME: &str = "realm-builder";
/// A collection of resolver registrations, keyed by target URL scheme.
#[derive(Clone, Debug, Default)]
pub struct ResolverRegistry {
resolvers: HashMap<String, ResolverRegistration>,
}
impl ResolverRegistry {
pub fn new() -> ResolverRegistry {
Self { resolvers: HashMap::default() }
}
pub fn from_decl(decl: &[ResolverRegistration]) -> Result<Self, BuildAnalyzerModelError> {
let mut registry = Self::new();
for resolver in decl.iter() {
if let Some(reg) = registry.register(resolver) {
return Err(BuildAnalyzerModelError::DuplicateResolverScheme(reg.scheme));
}
}
Ok(registry)
}
pub fn register(&mut self, resolver: &ResolverRegistration) -> Option<ResolverRegistration> {
self.resolvers.insert(resolver.scheme.clone(), resolver.clone())
}
pub fn get_resolver(&self, scheme: &str) -> Option<&ResolverRegistration> {
self.resolvers.get(scheme)
}
}
/// A representation of a v2 component instance's environment and its relationship to the
/// parent realm's environment.
#[derive(Debug)]
pub struct EnvironmentForAnalyzer {
/// The name of this environment as defined by its creator. Should be `None` for the root
/// environment.
name: Option<String>,
/// The relationship of this environment to that of the component instance's parent.
extends: EnvironmentExtends,
/// The parent of this instance.
parent: WeakExtendedInstanceInterface<ComponentInstanceForAnalyzer>,
/// The runners available in this environment.
runner_registry: RunnerRegistry,
/// The resolvers available in this environment.
resolver_registry: ResolverRegistry,
/// Protocols available in this environment as debug capabilities.
debug_registry: DebugRegistry,
}
impl EnvironmentForAnalyzer {
// TODO(https://fxbug.dev/61861): This parallel implementation of component manager's builtin environment
// setup will do for now, but is fragile and should be replaced soon. In particular, it doesn't provide a
// way to register builtin runners or resolvers that appear in the `builtin_capabilities` field of the
// RuntimeConfig but are not one of these hard-coded built-ins.
pub fn new_root(
runner_registry: RunnerRegistry,
runtime_config: &Arc<RuntimeConfig>,
top_instance: &Arc<TopInstanceForAnalyzer>,
) -> Arc<Self> {
let mut resolver_registry = ResolverRegistry::default();
// Register the boot resolver, if any
match runtime_config.builtin_boot_resolver {
component_internal::BuiltinBootResolver::Boot => {
assert!(
resolver_registry
.register(&ResolverRegistration {
resolver: BOOT_RESOLVER_NAME.into(),
source: RegistrationSource::Self_,
scheme: BOOT_SCHEME.to_string(),
})
.is_none(),
"found duplicate resolver for boot scheme"
);
}
component_internal::BuiltinBootResolver::None => {}
};
// Register the RealmBuilder resolver and runner, if any
match runtime_config.realm_builder_resolver_and_runner {
component_internal::RealmBuilderResolverAndRunner::Namespace => {
assert!(
resolver_registry
.register(&ResolverRegistration {
resolver: REALM_BUILDER_RESOLVER_NAME.into(),
source: RegistrationSource::Self_,
scheme: REALM_BUILDER_SCHEME.to_string(),
})
.is_none(),
"found duplicate resolver for realm builder scheme"
);
}
component_internal::RealmBuilderResolverAndRunner::None => {}
};
Arc::new(Self {
name: None,
extends: EnvironmentExtends::None,
parent: WeakExtendedInstanceInterface::from(&ExtendedInstanceInterface::AboveRoot(
Arc::clone(top_instance),
)),
runner_registry,
resolver_registry,
debug_registry: DebugRegistry::default(),
})
}
pub fn new_for_child(
parent: &Arc<ComponentInstanceForAnalyzer>,
child: &Child,
) -> Result<Arc<Self>, BuildAnalyzerModelError> {
match child.environment.as_ref() {
Some(child_env_name) => {
let env_decl = parent
.decl_for_testing()
.environments
.iter()
.find(|&env| &env.name == child_env_name)
.ok_or(BuildAnalyzerModelError::EnvironmentNotFound(
child_env_name.clone(),
child.child_moniker.name.clone(),
NodePath::from(parent.abs_moniker().clone()).to_string(),
))?;
Self::new_from_decl(parent, env_decl)
}
None => Ok(Self::new_inheriting(parent)),
}
}
fn new_inheriting(parent: &Arc<ComponentInstanceForAnalyzer>) -> Arc<Self> {
Arc::new(Self {
name: None,
extends: EnvironmentExtends::Realm,
parent: WeakExtendedInstanceInterface::from(&ExtendedInstanceInterface::Component(
Arc::clone(parent),
)),
runner_registry: RunnerRegistry::default(),
resolver_registry: ResolverRegistry::default(),
debug_registry: DebugRegistry::default(),
})
}
fn new_from_decl(
parent: &Arc<ComponentInstanceForAnalyzer>,
env_decl: &EnvironmentDecl,
) -> Result<Arc<Self>, BuildAnalyzerModelError> {
Ok(Arc::new(Self {
name: Some(env_decl.name.clone()),
extends: env_decl.extends.into(),
parent: WeakExtendedInstanceInterface::from(&ExtendedInstanceInterface::Component(
Arc::clone(parent),
)),
runner_registry: RunnerRegistry::from_decl(&env_decl.runners),
resolver_registry: ResolverRegistry::from_decl(&env_decl.resolvers)?,
debug_registry: env_decl.debug_capabilities.clone().into(),
}))
}
/// Returns the resolver registered for `scheme` and the component that created the environment the
/// resolver was registered to. Returns `None` if there was no match.
pub fn get_registered_resolver(
&self,
scheme: &str,
) -> Result<
Option<(ExtendedInstanceInterface<ComponentInstanceForAnalyzer>, ResolverRegistration)>,
ComponentInstanceError,
> {
let parent = self.parent().upgrade()?;
match self.resolver_registry().get_resolver(scheme) {
Some(reg) => Ok(Some((parent, reg.clone()))),
None => match self.extends() {
EnvironmentExtends::Realm => match parent {
ExtendedInstanceInterface::Component(parent) => {
parent.environment.get_registered_resolver(scheme)
}
ExtendedInstanceInterface::AboveRoot(_) => {
unreachable!("root env can't extend")
}
},
EnvironmentExtends::None => {
return Ok(None);
}
},
}
}
fn resolver_registry(&self) -> &ResolverRegistry {
&self.resolver_registry
}
}
impl EnvironmentInterface<ComponentInstanceForAnalyzer> for EnvironmentForAnalyzer {
fn name(&self) -> Option<&str> {
self.name.as_deref()
}
fn parent(&self) -> &WeakExtendedInstanceInterface<ComponentInstanceForAnalyzer> {
&self.parent
}
fn extends(&self) -> &EnvironmentExtends {
&self.extends
}
fn runner_registry(&self) -> &RunnerRegistry {
&self.runner_registry
}
fn debug_registry(&self) -> &DebugRegistry {
&self.debug_registry
}
}