Skip to main content

routing/bedrock/
sandbox_construction.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::DictExt;
6use crate::bedrock::aggregate_router::{AggregateRouterFn, AggregateSource};
7use crate::bedrock::structured_dict::{
8    ComponentEnvironment, ComponentInput, ComponentOutput, StructuredDictMap,
9};
10use crate::bedrock::use_dictionary_router::UseDictionaryRouter;
11use crate::bedrock::with_service_renames_and_filter::WithServiceRenamesAndFilter;
12use crate::component_instance::ComponentInstanceInterface;
13use crate::error::{ErrorReporter, RouteVerb, RoutingError};
14use crate::error_logging_router::ErrorLoggingRouter;
15use crate::intermediate_router::{IntermediateRouter, RouteRequest, WeakDictionaryOrRouter};
16use crate::to_request::ToRequest;
17use crate::to_source::ToSource;
18use async_trait::async_trait;
19use capability_source::{
20    AggregateCapability, AggregateInstance, AggregateMember, AnonymizedAggregateSource,
21    CapabilitySource, ComponentCapability, ComponentSource, FilteredAggregateProviderSource,
22    InternalCapability, InternalEventStreamCapability, VoidSource,
23};
24use cm_rust::offer::{OfferDeclCommon, OfferTarget};
25use cm_rust::{
26    CapabilityTypeName, DictionaryValue, ExposeDeclCommon, ExposeTarget, FidlIntoNative,
27    GenericRef, SourceName, SourcePath, UseDeclCommon,
28};
29use cm_types::{BorrowedName, IterablePath, Name, RelativePath};
30use fidl_fuchsia_component_decl as fdecl;
31use fidl_fuchsia_component_runtime as fruntime;
32use fuchsia_sync::Mutex;
33use log::warn;
34use moniker::{ChildName, Moniker};
35use router_error::RouterError;
36use runtime_capabilities::{
37    Capability, CapabilityBound, Connector, Data, Dictionary, DirConnector, Routable, Router,
38    RouterErrorInfo, WeakInstanceToken,
39};
40use std::collections::{BTreeMap, HashMap};
41use std::fmt::Debug;
42use std::sync::{Arc, LazyLock};
43
44#[cfg(target_os = "fuchsia")]
45use fuchsia_trace as trace;
46
47/// This type comes from `UseEventStreamDecl`.
48pub type EventStreamFilter = Option<BTreeMap<String, DictionaryValue>>;
49
50/// Contains all of the information needed to find and use a source of an event stream.
51#[derive(Clone)]
52pub struct EventStreamSourceRouter {
53    /// The source router that should return a dictionary detailing specifics on the event stream
54    /// such as its type and scope.
55    pub router: Arc<Router<Dictionary>>,
56    /// The filter that should be applied on the event stream initialized from the information
57    /// returned by the router.
58    pub filter: EventStreamFilter,
59}
60pub type EventStreamUseRouterFn<C> =
61    dyn Fn(&Arc<C>, Vec<EventStreamSourceRouter>) -> Arc<Router<Connector>>;
62
63static NAMESPACE: LazyLock<Name> = LazyLock::new(|| "namespace".parse().unwrap());
64static NUMBERED_HANDLES: LazyLock<Name> = LazyLock::new(|| "numbered_handles".parse().unwrap());
65static RUNNER: LazyLock<Name> = LazyLock::new(|| "runner".parse().unwrap());
66static CONFIG: LazyLock<Name> = LazyLock::new(|| "config".parse().unwrap());
67
68/// All capabilities that are available to a component's program.
69#[derive(Debug, Clone)]
70pub struct ProgramInput {
71    // This will always have the following fields:
72    // - namespace: Arc<Dictionary>
73    // - runner: Option<Arc<Router<Connector>>>
74    // - config: Arc<Dictionary>
75    // - numbered_handles: Arc<Dictionary>
76    inner: Arc<Dictionary>,
77}
78
79impl Default for ProgramInput {
80    fn default() -> Self {
81        Self::new(Dictionary::new(), None, Dictionary::new())
82    }
83}
84
85impl From<ProgramInput> for Arc<Dictionary> {
86    fn from(program_input: ProgramInput) -> Self {
87        program_input.inner
88    }
89}
90
91impl ProgramInput {
92    pub fn new(
93        namespace: Arc<Dictionary>,
94        runner: Option<Arc<Router<Connector>>>,
95        config: Arc<Dictionary>,
96    ) -> Self {
97        let inner = Dictionary::new();
98        inner.insert(NAMESPACE.clone(), Capability::Dictionary(namespace));
99        if let Some(runner) = runner {
100            inner.insert(RUNNER.clone(), Capability::ConnectorRouter(runner));
101        }
102        inner.insert(NUMBERED_HANDLES.clone(), Capability::Dictionary(Dictionary::new()));
103        inner.insert(CONFIG.clone(), Capability::Dictionary(config));
104        ProgramInput { inner }
105    }
106
107    /// All of the capabilities that appear in a program's namespace.
108    pub fn namespace(&self) -> Arc<Dictionary> {
109        let cap = self.inner.get(&*NAMESPACE).unwrap();
110        let Capability::Dictionary(dict) = cap else {
111            unreachable!("namespace entry must be a dictionary: {cap:?}");
112        };
113        dict
114    }
115
116    /// All of the capabilities that appear in a program's set of numbered handles.
117    pub fn numbered_handles(&self) -> Arc<Dictionary> {
118        let cap = self.inner.get(&*NUMBERED_HANDLES).unwrap();
119        let Capability::Dictionary(dict) = cap else {
120            unreachable!("numbered_handles entry must be a dictionary: {cap:?}");
121        };
122        dict
123    }
124
125    /// A router for the runner that a component has used (if any).
126    pub fn runner(&self) -> Option<Arc<Router<Connector>>> {
127        let cap = self.inner.get(&*RUNNER);
128        match cap {
129            None => None,
130            Some(Capability::ConnectorRouter(r)) => Some(r),
131            cap => unreachable!("runner entry must be a router: {cap:?}"),
132        }
133    }
134
135    fn set_runner(&self, capability: Capability) {
136        let _ = self.inner.insert(RUNNER.clone(), capability);
137    }
138
139    /// All of the config capabilities that a program will use.
140    pub fn config(&self) -> Arc<Dictionary> {
141        let cap = self.inner.get(&*CONFIG).unwrap();
142        let Capability::Dictionary(dict) = cap else {
143            unreachable!("config entry must be a dictionary: {cap:?}");
144        };
145        dict
146    }
147}
148
149/// A component's sandbox holds all the routing dictionaries that a component has once its been
150/// resolved.
151#[derive(Debug)]
152pub struct ComponentSandbox {
153    /// The dictionary containing all capabilities that a component's parent provided to it.
154    pub component_input: ComponentInput,
155
156    /// The dictionary containing all capabilities that a component makes available to its parent.
157    pub component_output: ComponentOutput,
158
159    /// The dictionary containing all capabilities that are available to a component's program.
160    pub program_input: ProgramInput,
161
162    /// The dictionary containing all capabilities that a component's program can provide.
163    pub program_output_dict: Arc<Dictionary>,
164
165    /// Router that returns the dictionary of framework capabilities scoped to a component. This a
166    /// Router rather than the Dictionary itself to save memory.
167    ///
168    /// REQUIRES: This Router must never poll. This constraint exists `build_component_sandbox` is
169    /// not async.
170    // NOTE: This is wrapped in Mutex for interior mutability so that it is modifiable like the
171    // other parts of the sandbox. If this were a Dictionary this wouldn't be necessary because
172    // Dictionary already supports interior mutability, but since this is a singleton we don't need
173    // a Dictionary here. The Arc around the Mutex is needed for Sync.
174    framework_router: Mutex<Arc<Router<Dictionary>>>,
175
176    /// The dictionary containing all capabilities that a component declares based on another
177    /// capability. Currently this is only the storage admin protocol.
178    pub capability_sourced_capabilities_dict: Arc<Dictionary>,
179
180    /// The dictionary containing all dictionaries declared by this component.
181    pub declared_dictionaries: Arc<Dictionary>,
182
183    /// This set holds a component input dictionary for each child of a component. Each dictionary
184    /// contains all capabilities the component has made available to a specific collection.
185    pub child_inputs: StructuredDictMap<ComponentInput>,
186
187    /// This set holds a component input dictionary for each collection declared by a component.
188    /// Each dictionary contains all capabilities the component has made available to a specific
189    /// collection.
190    pub collection_inputs: StructuredDictMap<ComponentInput>,
191
192    /// This holds the one dictionary router for each child of this component, for the child's
193    /// outgoing dictionary. Invoking the router causes the child to be resolved if this hasn't yet
194    /// occurred.
195    pub child_outputs: Mutex<HashMap<ChildName, Arc<Router<Dictionary>>>>,
196}
197
198impl Default for ComponentSandbox {
199    fn default() -> Self {
200        static NULL_ROUTER: LazyLock<Arc<Router<Dictionary>>> =
201            LazyLock::new(|| Router::new(NullRouter {}));
202        struct NullRouter;
203        #[async_trait]
204        impl Routable<Dictionary> for NullRouter {
205            async fn route(
206                &self,
207                _request: fruntime::RouteRequest,
208                _target: Arc<WeakInstanceToken>,
209            ) -> Result<Option<Arc<Dictionary>>, RouterError> {
210                panic!("null router invoked");
211            }
212            async fn route_debug(
213                &self,
214                _request: fruntime::RouteRequest,
215                _target: Arc<WeakInstanceToken>,
216            ) -> Result<CapabilitySource, RouterError> {
217                panic!("null router invoked");
218            }
219        }
220        let framework_router = Mutex::new(NULL_ROUTER.clone());
221        Self {
222            framework_router,
223            component_input: Default::default(),
224            component_output: Default::default(),
225            program_input: Default::default(),
226            program_output_dict: Default::default(),
227            capability_sourced_capabilities_dict: Default::default(),
228            declared_dictionaries: Default::default(),
229            child_inputs: Default::default(),
230            collection_inputs: Default::default(),
231            child_outputs: Mutex::new(Default::default()),
232        }
233    }
234}
235
236impl From<ComponentSandbox> for Arc<Dictionary> {
237    fn from(sandbox: ComponentSandbox) -> Arc<Dictionary> {
238        let sandbox_dictionary = Dictionary::new();
239        sandbox_dictionary.insert(
240            Name::new("framework").unwrap(),
241            Capability::DictionaryRouter(sandbox.framework_router.lock().clone()),
242        );
243        sandbox_dictionary.insert(
244            Name::new("component_input").unwrap(),
245            Capability::Dictionary(sandbox.component_input.into()),
246        );
247        sandbox_dictionary.insert(
248            Name::new("component_output").unwrap(),
249            Capability::Dictionary(sandbox.component_output.into()),
250        );
251        sandbox_dictionary.insert(
252            Name::new("program_input").unwrap(),
253            Capability::Dictionary(sandbox.program_input.into()),
254        );
255        sandbox_dictionary.insert(
256            Name::new("program_output").unwrap(),
257            Capability::Dictionary(sandbox.program_output_dict),
258        );
259        sandbox_dictionary.insert(
260            Name::new("capability_sourced").unwrap(),
261            Capability::Dictionary(sandbox.capability_sourced_capabilities_dict),
262        );
263        sandbox_dictionary.insert(
264            Name::new("declared_dictionaries").unwrap(),
265            Capability::Dictionary(sandbox.declared_dictionaries),
266        );
267        sandbox_dictionary.insert(
268            Name::new("child_inputs").unwrap(),
269            Capability::Dictionary(sandbox.child_inputs.into()),
270        );
271        sandbox_dictionary.insert(
272            Name::new("collection_inputs").unwrap(),
273            Capability::Dictionary(sandbox.collection_inputs.into()),
274        );
275        sandbox_dictionary
276    }
277}
278
279impl Clone for ComponentSandbox {
280    fn clone(&self) -> Self {
281        let Self {
282            component_input,
283            component_output,
284            program_input,
285            program_output_dict,
286            framework_router,
287            capability_sourced_capabilities_dict,
288            declared_dictionaries,
289            child_inputs,
290            collection_inputs,
291            child_outputs,
292        } = self;
293        Self {
294            component_input: component_input.clone(),
295            component_output: component_output.clone(),
296            program_input: program_input.clone(),
297            program_output_dict: program_output_dict.clone(),
298            framework_router: Mutex::new(framework_router.lock().clone()),
299            capability_sourced_capabilities_dict: capability_sourced_capabilities_dict.clone(),
300            declared_dictionaries: declared_dictionaries.clone(),
301            child_inputs: child_inputs.clone(),
302            collection_inputs: collection_inputs.clone(),
303            child_outputs: Mutex::new(child_outputs.lock().clone()),
304        }
305    }
306}
307
308impl ComponentSandbox {
309    pub fn framework_router(&self) -> Arc<Router<Dictionary>> {
310        self.framework_router.lock().clone()
311    }
312}
313
314struct ComponentWithToken<'a, C: ComponentInstanceInterface + 'static> {
315    component: &'a Arc<C>,
316    weak_token: Arc<WeakInstanceToken>,
317}
318
319impl<'a, C: ComponentInstanceInterface + 'static> ComponentWithToken<'a, C> {
320    fn new(component: &'a Arc<C>) -> Self {
321        Self { component, weak_token: component.as_weak().into() }
322    }
323}
324
325/// Once a component has been resolved and its manifest becomes known, this function produces the
326/// various dicts the component needs based on the contents of its manifest.
327pub fn build_component_sandbox<C: ComponentInstanceInterface + 'static>(
328    component: &Arc<C>,
329    child_outputs: HashMap<ChildName, Arc<Router<Dictionary>>>,
330    decl: &cm_rust::ComponentDecl,
331    component_input: ComponentInput,
332    program_output_dict: Arc<Dictionary>,
333    framework_router: Arc<Router<Dictionary>>,
334    capability_sourced_capabilities_dict: Arc<Dictionary>,
335    declared_dictionaries: Arc<Dictionary>,
336    error_reporter: impl ErrorReporter,
337    aggregate_router_fn: &AggregateRouterFn<C>,
338    event_stream_use_router_fn: &EventStreamUseRouterFn<C>,
339) -> ComponentSandbox {
340    #[cfg(target_os = "fuchsia")]
341    trace::duration!(
342        "component_manager",
343        "build_component_sandbox",
344        "moniker" => component.moniker().as_str()
345    );
346    let sandbox = ComponentSandbox {
347        framework_router: Mutex::new(framework_router),
348        component_input,
349        program_output_dict,
350        capability_sourced_capabilities_dict,
351        declared_dictionaries,
352        child_outputs: Mutex::new(child_outputs),
353        ..Default::default()
354    };
355    let component_with_token = ComponentWithToken::new(component);
356    let mut environments = HashMap::new();
357
358    for environment_decl in &decl.environments {
359        let _ = environments.insert(
360            environment_decl.name.clone(),
361            build_environment(&component_with_token, &sandbox, environment_decl),
362        );
363    }
364
365    for child in &decl.children {
366        let environment;
367        if let Some(environment_name) = child.environment.as_ref() {
368            environment = environments
369                .get(environment_name)
370                .expect(
371                    "child references nonexistent environment, \
372                    this should be prevented in manifest validation",
373                )
374                .clone();
375        } else {
376            environment = sandbox.component_input.environment();
377        }
378        let input = ComponentInput::new(environment);
379        let name = Name::new(child.name.as_str()).expect("child is static so name is not long");
380        let _ = sandbox.child_inputs.insert(name, input);
381    }
382
383    for collection in &decl.collections {
384        let environment;
385        if let Some(environment_name) = collection.environment.as_ref() {
386            environment = environments
387                .get(environment_name)
388                .expect(
389                    "collection references nonexistent environment, \
390                    this should be prevented in manifest validation",
391                )
392                .clone();
393        } else {
394            environment = sandbox.component_input.environment();
395        }
396        let input = ComponentInput::new(environment);
397        let _ = sandbox.collection_inputs.insert(collection.name.clone(), input);
398    }
399
400    let mut dictionary_use_bundles = Vec::with_capacity(decl.uses.len());
401    for use_bundle in group_use_aggregates(&decl.uses).into_iter() {
402        let first_use = *use_bundle.first().unwrap();
403        match first_use {
404            cm_rust::UseDecl::Service(_)
405                if use_bundle.len() > 1
406                    || matches!(first_use.source(), cm_rust::UseSource::Collection(_)) =>
407            {
408                let aggregate_router = new_aggregate_service_router(
409                    &component_with_token,
410                    &sandbox,
411                    &use_bundle,
412                    aggregate_router_fn,
413                );
414                let prev = sandbox
415                    .program_input
416                    .namespace()
417                    .insert_capability(first_use.path().unwrap(), aggregate_router);
418                assert!(
419                    prev.is_none(),
420                    "failed to insert {}: preexisting value",
421                    first_use.path().unwrap()
422                );
423            }
424            cm_rust::UseDecl::EventStream(_) => extend_dict_with_event_stream_uses(
425                &component_with_token,
426                &sandbox,
427                use_bundle,
428                error_reporter.clone(),
429                event_stream_use_router_fn,
430            ),
431            cm_rust::UseDecl::Dictionary(_) => {
432                dictionary_use_bundles.push(use_bundle);
433            }
434            use_ => install_use_in_sandbox(
435                &component_with_token,
436                &sandbox,
437                use_,
438                error_reporter.clone(),
439            ),
440        }
441    }
442
443    // The runner may be specified by either use declaration or in the program section of the
444    // manifest. If there's no use declaration for a runner and there is one set in the program
445    // section, then let's synthesize a use decl for it and add it to the sandbox.
446    if !decl.uses.iter().any(|u| matches!(u, cm_rust::UseDecl::Runner(_))) {
447        if let Some(runner_name) = decl.program.as_ref().and_then(|p| p.runner.as_ref()) {
448            install_use_in_sandbox(
449                &component_with_token,
450                &sandbox,
451                &cm_rust::UseDecl::Runner(cm_rust::UseRunnerDecl {
452                    source: cm_rust::UseSource::Environment,
453                    source_name: runner_name.clone(),
454                    source_dictionary: Default::default(),
455                }),
456                error_reporter.clone(),
457            );
458        }
459    }
460
461    // Dictionary uses are special: if any capabilities are used at a path that's a prefix of a
462    // dictionary use, then those capabilities are transparently added to the dictionary we
463    // assemble in the program input dictionary. In order to do this correctly, we want the program
464    // input dictionary to be complete (aside from used dictionaries) so that the dictionaries
465    // we're merging with the used dictionaries aren't missing entries. For this reason, we wait
466    // until after all other uses are processed before processing used dictionaries.
467    for dictionary_use_bundle in dictionary_use_bundles {
468        extend_dict_with_dictionary_use(
469            &component_with_token,
470            &sandbox,
471            dictionary_use_bundle,
472            error_reporter.clone(),
473        )
474    }
475
476    for offer_bundle in group_offer_aggregates(&decl.offers) {
477        let first_offer = offer_bundle.first().unwrap();
478        match first_offer {
479            cm_rust::offer::OfferDecl::Service(_)
480                if offer_bundle.len() > 1
481                    || matches!(
482                        first_offer.source(),
483                        cm_rust::offer::OfferSource::Collection(_)
484                    ) =>
485            {
486                let aggregate_router = new_aggregate_service_router(
487                    &component_with_token,
488                    &sandbox,
489                    &offer_bundle,
490                    aggregate_router_fn,
491                );
492                install_router_to_target(
493                    &sandbox,
494                    aggregate_router.into(),
495                    first_offer.target(),
496                    vec![first_offer.target_name().clone()].into(),
497                );
498            }
499            _ => install_offer_in_sandbox(&component_with_token, &sandbox, first_offer),
500        }
501    }
502
503    for expose_bundle in group_expose_aggregates(&decl.exposes) {
504        let first_expose = expose_bundle.first().unwrap();
505        match first_expose {
506            cm_rust::ExposeDecl::Service(_)
507                if expose_bundle.len() > 1
508                    || matches!(first_expose.source(), cm_rust::ExposeSource::Collection(_)) =>
509            {
510                let router = new_aggregate_service_router(
511                    &component_with_token,
512                    &sandbox,
513                    &expose_bundle,
514                    aggregate_router_fn,
515                );
516                let target_name = first_expose.target_name().clone();
517                let prev =
518                    sandbox.component_output.capabilities().insert(target_name, router.into());
519                assert!(
520                    prev.is_none(),
521                    "failed to insert {}: preexisting value",
522                    first_expose.target_name()
523                );
524            }
525            _ => install_expose_in_sandbox(&component_with_token, &sandbox, first_expose),
526        }
527    }
528
529    sandbox
530}
531
532fn new_aggregate_service_router<'a, C: ComponentInstanceInterface + 'static, D>(
533    component: &ComponentWithToken<'_, C>,
534    sandbox: &ComponentSandbox,
535    decl_bundle: &Vec<&'a D>,
536    aggregate_router_fn: &AggregateRouterFn<C>,
537) -> Capability
538where
539    AggregateMember: TryFrom<&'a D>,
540    D: SourcePath + ToSource + ToRequest + ServiceDeclExt,
541    &'a D: Into<CapabilityTypeName> + Into<RouteVerb>,
542{
543    let mut aggregate_sources = vec![];
544    let source =
545        new_aggregate_capability_source(component.component.moniker().clone(), decl_bundle);
546    for decl in decl_bundle.iter() {
547        if matches!(&source, &CapabilitySource::FilteredAggregateProvider(_))
548            && decl
549                .offer_service_decl()
550                .map(|decl| !has_filtered_offer(&vec![decl]))
551                .unwrap_or(false)
552        {
553            // We can ignore any offers for a filtered aggregate that have no rename or
554            // filtering rules, as they will not be contributing any instances to the
555            // aggregate.
556            continue;
557        } else if let GenericRef::Collection(collection_name) = decl.to_source() {
558            aggregate_sources.push(AggregateSource::Collection { collection_name });
559        } else {
560            let router_capability = new_intermediate_router(component, sandbox, *decl);
561            let router: Arc<Router<DirConnector>> = router_capability
562                .try_into()
563                .expect("invalid type returned by new_intermediate_router");
564            let source_instance = match decl.to_source() {
565                GenericRef::Self_ => AggregateInstance::Self_,
566                GenericRef::Parent => AggregateInstance::Parent,
567                GenericRef::Child(name) => {
568                    AggregateInstance::Child(ChildName::new(name.to_long(), None))
569                }
570                GenericRef::ChildInCollection(name, collection) => {
571                    AggregateInstance::Child(ChildName::new(name, Some(collection)))
572                }
573                other_source => {
574                    warn!("unsupported source found in offer aggregate: {:?}", other_source);
575                    continue;
576                }
577            };
578            aggregate_sources.push(AggregateSource::DirectoryRouter { source_instance, router })
579        }
580    }
581    (aggregate_router_fn)(component.component.clone(), aggregate_sources, source).into()
582}
583
584/// Returns `true` if any of the offers set a filter or rename mapping.
585fn has_filtered_offer(offer_service_decls: &Vec<&cm_rust::OfferServiceDecl>) -> bool {
586    offer_service_decls.iter().any(|o| {
587        o.source_instance_filter.as_ref().map(|v| !v.is_empty()).unwrap_or(false)
588            || o.renamed_instances.as_ref().map(|v| !v.is_empty()).unwrap_or(false)
589    })
590}
591
592fn new_aggregate_capability_source<'a, D: ServiceDeclExt + ToSource>(
593    moniker: Moniker,
594    decls: &Vec<&'a D>,
595) -> CapabilitySource
596where
597    AggregateMember: TryFrom<&'a D>,
598{
599    let offer_service_decls =
600        decls.iter().filter_map(|d| d.offer_service_decl()).collect::<Vec<_>>();
601    let capability =
602        AggregateCapability::Service(decls.first().unwrap().service_name().unwrap().clone());
603    if has_filtered_offer(&offer_service_decls) {
604        CapabilitySource::FilteredAggregateProvider(FilteredAggregateProviderSource {
605            capability,
606            moniker,
607            offer_service_decls: offer_service_decls.into_iter().cloned().collect(),
608        })
609    } else {
610        let members = decls.iter().filter_map(|o| AggregateMember::try_from(*o).ok()).collect();
611        CapabilitySource::AnonymizedAggregate(AnonymizedAggregateSource {
612            capability,
613            moniker,
614            members,
615            instances: vec![],
616        })
617    }
618}
619
620/// Groups together a set of offers into sub-sets of those that have the same target and target
621/// name. This is useful for identifying which offers are part of an aggregation of capabilities,
622/// and which are for standalone routes.
623fn group_use_aggregates<'a>(
624    uses: &'a [cm_rust::UseDecl],
625) -> impl Iterator<Item = Vec<&'a cm_rust::UseDecl>> + 'a {
626    let mut groupings = HashMap::with_capacity(uses.len());
627    let mut ungroupable_uses = Vec::new();
628    for use_ in uses.iter() {
629        if let Some(target_path) = use_.path() {
630            groupings.entry(target_path).or_insert_with(|| Vec::with_capacity(1)).push(use_);
631        } else {
632            ungroupable_uses.push(use_);
633        }
634    }
635    groupings.into_values().chain(ungroupable_uses.into_iter().map(|u| vec![u]))
636}
637
638/// Groups together a set of offers into sub-sets of those that have the same target and target
639/// name. This is useful for identifying which offers are part of an aggregation of capabilities,
640/// and which are for standalone routes.
641fn group_offer_aggregates<'a>(
642    offers: &'a [cm_rust::offer::OfferDecl],
643) -> impl Iterator<Item = Vec<&'a cm_rust::offer::OfferDecl>> + 'a {
644    let mut groupings = HashMap::with_capacity(offers.len());
645
646    for offer in offers {
647        groupings
648            .entry((offer.target(), offer.target_name()))
649            .or_insert_with(|| Vec::with_capacity(1))
650            .push(offer);
651    }
652    groupings.into_values()
653}
654
655/// Identical to `group_offer_aggregates`, but for exposes.
656fn group_expose_aggregates<'a>(
657    exposes: &'a [cm_rust::ExposeDecl],
658) -> impl Iterator<Item = Vec<&'a cm_rust::ExposeDecl>> + 'a {
659    let mut groupings = HashMap::with_capacity(exposes.len());
660    for expose in exposes {
661        groupings
662            .entry((expose.target(), expose.target_name()))
663            .or_insert_with(|| Vec::with_capacity(1))
664            .push(expose);
665    }
666    groupings.into_values()
667}
668
669fn build_environment<C: ComponentInstanceInterface + 'static>(
670    component: &ComponentWithToken<'_, C>,
671    sandbox: &ComponentSandbox,
672    environment_decl: &cm_rust::EnvironmentDecl,
673) -> ComponentEnvironment {
674    let mut environment = ComponentEnvironment::new();
675    if environment_decl.extends == fdecl::EnvironmentExtends::Realm {
676        environment = sandbox.component_input.environment().shallow_copy();
677    }
678    environment.set_name(&environment_decl.name);
679    if let Some(stop_timeout_ms) = environment_decl.stop_timeout_ms {
680        environment.set_stop_timeout(stop_timeout_ms as i64);
681    }
682    let debug_routers_and_targets =
683        environment_decl.debug_capabilities.iter().map(|registration| {
684            let cm_rust::DebugRegistration::Protocol(debug_protocol_registration) = registration;
685            (
686                new_intermediate_router_source_name(component, sandbox, registration),
687                debug_protocol_registration.target_name.clone(),
688                environment.debug(),
689            )
690        });
691    let runner_routers_and_targets = environment_decl.runners.iter().map(|registration| {
692        (
693            new_intermediate_router_source_name(component, sandbox, registration),
694            registration.target_name.clone(),
695            environment.runners(),
696        )
697    });
698    let resolver_routers_and_targets = environment_decl.resolvers.iter().map(|registration| {
699        (
700            new_intermediate_router_source_name(component, sandbox, registration),
701            Name::new(&registration.scheme).unwrap(),
702            environment.resolvers(),
703        )
704    });
705    for (router, target_name, target_dictionary) in debug_routers_and_targets
706        .chain(runner_routers_and_targets)
707        .chain(resolver_routers_and_targets)
708    {
709        // This might overwrite an existing value if we're shadowing something in the environment,
710        // so we don't assert that there was no previous value.
711        let _ = target_dictionary.insert(target_name, router);
712    }
713    environment
714}
715
716/// Extends the given `target_input` to contain the capabilities described in `dynamic_offers`.
717pub fn extend_dict_with_offers<C: ComponentInstanceInterface + 'static>(
718    component: &Arc<C>,
719    sandbox: &ComponentSandbox,
720    static_offers: &[cm_rust::offer::OfferDecl],
721    dynamic_offers: &[cm_rust::offer::OfferDecl],
722    target_input: &ComponentInput,
723    aggregate_router_fn: &AggregateRouterFn<C>,
724) {
725    let component_with_token = ComponentWithToken::new(component);
726    for offer_bundle in group_offer_aggregates(dynamic_offers).into_iter() {
727        let first_offer = offer_bundle.first().unwrap();
728        match first_offer {
729            cm_rust::offer::OfferDecl::Service(_) => {
730                let static_offer_bundles = group_offer_aggregates(static_offers);
731                let maybe_static_offer_bundle = static_offer_bundles.into_iter().find(|bundle| {
732                    bundle.first().unwrap().target_name() == first_offer.target_name()
733                });
734                let mut combined_offer_bundle = offer_bundle.clone();
735                if let Some(mut static_offer_bundle) = maybe_static_offer_bundle {
736                    // We are aggregating together dynamic and static offers, as there are static
737                    // offers with the same target name as our current dynamic offers. We already
738                    // populated a router for the static bundle in the target input, let's toss
739                    // that and generate a new one with the expanded set of offers.
740                    let _ = target_input.capabilities().remove(first_offer.target_name());
741                    combined_offer_bundle.append(&mut static_offer_bundle);
742                }
743                if combined_offer_bundle.len() == 1
744                    && !matches!(first_offer.source(), cm_rust::offer::OfferSource::Collection(_))
745                {
746                    let router =
747                        new_intermediate_router(&component_with_token, sandbox, *first_offer);
748                    let prev = target_input
749                        .capabilities()
750                        .insert(first_offer.target_name().clone(), router);
751                    assert!(prev.is_none(), "failed to insert capability into target dict");
752                } else {
753                    let aggregate_router = new_aggregate_service_router(
754                        &component_with_token,
755                        sandbox,
756                        &combined_offer_bundle,
757                        aggregate_router_fn,
758                    );
759                    let prev = target_input
760                        .capabilities()
761                        .insert(first_offer.target_name().clone(), aggregate_router.into());
762                    assert!(prev.is_none(), "failed to insert capability into target dict");
763                }
764            }
765            offer => {
766                let router = new_intermediate_router(&component_with_token, sandbox, *offer);
767                let prev =
768                    target_input.capabilities().insert(first_offer.target_name().clone(), router);
769                assert!(prev.is_none(), "failed to insert capability into target dict");
770            }
771        }
772    }
773}
774
775fn extend_dict_with_event_stream_uses<C: ComponentInstanceInterface + 'static>(
776    component: &ComponentWithToken<'_, C>,
777    sandbox: &ComponentSandbox,
778    uses: Vec<&cm_rust::UseDecl>,
779    error_reporter: impl ErrorReporter,
780    event_stream_use_router_fn: &EventStreamUseRouterFn<C>,
781) {
782    let routers = uses
783        .iter()
784        .map(|use_| {
785            let router = new_intermediate_router(component, sandbox, *use_);
786            let router = ErrorLoggingRouter::new(
787                router,
788                *use_,
789                error_reporter.clone(),
790                component.weak_token.clone(),
791            );
792            let filter = match use_ {
793                cm_rust::UseDecl::EventStream(u) => u.filter.clone(),
794                _ => panic!("found non-event-stream use"),
795            };
796            EventStreamSourceRouter {
797                router: router.try_into().expect("unexpected router type"),
798                filter,
799            }
800        })
801        .collect::<Vec<_>>();
802
803    let router = event_stream_use_router_fn(component.component, routers);
804    let target_path = match uses.first().unwrap() {
805        cm_rust::UseDecl::EventStream(u) => u.target_path.clone(),
806        _ => panic!("found non-event-stream use"),
807    };
808    let prev = sandbox
809        .program_input
810        .namespace()
811        .insert_capability(&target_path, Capability::ConnectorRouter(router));
812    assert!(prev.is_none(), "failed to insert {target_path}: preexisting value");
813}
814
815fn new_intermediate_router_inner(
816    moniker: Moniker,
817    _type_name: CapabilityTypeName,
818    sandbox: &ComponentSandbox,
819    request: RouteRequest,
820    default_token: Arc<WeakInstanceToken>,
821    verb: RouteVerb,
822    ref_: GenericRef,
823    source_path: RelativePath,
824) -> Capability {
825    let source: WeakDictionaryOrRouter = match &ref_ {
826        GenericRef::Parent => Arc::downgrade(&sandbox.component_input.capabilities()).into(),
827        GenericRef::Self_ => Arc::downgrade(&sandbox.program_output_dict).into(),
828        GenericRef::Child(name) => {
829            let guard = sandbox.child_outputs.lock();
830            let router = guard.get(name.as_str()).expect("reference to non-existent child");
831            Arc::downgrade(&router).into()
832        }
833        GenericRef::ChildInCollection(name, collection) => {
834            let child_name = moniker::ChildName::new(name.clone(), Some(collection.clone()));
835            let guard = sandbox.child_outputs.lock();
836            let router = guard.get(&child_name).expect("reference to non-existent child");
837            Arc::downgrade(&router).into()
838        }
839        GenericRef::Collection(_) => unimplemented!(),
840        GenericRef::Framework => Arc::downgrade(&*sandbox.framework_router.lock()).into(),
841        GenericRef::Capability(_) => {
842            Arc::downgrade(&sandbox.capability_sourced_capabilities_dict).into()
843        }
844        GenericRef::Debug => Arc::downgrade(&sandbox.component_input.environment().debug()).into(),
845        GenericRef::Void => {
846            let source_name = source_path.basename().expect("invalid source capability path");
847            let type_name = request.build_type_name;
848            return UnavailableRouter::new_from_type_name(source_name.into(), type_name, moniker);
849        }
850        GenericRef::Environment => {
851            let type_name = request.build_type_name;
852            match type_name {
853                CapabilityTypeName::Runner => {
854                    Arc::downgrade(&sandbox.component_input.environment().runners()).into()
855                }
856                CapabilityTypeName::Resolver => {
857                    Arc::downgrade(&sandbox.component_input.environment().resolvers()).into()
858                }
859                _ => unreachable!("other capability types may not have an environment source"),
860            }
861        }
862    };
863    IntermediateRouter::new(source, source_path, request, default_token, moniker, verb, ref_)
864}
865
866fn install_use_in_sandbox<C: ComponentInstanceInterface + 'static>(
867    component: &ComponentWithToken<'_, C>,
868    sandbox: &ComponentSandbox,
869    use_: &cm_rust::UseDecl,
870    error_reporter: impl ErrorReporter,
871) {
872    let router = new_intermediate_router(component, sandbox, use_);
873    let router =
874        ErrorLoggingRouter::new(router, use_, error_reporter, component.weak_token.clone());
875    match use_ {
876        cm_rust::UseDecl::Protocol(cm_rust::UseProtocolDecl {
877            numbered_handle: Some(numbered_handle),
878            ..
879        }) => {
880            let numbered_handle = Name::from(*numbered_handle);
881            let prev = sandbox
882                .program_input
883                .numbered_handles()
884                .insert_capability(&numbered_handle, router);
885            assert!(prev.is_none(), "failed to insert {numbered_handle}: preexisting value");
886        }
887        cm_rust::UseDecl::Runner(_) => {
888            assert!(
889                sandbox.program_input.runner().is_none(),
890                "component can't use multiple runners"
891            );
892            sandbox.program_input.set_runner(router.try_into().expect("invalid type for runner"));
893        }
894        cm_rust::UseDecl::Config(use_config) => {
895            let prev =
896                sandbox.program_input.config().insert_capability(&use_config.target_name, router);
897            assert!(
898                prev.is_none(),
899                "failed to insert {}: preexisting value",
900                use_config.target_name
901            );
902        }
903        _ => {
904            let prev =
905                sandbox.program_input.namespace().insert_capability(use_.path().unwrap(), router);
906            assert!(prev.is_none(), "failed to insert {}: preexisting value", use_.path().unwrap());
907        }
908    }
909}
910
911fn extend_dict_with_dictionary_use<C: ComponentInstanceInterface + 'static>(
912    component: &ComponentWithToken<'_, C>,
913    sandbox: &ComponentSandbox,
914    use_bundle: Vec<&cm_rust::UseDecl>,
915    error_reporter: impl ErrorReporter,
916) {
917    let path = use_bundle[0].path().unwrap();
918
919    let original_dictionary = match sandbox.program_input.namespace().remove_capability(path) {
920        Some(Capability::Dictionary(dictionary)) => dictionary,
921        _ => Dictionary::new(),
922    };
923
924    let mut dictionary_routers = vec![];
925    for use_ in use_bundle.iter() {
926        install_use_in_sandbox(component, sandbox, use_, error_reporter.clone());
927        let dictionary_router = match sandbox.program_input.namespace().remove_capability(path) {
928            Some(Capability::DictionaryRouter(router)) => router,
929            other_value => panic!("unexpected dictionary get result: {other_value:?}"),
930        };
931        dictionary_routers.push(dictionary_router);
932    }
933
934    let moniker = component.component.moniker().clone();
935    let router = UseDictionaryRouter::new(
936        path.clone(),
937        moniker.clone(),
938        original_dictionary,
939        dictionary_routers,
940        CapabilitySource::Component(ComponentSource {
941            capability: ComponentCapability::Use_((*use_bundle.first().unwrap()).clone()),
942            moniker,
943        }),
944    );
945    // This value will be `Some` if we're shadowing something else. This is fine in this case
946    // because we've already merged any preexisting value with what we're inserting.
947    let _ = sandbox
948        .program_input
949        .namespace()
950        .insert_capability(path, Capability::DictionaryRouter(router));
951}
952
953pub(crate) trait ServiceDeclExt {
954    fn offer_service_decl(&self) -> Option<&cm_rust::OfferServiceDecl>;
955    fn service_name(&self) -> Option<&Name>;
956}
957
958impl ServiceDeclExt for cm_rust::UseDecl {
959    fn offer_service_decl(&self) -> Option<&cm_rust::OfferServiceDecl> {
960        None
961    }
962    fn service_name(&self) -> Option<&Name> {
963        match self {
964            cm_rust::UseDecl::Service(s) => Some(&s.source_name),
965            _ => None,
966        }
967    }
968}
969
970impl ServiceDeclExt for cm_rust::ExposeDecl {
971    fn offer_service_decl(&self) -> Option<&cm_rust::OfferServiceDecl> {
972        None
973    }
974    fn service_name(&self) -> Option<&Name> {
975        match self {
976            cm_rust::ExposeDecl::Service(s) => Some(&s.target_name),
977            _ => None,
978        }
979    }
980}
981
982impl ServiceDeclExt for cm_rust::OfferDecl {
983    fn offer_service_decl(&self) -> Option<&cm_rust::OfferServiceDecl> {
984        match self {
985            cm_rust::OfferDecl::Service(s) => Some(&s),
986            _ => None,
987        }
988    }
989    fn service_name(&self) -> Option<&Name> {
990        match self {
991            cm_rust::OfferDecl::Service(s) => Some(&s.target_name),
992            _ => None,
993        }
994    }
995}
996
997fn install_offer_in_sandbox<C: ComponentInstanceInterface + 'static>(
998    component: &ComponentWithToken<'_, C>,
999    sandbox: &ComponentSandbox,
1000    offer: &cm_rust::offer::OfferDecl,
1001) {
1002    let intermediate_router = new_intermediate_router(component, sandbox, offer);
1003    install_router_to_target(
1004        sandbox,
1005        intermediate_router,
1006        offer.target(),
1007        vec![offer.target_name().clone()].into(),
1008    );
1009}
1010
1011fn install_router_to_target(
1012    sandbox: &ComponentSandbox,
1013    router: Capability,
1014    target: &OfferTarget,
1015    target_path: RelativePath,
1016) {
1017    let target_dictionary = match target {
1018        OfferTarget::Child(child) => {
1019            let child_name = BorrowedName::new(child.name.as_str())
1020                .expect("child is static so name is not long");
1021            sandbox.child_inputs.get(child_name).expect("invalid child ref").capabilities()
1022        }
1023        OfferTarget::Collection(collection_name) => sandbox
1024            .collection_inputs
1025            .get(collection_name)
1026            .expect("invalid collection ref")
1027            .capabilities(),
1028        OfferTarget::Capability(capability_name) => sandbox
1029            .declared_dictionaries
1030            .get(capability_name)
1031            .expect("capability target doesn't exist")
1032            .try_into()
1033            .expect("unexpected capability type"),
1034    };
1035    let prev = target_dictionary.insert_capability(&target_path, router);
1036    assert!(prev.is_none(), "failed to insert {target_path}: preexisting value");
1037}
1038
1039fn new_intermediate_router_source_name<'a, C: ComponentInstanceInterface + 'static, D>(
1040    component: &ComponentWithToken<'_, C>,
1041    sandbox: &ComponentSandbox,
1042    decl: &'a D,
1043) -> Capability
1044where
1045    D: SourceName + ToSource + ToRequest,
1046    &'a D: Into<CapabilityTypeName> + Into<RouteVerb>,
1047{
1048    let source = decl.to_source();
1049    let source_path = RelativePath::from(vec![decl.source_name().clone()]);
1050    let moniker = component.component.moniker();
1051    new_intermediate_router_inner(
1052        moniker.clone(),
1053        decl.into(),
1054        sandbox,
1055        decl.to_request(moniker),
1056        component.weak_token.clone(),
1057        decl.into(),
1058        source,
1059        source_path,
1060    )
1061}
1062
1063fn new_intermediate_router<'a, C: ComponentInstanceInterface + 'static, D>(
1064    component: &ComponentWithToken<'_, C>,
1065    sandbox: &ComponentSandbox,
1066    decl: &'a D,
1067) -> Capability
1068where
1069    D: SourcePath + ToSource + ToRequest + ServiceDeclExt,
1070    &'a D: Into<CapabilityTypeName> + Into<RouteVerb>,
1071{
1072    let source = decl.to_source();
1073    let source_path = match &source {
1074        GenericRef::Capability(name)
1075            if decl.source_path().basename.as_str() == "fuchsia.component.StorageAdmin"
1076                || decl.source_path().basename.as_str() == "fuchsia.sys2.StorageAdmin" =>
1077        {
1078            let mut path: RelativePath =
1079                decl.source_path().iter_segments().collect::<Vec<_>>().into();
1080            path = path.parent().unwrap_or(path);
1081            let not_too_long = path.push(name.clone());
1082            assert!(not_too_long);
1083            path
1084        }
1085        _ => decl.source_path().iter_segments().collect::<Vec<_>>().into(),
1086    };
1087    let moniker = component.component.moniker();
1088    let router = new_intermediate_router_inner(
1089        moniker.clone(),
1090        decl.into(),
1091        sandbox,
1092        decl.to_request(moniker),
1093        component.weak_token.clone(),
1094        decl.into(),
1095        source,
1096        source_path,
1097    );
1098
1099    // Service capabilities are special, and we need to handle the filtering/renaming that they do
1100    // when offered.
1101    if let Some(offer_service_decl) = decl.offer_service_decl() {
1102        let Capability::DirConnectorRouter(r) = router else {
1103            panic!("wrong type returned for service capability");
1104        };
1105        r.with_service_renames_and_filter(cm_rust::OfferDecl::Service(Box::new(
1106            offer_service_decl.clone(),
1107        )))
1108    } else {
1109        router
1110    }
1111}
1112
1113fn install_expose_in_sandbox<C: ComponentInstanceInterface + 'static>(
1114    component: &ComponentWithToken<'_, C>,
1115    sandbox: &ComponentSandbox,
1116    expose: &cm_rust::ExposeDecl,
1117) {
1118    let router = new_intermediate_router(component, sandbox, expose);
1119    let target_dictionary = match expose.target() {
1120        ExposeTarget::Parent => sandbox.component_output.capabilities(),
1121        ExposeTarget::Framework => sandbox.component_output.framework(),
1122    };
1123    let target_path: RelativePath = vec![expose.target_name().clone()].into();
1124    let prev = target_dictionary.insert_capability(&target_path, router);
1125    assert!(prev.is_none(), "failed to insert {target_path}: preexisting value");
1126}
1127
1128struct UnavailableRouter {
1129    capability: InternalCapability,
1130    moniker: Moniker,
1131}
1132
1133impl UnavailableRouter {
1134    fn new<T: CapabilityBound>(capability: InternalCapability, moniker: Moniker) -> Arc<Router<T>> {
1135        Router::<T>::new(Self { capability, moniker })
1136    }
1137
1138    fn new_from_type_name(
1139        name: Name,
1140        type_name: CapabilityTypeName,
1141        moniker: Moniker,
1142    ) -> Capability {
1143        match type_name {
1144            CapabilityTypeName::Service => {
1145                Self::new::<DirConnector>(InternalCapability::Service(name), moniker).into()
1146            }
1147            CapabilityTypeName::Protocol => {
1148                Self::new::<Connector>(InternalCapability::Protocol(name), moniker).into()
1149            }
1150            CapabilityTypeName::Directory => {
1151                Self::new::<DirConnector>(InternalCapability::Directory(name), moniker).into()
1152            }
1153            CapabilityTypeName::Storage => {
1154                Self::new::<DirConnector>(InternalCapability::Storage(name), moniker).into()
1155            }
1156            CapabilityTypeName::Runner => {
1157                Self::new::<Connector>(InternalCapability::Runner(name), moniker).into()
1158            }
1159            CapabilityTypeName::Resolver => {
1160                Self::new::<Connector>(InternalCapability::Resolver(name), moniker).into()
1161            }
1162            CapabilityTypeName::EventStream => Self::new::<Dictionary>(
1163                InternalCapability::EventStream(InternalEventStreamCapability {
1164                    name,
1165                    scope_moniker: None,
1166                    scope: None,
1167                }),
1168                moniker,
1169            )
1170            .into(),
1171            CapabilityTypeName::Dictionary => {
1172                Self::new::<Dictionary>(InternalCapability::Dictionary(name), moniker).into()
1173            }
1174            CapabilityTypeName::Config => {
1175                Self::new::<Data>(InternalCapability::Config(name), moniker).into()
1176            }
1177        }
1178    }
1179}
1180
1181#[async_trait]
1182impl<T: CapabilityBound> Routable<T> for UnavailableRouter {
1183    async fn route(
1184        &self,
1185        request: fruntime::RouteRequest,
1186        _target: Arc<WeakInstanceToken>,
1187    ) -> Result<Option<Arc<T>>, RouterError> {
1188        let availability = request
1189            .availability
1190            .ok_or_else(|| RoutingError::RouteRequestMissingField {
1191                moniker: self.moniker.clone().into(),
1192                missing_field: "availability".to_string(),
1193            })?
1194            .fidl_into_native();
1195        match availability {
1196            cm_rust::Availability::Required => {
1197                Err(RoutingError::SourceCapabilityIsVoid { moniker: self.moniker.clone().into() }
1198                    .into())
1199            }
1200            cm_rust::Availability::Optional
1201            | cm_rust::Availability::Transitional
1202            | cm_rust::Availability::SameAsTarget => Ok(None),
1203        }
1204    }
1205
1206    async fn route_debug(
1207        &self,
1208        request: fruntime::RouteRequest,
1209        _target: Arc<WeakInstanceToken>,
1210    ) -> Result<CapabilitySource, RouterError> {
1211        match request.availability {
1212            Some(fdecl::Availability::Required) => {
1213                Err(RoutingError::SourceCapabilityIsVoid { moniker: self.moniker.clone().into() }
1214                    .into())
1215            }
1216            Some(fdecl::Availability::Optional)
1217            | Some(fdecl::Availability::Transitional)
1218            | Some(fdecl::Availability::SameAsTarget)
1219            | None => Ok(CapabilitySource::Void(VoidSource {
1220                capability: self.capability.clone(),
1221                moniker: self.moniker.clone(),
1222            })),
1223        }
1224    }
1225
1226    fn error_info(&self) -> Option<RouterErrorInfo> {
1227        Some(RouterErrorInfo {
1228            capability_type: self.capability.type_name(),
1229            name: self.capability.source_name().clone(),
1230            availability: cm_rust::Availability::Optional,
1231        })
1232    }
1233}