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;
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
45pub type EventStreamFilter = Option<BTreeMap<String, DictionaryValue>>;
47
48#[derive(Clone)]
50pub struct EventStreamSourceRouter {
51 pub router: Arc<Router<Dictionary>>,
54 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#[derive(Debug, Clone)]
68pub struct ProgramInput {
69 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 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 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 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 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#[derive(Debug)]
150pub struct ComponentSandbox {
151 pub component_input: ComponentInput,
153
154 pub component_output: ComponentOutput,
156
157 pub program_input: ProgramInput,
159
160 pub program_output_dict: Arc<Dictionary>,
162
163 framework_router: Mutex<Arc<Router<Dictionary>>>,
173
174 pub capability_sourced_capabilities_dict: Arc<Dictionary>,
177
178 pub declared_dictionaries: Arc<Dictionary>,
180
181 pub child_inputs: StructuredDictMap<ComponentInput>,
184
185 pub collection_inputs: StructuredDictMap<ComponentInput>,
189
190 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
312pub 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 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 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 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
557fn 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
593fn 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
611fn 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
628fn 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(®istration.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 let _ = target_dictionary.insert(target_name, router);
682 }
683 environment
684}
685
686pub 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 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 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 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}