1pub mod availability;
6pub mod bedrock;
7pub mod component_instance;
8pub mod config;
9pub mod error;
10pub mod error_logging_router;
11pub mod policy;
12pub mod resolving;
13pub mod rights;
14pub mod subdir;
15
16use crate::bedrock::request_metadata::directory_metadata;
17use crate::component_instance::{ComponentInstanceInterface, ResolvedInstanceInterface};
18use crate::error::RoutingError;
19use capability_source::CapabilitySource;
20use cm_rust::{
21 Availability, ExposeDecl, ExposeDeclCommon, ExposeTarget, OfferDecl, OfferDeclCommon,
22 OfferTarget, StorageDecl, StorageDirectorySource, UseDecl,
23};
24use cm_types::{IterablePath, Name, RelativePath};
25use fidl_fuchsia_component_runtime::RouteRequest;
26use fidl_fuchsia_io::RW_STAR_DIR;
27use itertools::Itertools;
28use moniker::ChildName;
29use runtime_capabilities::{
30 Capability, CapabilityBound, Dictionary, DirConnector, Routable, Router,
31};
32use std::fmt::Debug;
33use std::sync::Arc;
34
35pub use bedrock::dict_ext::DictExt;
36pub use bedrock::lazy_get::LazyGet;
37pub use bedrock::weak_instance_token_ext::{WeakInstanceTokenExt, test_invalid_instance_token};
38pub use bedrock::with_porcelain::WithPorcelain;
39
40#[derive(Clone)]
41pub struct SandboxPath {
42 path: String,
43}
44
45impl SandboxPath {
46 pub fn resolver(scheme: &str) -> Self {
47 Self { path: format!("component_input/environment/resolvers/{}", scheme) }
48 }
49
50 pub fn used_path(target_path: &impl IterablePath) -> Self {
51 let path: RelativePath = target_path.iter_segments().collect::<Vec<_>>().into();
52 Self { path: format!("program_input/namespace/{}", path) }
53 }
54}
55
56impl From<&UseDecl> for SandboxPath {
57 fn from(use_decl: &UseDecl) -> Self {
58 let path = match use_decl {
59 UseDecl::Config(u) => format!("program_input/config/{}", u.target_name),
60 UseDecl::Dictionary(u) => format!("program_input/namespace{}", u.target_path),
61 UseDecl::Directory(u) => format!("program_input/namespace{}", u.target_path),
62 UseDecl::EventStream(u) => format!("program_input/namespace{}", u.target_path),
63 UseDecl::Protocol(u) => match (&u.target_path, &u.numbered_handle) {
64 (Some(target_path), None) => format!("program_input/namespace{}", target_path),
65 (None, Some(numbered_handle)) => {
66 format!("program_input/numbered_handles/{}", Name::from(*numbered_handle))
67 }
68 _ => panic!("invalid use decl"),
69 },
70 UseDecl::Runner(_u) => "program_input/runner".to_string(),
71 UseDecl::Service(u) => format!("program_input/namespace{}", u.target_path),
72 UseDecl::Storage(u) => format!("program_input/namespace{}", u.target_path),
73 };
74 Self { path }
75 }
76}
77
78impl From<&OfferDecl> for SandboxPath {
79 fn from(offer_decl: &OfferDecl) -> Self {
80 let path = match offer_decl.target() {
81 OfferTarget::Child(child_ref) if child_ref.collection.is_some() => {
82 panic!("dynamic offers not supported")
83 }
84 OfferTarget::Child(child_ref) => {
85 format!("child_inputs/{}/parent/{}", child_ref.name, offer_decl.target_name())
86 }
87 OfferTarget::Collection(name) => {
88 format!("collection_inputs/{}/parent/{}", name, offer_decl.target_name())
89 }
90 OfferTarget::Capability(name) => {
91 format!("declared_dictionaries/{}/{}", name, offer_decl.target_name())
92 }
93 };
94 Self { path }
95 }
96}
97
98impl From<&ExposeDecl> for SandboxPath {
99 fn from(expose_decl: &ExposeDecl) -> Self {
100 let path = match expose_decl.target() {
101 ExposeTarget::Parent => {
102 format!("component_output/parent/{}", expose_decl.target_name())
103 }
104 ExposeTarget::Framework => {
105 format!("component_output/framework/{}", expose_decl.target_name())
106 }
107 };
108 Self { path }
109 }
110}
111
112impl From<SandboxPath> for RelativePath {
113 fn from(path: SandboxPath) -> Self {
114 RelativePath::new(&path.path).expect("invalid path string")
115 }
116}
117
118pub async fn debug_route_sandbox_path<C: ComponentInstanceInterface + 'static>(
121 component: &Arc<C>,
122 sandbox_path: impl Into<SandboxPath>,
123) -> Result<CapabilitySource, RoutingError> {
124 debug_route_sandbox_path_with_request(component, sandbox_path, RouteRequest::default()).await
125}
126
127pub async fn debug_route_sandbox_path_with_request<C: ComponentInstanceInterface + 'static>(
130 component: &Arc<C>,
131 sandbox_path: impl Into<SandboxPath>,
132 request: RouteRequest,
133) -> Result<CapabilitySource, RoutingError> {
134 let sandbox_path = sandbox_path.into();
135 let path: RelativePath = sandbox_path.clone().into();
136 let sandbox = component.component_sandbox().await.map_err(RoutingError::from)?;
137 let sandbox_dictionary: Dictionary = sandbox.into();
138 let component_moniker = component.moniker().clone();
139 sandbox_dictionary
140 .get_with_request_debug(
141 &component_moniker.into(),
142 &path,
143 request,
144 component.as_weak().into(),
145 )
146 .await
147 .map_err(|e| RoutingError::try_from(e).expect("invalid routing error"))
148}
149
150pub async fn debug_route_storage_backing_directory<C: ComponentInstanceInterface + 'static>(
152 component: &Arc<C>,
153 storage_decl: StorageDecl,
154) -> Result<CapabilitySource, RoutingError> {
155 let component_sandbox = component.component_sandbox().await?;
156 let source_dictionary = match storage_decl.source {
157 StorageDirectorySource::Parent => component_sandbox.component_input.capabilities(),
158 StorageDirectorySource::Self_ => component_sandbox.program_output_dict.clone(),
159 StorageDirectorySource::Child(static_name) => {
160 let child_name = ChildName::parse(static_name)
161 .expect("invalid child name, this should be prevented by manifest validation");
162 let child_component = component
163 .lock_resolved_state()
164 .await?
165 .get_child(&child_name)
166 .expect("resolver registration references nonexistent static child, this should be prevented by manifest validation");
167 let child_sandbox = child_component.component_sandbox().await?;
168 child_sandbox.component_output.capabilities().clone()
169 }
170 };
171 route_capability_inner::<DirConnector, _>(
172 &source_dictionary,
173 &storage_decl.backing_dir,
174 directory_metadata(Availability::Required, Some(RW_STAR_DIR.into()), None),
175 component,
176 )
177 .await
178}
179
180async fn route_capability_inner<T, C>(
181 dictionary: &Dictionary,
182 path: &impl IterablePath,
183 request: RouteRequest,
184 target: &Arc<C>,
185) -> Result<CapabilitySource, RoutingError>
186where
187 C: ComponentInstanceInterface + 'static,
188 T: CapabilityBound + Debug,
189 Router<T>: TryFrom<Capability>,
190{
191 let router = dictionary.get_router_or_not_found(
192 path,
193 RoutingError::BedrockNotPresentInDictionary {
194 moniker: target.moniker().clone().into(),
195 name: path.iter_segments().join("/"),
196 },
197 );
198 perform_route::<T, C>(router, request, target).await
199}
200
201async fn perform_route<T, C>(
202 router: impl Routable<T>,
203 request: RouteRequest,
204 target: &Arc<C>,
205) -> Result<CapabilitySource, RoutingError>
206where
207 C: ComponentInstanceInterface + 'static,
208 T: CapabilityBound + Debug,
209 Router<T>: TryFrom<Capability>,
210{
211 router
212 .route_debug(request, target.as_weak().into())
213 .await
214 .map_err(|e| RoutingError::try_from(e).unwrap_or(RoutingError::UnexpectedError))
215}