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