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