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