1use 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
47pub type EventStreamFilter = Option<BTreeMap<String, DictionaryValue>>;
49
50#[derive(Clone)]
52pub struct EventStreamSourceRouter {
53 pub router: Arc<Router<Dictionary>>,
56 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#[derive(Debug, Clone)]
70pub struct ProgramInput {
71 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 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 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 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 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#[derive(Debug)]
152pub struct ComponentSandbox {
153 pub component_input: ComponentInput,
155
156 pub component_output: ComponentOutput,
158
159 pub program_input: ProgramInput,
161
162 pub program_output_dict: Arc<Dictionary>,
164
165 framework_router: Mutex<Arc<Router<Dictionary>>>,
175
176 pub capability_sourced_capabilities_dict: Arc<Dictionary>,
179
180 pub declared_dictionaries: Arc<Dictionary>,
182
183 pub child_inputs: StructuredDictMap<ComponentInput>,
186
187 pub collection_inputs: StructuredDictMap<ComponentInput>,
191
192 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
325pub 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 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 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 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
584fn 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
620fn 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
638fn 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
655fn 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(®istration.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 let _ = target_dictionary.insert(target_name, router);
712 }
713 environment
714}
715
716pub 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 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 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 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}