1use crate::policy::PolicyError;
6use crate::rights::Rights;
7use async_trait::async_trait;
8use clonable_error::ClonableError;
9use cm_rust::{CapabilityTypeName, ExposeDeclCommon, OfferDeclCommon, SourceName, UseDeclCommon};
10use cm_types::{Availability, Name};
11use itertools::Itertools;
12use moniker::{ChildName, ExtendedMoniker, Moniker};
13use router_error::{DowncastErrorForTest, Explain, RouterError};
14use std::sync::Arc;
15use thiserror::Error;
16use {fidl_fuchsia_component as fcomponent, zx_status as zx};
17
18#[cfg(feature = "serde")]
19use serde::{Deserialize, Serialize};
20
21#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
23#[derive(Debug, Error, Clone)]
24pub enum ComponentInstanceError {
25 #[error("could not find `{moniker}`")]
26 InstanceNotFound { moniker: Moniker },
27 #[error("component is not executable `{moniker}`")]
28 InstanceNotExecutable { moniker: Moniker },
29 #[error("component manager instance unavailable")]
30 ComponentManagerInstanceUnavailable {},
31 #[error("expected a component instance, but got component manager's instance")]
32 ComponentManagerInstanceUnexpected {},
33 #[error("malformed url `{url}` for `{moniker}`")]
34 MalformedUrl { url: String, moniker: Moniker },
35 #[error("url `{url}` for `{moniker}` does not resolve to an absolute url")]
36 NoAbsoluteUrl { url: String, moniker: Moniker },
37 #[cfg_attr(feature = "serde", serde(skip))]
40 #[error("failed to resolve `{moniker}`:\n\t{err}")]
41 ResolveFailed {
42 moniker: Moniker,
43 #[source]
44 err: ClonableError,
45 },
46}
47
48impl ComponentInstanceError {
49 pub fn as_zx_status(&self) -> zx::Status {
50 match self {
51 ComponentInstanceError::ResolveFailed { .. }
52 | ComponentInstanceError::InstanceNotFound { .. }
53 | ComponentInstanceError::ComponentManagerInstanceUnavailable {}
54 | ComponentInstanceError::InstanceNotExecutable { .. }
55 | ComponentInstanceError::NoAbsoluteUrl { .. } => zx::Status::NOT_FOUND,
56 ComponentInstanceError::MalformedUrl { .. }
57 | ComponentInstanceError::ComponentManagerInstanceUnexpected { .. } => {
58 zx::Status::INTERNAL
59 }
60 }
61 }
62
63 pub fn instance_not_found(moniker: Moniker) -> ComponentInstanceError {
64 ComponentInstanceError::InstanceNotFound { moniker }
65 }
66
67 pub fn cm_instance_unavailable() -> ComponentInstanceError {
68 ComponentInstanceError::ComponentManagerInstanceUnavailable {}
69 }
70
71 pub fn resolve_failed(moniker: Moniker, err: impl Into<anyhow::Error>) -> Self {
72 Self::ResolveFailed { moniker, err: err.into().into() }
73 }
74}
75
76impl Explain for ComponentInstanceError {
77 fn as_zx_status(&self) -> zx::Status {
78 self.as_zx_status()
79 }
80}
81
82impl From<ComponentInstanceError> for ExtendedMoniker {
83 fn from(err: ComponentInstanceError) -> ExtendedMoniker {
84 match err {
85 ComponentInstanceError::InstanceNotFound { moniker }
86 | ComponentInstanceError::MalformedUrl { moniker, .. }
87 | ComponentInstanceError::NoAbsoluteUrl { moniker, .. }
88 | ComponentInstanceError::InstanceNotExecutable { moniker }
89 | ComponentInstanceError::ResolveFailed { moniker, .. } => {
90 ExtendedMoniker::ComponentInstance(moniker)
91 }
92 ComponentInstanceError::ComponentManagerInstanceUnavailable {}
93 | ComponentInstanceError::ComponentManagerInstanceUnexpected {} => {
94 ExtendedMoniker::ComponentManager
95 }
96 }
97 }
98}
99
100impl PartialEq for ComponentInstanceError {
103 fn eq(&self, other: &Self) -> bool {
104 match (self, other) {
105 (
106 Self::InstanceNotFound { moniker: self_moniker },
107 Self::InstanceNotFound { moniker: other_moniker },
108 ) => self_moniker.eq(other_moniker),
109 (
110 Self::ComponentManagerInstanceUnavailable {},
111 Self::ComponentManagerInstanceUnavailable {},
112 ) => true,
113 (Self::ResolveFailed { .. }, Self::ResolveFailed { .. }) => false,
114 _ => false,
115 }
116 }
117}
118
119#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
121#[derive(Debug, Error, Clone, PartialEq)]
122pub enum RoutingError {
123 #[error(
124 "backing directory `{capability_id}` was not exposed to `{moniker}` from `#{child_moniker}`"
125 )]
126 StorageFromChildExposeNotFound {
127 child_moniker: ChildName,
128 moniker: Moniker,
129 capability_id: String,
130 },
131
132 #[error(
133 "`{target_name:?}` tried to use a storage capability from `{source_moniker}` but it is \
134 not in the component id index. https://fuchsia.dev/go/components/instance-id"
135 )]
136 ComponentNotInIdIndex { source_moniker: Moniker, target_name: Option<ChildName> },
137
138 #[error("`{capability_id}` is not a built-in capability")]
139 UseFromComponentManagerNotFound { capability_id: String },
140
141 #[error("`{capability_id}` is not a built-in capability")]
142 RegisterFromComponentManagerNotFound { capability_id: String },
143
144 #[error("`{capability_id}` is not a built-in capability")]
145 OfferFromComponentManagerNotFound { capability_id: String },
146
147 #[error("`{capability_id}` was not offered to `{moniker}` by parent")]
148 UseFromParentNotFound { moniker: Moniker, capability_id: String },
149
150 #[error("`{capability_id}` was not declared as a capability by `{moniker}`")]
151 UseFromSelfNotFound { moniker: Moniker, capability_id: String },
152
153 #[error("`{moniker}` does not have child `#{child_moniker}`")]
154 UseFromChildInstanceNotFound {
155 child_moniker: ChildName,
156 moniker: Moniker,
157 capability_id: String,
158 },
159
160 #[error(
161 "{capability_type} `{capability_name}` was not registered in environment of `{moniker}`"
162 )]
163 UseFromEnvironmentNotFound { moniker: Moniker, capability_type: String, capability_name: Name },
164
165 #[error(
166 "`{moniker}` tried to use {capability_type} `{capability_name}` from the root environment"
167 )]
168 UseFromRootEnvironmentNotAllowed {
169 moniker: Moniker,
170 capability_type: String,
171 capability_name: Name,
172 },
173
174 #[error("{capability_type} `{capability_name}` was not offered to `{moniker}` by parent")]
175 EnvironmentFromParentNotFound {
176 moniker: Moniker,
177 capability_type: String,
178 capability_name: Name,
179 },
180
181 #[error("`{capability_name}` was not exposed to `{moniker}` from `#{child_moniker}`")]
182 EnvironmentFromChildExposeNotFound {
183 child_moniker: ChildName,
184 moniker: Moniker,
185 capability_type: String,
186 capability_name: Name,
187 },
188
189 #[error("`{moniker}` does not have child `#{child_moniker}`")]
190 EnvironmentFromChildInstanceNotFound {
191 child_moniker: ChildName,
192 moniker: Moniker,
193 capability_name: Name,
194 capability_type: String,
195 },
196
197 #[error("`{capability_id}` was not offered to `{moniker}` by parent")]
198 OfferFromParentNotFound { moniker: Moniker, capability_id: String },
199
200 #[error(
201 "cannot offer `{capability_id}` because was not declared as a capability by `{moniker}`"
202 )]
203 OfferFromSelfNotFound { moniker: Moniker, capability_id: String },
204
205 #[error("`{capability_id}` was not offered to `{moniker}` by parent")]
206 StorageFromParentNotFound { moniker: Moniker, capability_id: String },
207
208 #[error("`{moniker}` does not have child `#{child_moniker}`")]
209 OfferFromChildInstanceNotFound {
210 child_moniker: ChildName,
211 moniker: Moniker,
212 capability_id: String,
213 },
214
215 #[error("`{moniker}` does not have collection `#{collection}`")]
216 OfferFromCollectionNotFound { collection: String, moniker: Moniker, capability: Name },
217
218 #[error("`{capability_id}` was not exposed to `{moniker}` from `#{child_moniker}`")]
219 OfferFromChildExposeNotFound {
220 child_moniker: ChildName,
221 moniker: Moniker,
222 capability_id: String,
223 },
224
225 #[error("`{capability_id}` is not a framework capability (at component `{moniker}`)")]
227 CapabilityFromFrameworkNotFound { moniker: Moniker, capability_id: String },
228
229 #[error(
230 "A capability was sourced to a base capability `{capability_id}` from `{moniker}`, but this is unsupported"
231 )]
232 CapabilityFromCapabilityNotFound { moniker: Moniker, capability_id: String },
233
234 #[error("`{capability_id}` is not a framework capability")]
236 CapabilityFromComponentManagerNotFound { capability_id: String },
237
238 #[error(
239 "unable to expose `{capability_id}` because it was not declared as a capability by `{moniker}`"
240 )]
241 ExposeFromSelfNotFound { moniker: Moniker, capability_id: String },
242
243 #[error("`{moniker}` does not have child `#{child_moniker}`")]
244 ExposeFromChildInstanceNotFound {
245 child_moniker: ChildName,
246 moniker: Moniker,
247 capability_id: String,
248 },
249
250 #[error("`{moniker}` does not have collection `#{collection}`")]
251 ExposeFromCollectionNotFound { collection: String, moniker: Moniker, capability: Name },
252
253 #[error("`{capability_id}` was not exposed to `{moniker}` from `#{child_moniker}`")]
254 ExposeFromChildExposeNotFound {
255 child_moniker: ChildName,
256 moniker: Moniker,
257 capability_id: String,
258 },
259
260 #[error(
261 "`{moniker}` tried to expose `{capability_id}` from the framework, but no such framework capability was found"
262 )]
263 ExposeFromFrameworkNotFound { moniker: Moniker, capability_id: String },
264
265 #[error("`{capability_id}` was not exposed to `{moniker}` from `#{child_moniker}`")]
266 UseFromChildExposeNotFound { child_moniker: ChildName, moniker: Moniker, capability_id: String },
267
268 #[error("`{capability_id}` was not exposed from `/`")]
269 UseFromRootExposeNotFound { capability_id: String },
270
271 #[error("routing a capability from an unsupported source type `{source_type}` at `{moniker}`")]
272 UnsupportedRouteSource { source_type: String, moniker: ExtendedMoniker },
273
274 #[error("routing a capability of an unsupported type `{type_name}` at `{moniker}`")]
275 UnsupportedCapabilityType { type_name: CapabilityTypeName, moniker: ExtendedMoniker },
276
277 #[error(
278 "dictionaries are not yet supported for {cap_type} capabilities at component `{moniker}`"
279 )]
280 DictionariesNotSupported { moniker: Moniker, cap_type: CapabilityTypeName },
281
282 #[error("dynamic dictionaries are not allowed at component `{moniker}`")]
283 DynamicDictionariesNotAllowed { moniker: Moniker },
284
285 #[error("the capability does not support member access at `{moniker}`")]
286 BedrockMemberAccessUnsupported { moniker: ExtendedMoniker },
287
288 #[error("item `{name}` is not present in dictionary at component `{moniker}`")]
289 BedrockNotPresentInDictionary { name: String, moniker: ExtendedMoniker },
290
291 #[error(
292 "routed capability was the wrong type at component `{moniker}`. Was: {actual}, expected: {expected}"
293 )]
294 BedrockWrongCapabilityType { actual: String, expected: String, moniker: ExtendedMoniker },
295
296 #[error(
297 "expected type {type_name} for routed capability at component `{moniker}`, but type was missing"
298 )]
299 BedrockMissingCapabilityType { type_name: String, moniker: ExtendedMoniker },
300
301 #[error("there was an error remoting a capability at component `{moniker}`")]
302 BedrockRemoteCapability { moniker: Moniker },
303
304 #[error("source dictionary was not found in child's exposes at component `{moniker}`")]
305 BedrockSourceDictionaryExposeNotFound { moniker: Moniker },
306
307 #[error("Some capability in the routing chain could not be cloned at `{moniker}`.")]
308 BedrockNotCloneable { moniker: ExtendedMoniker },
309
310 #[error(
311 "a capability in a dictionary extended from a source dictionary collides with \
312 a capability in the source dictionary that has the same key at `{moniker}`"
313 )]
314 BedrockSourceDictionaryCollision { moniker: ExtendedMoniker },
315
316 #[error("failed to send message for capability `{capability_id}` from component `{moniker}`")]
317 BedrockFailedToSend { moniker: ExtendedMoniker, capability_id: String },
318
319 #[error(
320 "failed to route capability because the route source has been shutdown and possibly destroyed"
321 )]
322 RouteSourceShutdown { moniker: Moniker },
323
324 #[error(transparent)]
325 ComponentInstanceError(#[from] ComponentInstanceError),
326
327 #[error(transparent)]
328 EventsRoutingError(#[from] EventsRoutingError),
329
330 #[error(transparent)]
331 RightsRoutingError(#[from] RightsRoutingError),
332
333 #[error(transparent)]
334 AvailabilityRoutingError(#[from] AvailabilityRoutingError),
335
336 #[error(transparent)]
337 PolicyError(#[from] PolicyError),
338
339 #[error(
340 "source capability at component {moniker} is void. \
341 If the offer/expose declaration has `source_availability` set to `unknown`, \
342 the source component instance likely isn't defined in the component declaration"
343 )]
344 SourceCapabilityIsVoid { moniker: Moniker },
345
346 #[error(
347 "routes that do not set the `debug` flag are unsupported in the current configuration (at `{moniker}`)."
348 )]
349 NonDebugRoutesUnsupported { moniker: ExtendedMoniker },
350
351 #[error("debug routes are unsupported for external routers (at `{moniker}`).")]
352 DebugRoutesUnsupported { moniker: ExtendedMoniker },
353
354 #[error("{type_name} router unexpectedly returned debug info for target {moniker}")]
355 RouteUnexpectedDebug { type_name: CapabilityTypeName, moniker: ExtendedMoniker },
356
357 #[error("{type_name} router unexpectedly returned unavailable for target {moniker}")]
358 RouteUnexpectedUnavailable { type_name: CapabilityTypeName, moniker: ExtendedMoniker },
359
360 #[error("{name} at {moniker} is missing porcelain type metadata.")]
361 MissingPorcelainType { name: Name, moniker: Moniker },
362
363 #[error("path at `{moniker}` was too long for `{keyword}`: {path}")]
364 PathTooLong { moniker: ExtendedMoniker, path: String, keyword: String },
365
366 #[error(
367 "conflicting dictionary entries detected component `{moniker}`: {}",
368 conflicting_names.iter().map(|n| format!("{}", n)).join(", ")
369 )]
370 ConflictingDictionaryEntries { moniker: ExtendedMoniker, conflicting_names: Vec<Name> },
371}
372
373impl Explain for RoutingError {
374 fn as_zx_status(&self) -> zx::Status {
376 match self {
377 RoutingError::UseFromRootEnvironmentNotAllowed { .. }
378 | RoutingError::DynamicDictionariesNotAllowed { .. } => zx::Status::ACCESS_DENIED,
379 RoutingError::StorageFromChildExposeNotFound { .. }
380 | RoutingError::ComponentNotInIdIndex { .. }
381 | RoutingError::UseFromComponentManagerNotFound { .. }
382 | RoutingError::RegisterFromComponentManagerNotFound { .. }
383 | RoutingError::OfferFromComponentManagerNotFound { .. }
384 | RoutingError::UseFromParentNotFound { .. }
385 | RoutingError::UseFromSelfNotFound { .. }
386 | RoutingError::UseFromChildInstanceNotFound { .. }
387 | RoutingError::UseFromEnvironmentNotFound { .. }
388 | RoutingError::EnvironmentFromParentNotFound { .. }
389 | RoutingError::EnvironmentFromChildExposeNotFound { .. }
390 | RoutingError::EnvironmentFromChildInstanceNotFound { .. }
391 | RoutingError::OfferFromParentNotFound { .. }
392 | RoutingError::OfferFromSelfNotFound { .. }
393 | RoutingError::StorageFromParentNotFound { .. }
394 | RoutingError::OfferFromChildInstanceNotFound { .. }
395 | RoutingError::OfferFromCollectionNotFound { .. }
396 | RoutingError::OfferFromChildExposeNotFound { .. }
397 | RoutingError::CapabilityFromFrameworkNotFound { .. }
398 | RoutingError::CapabilityFromCapabilityNotFound { .. }
399 | RoutingError::CapabilityFromComponentManagerNotFound { .. }
400 | RoutingError::ConflictingDictionaryEntries { .. }
401 | RoutingError::ExposeFromSelfNotFound { .. }
402 | RoutingError::ExposeFromChildInstanceNotFound { .. }
403 | RoutingError::ExposeFromCollectionNotFound { .. }
404 | RoutingError::ExposeFromChildExposeNotFound { .. }
405 | RoutingError::ExposeFromFrameworkNotFound { .. }
406 | RoutingError::UseFromChildExposeNotFound { .. }
407 | RoutingError::UseFromRootExposeNotFound { .. }
408 | RoutingError::UnsupportedRouteSource { .. }
409 | RoutingError::UnsupportedCapabilityType { .. }
410 | RoutingError::EventsRoutingError(_)
411 | RoutingError::BedrockNotPresentInDictionary { .. }
412 | RoutingError::BedrockSourceDictionaryExposeNotFound { .. }
413 | RoutingError::BedrockSourceDictionaryCollision { .. }
414 | RoutingError::BedrockFailedToSend { .. }
415 | RoutingError::RouteSourceShutdown { .. }
416 | RoutingError::BedrockMissingCapabilityType { .. }
417 | RoutingError::BedrockWrongCapabilityType { .. }
418 | RoutingError::BedrockRemoteCapability { .. }
419 | RoutingError::BedrockNotCloneable { .. }
420 | RoutingError::AvailabilityRoutingError(_)
421 | RoutingError::PathTooLong { .. } => zx::Status::NOT_FOUND,
422 RoutingError::BedrockMemberAccessUnsupported { .. }
423 | RoutingError::NonDebugRoutesUnsupported { .. }
424 | RoutingError::DebugRoutesUnsupported { .. }
425 | RoutingError::DictionariesNotSupported { .. } => zx::Status::NOT_SUPPORTED,
426 RoutingError::ComponentInstanceError(err) => err.as_zx_status(),
427 RoutingError::RightsRoutingError(err) => err.as_zx_status(),
428 RoutingError::PolicyError(err) => err.as_zx_status(),
429 RoutingError::SourceCapabilityIsVoid { .. } => zx::Status::NOT_FOUND,
430 RoutingError::RouteUnexpectedDebug { .. }
431 | RoutingError::RouteUnexpectedUnavailable { .. }
432 | RoutingError::MissingPorcelainType { .. } => zx::Status::INTERNAL,
433 }
434 }
435}
436
437impl From<RoutingError> for ExtendedMoniker {
438 fn from(err: RoutingError) -> ExtendedMoniker {
439 match err {
440 RoutingError::BedrockRemoteCapability { moniker, .. }
441 | RoutingError::BedrockSourceDictionaryExposeNotFound { moniker, .. }
442 | RoutingError::CapabilityFromCapabilityNotFound { moniker, .. }
443 | RoutingError::CapabilityFromFrameworkNotFound { moniker, .. }
444 | RoutingError::ComponentNotInIdIndex { source_moniker: moniker, .. }
445 | RoutingError::DictionariesNotSupported { moniker, .. }
446 | RoutingError::EnvironmentFromChildExposeNotFound { moniker, .. }
447 | RoutingError::EnvironmentFromChildInstanceNotFound { moniker, .. }
448 | RoutingError::EnvironmentFromParentNotFound { moniker, .. }
449 | RoutingError::ExposeFromChildExposeNotFound { moniker, .. }
450 | RoutingError::ExposeFromChildInstanceNotFound { moniker, .. }
451 | RoutingError::ExposeFromCollectionNotFound { moniker, .. }
452 | RoutingError::ExposeFromFrameworkNotFound { moniker, .. }
453 | RoutingError::ExposeFromSelfNotFound { moniker, .. }
454 | RoutingError::OfferFromChildExposeNotFound { moniker, .. }
455 | RoutingError::OfferFromChildInstanceNotFound { moniker, .. }
456 | RoutingError::OfferFromCollectionNotFound { moniker, .. }
457 | RoutingError::OfferFromParentNotFound { moniker, .. }
458 | RoutingError::OfferFromSelfNotFound { moniker, .. }
459 | RoutingError::SourceCapabilityIsVoid { moniker, .. }
460 | RoutingError::StorageFromChildExposeNotFound { moniker, .. }
461 | RoutingError::StorageFromParentNotFound { moniker, .. }
462 | RoutingError::UseFromChildExposeNotFound { moniker, .. }
463 | RoutingError::UseFromChildInstanceNotFound { moniker, .. }
464 | RoutingError::UseFromEnvironmentNotFound { moniker, .. }
465 | RoutingError::UseFromParentNotFound { moniker, .. }
466 | RoutingError::UseFromRootEnvironmentNotAllowed { moniker, .. }
467 | RoutingError::DynamicDictionariesNotAllowed { moniker, .. }
468 | RoutingError::RouteSourceShutdown { moniker }
469 | RoutingError::UseFromSelfNotFound { moniker, .. }
470 | RoutingError::MissingPorcelainType { moniker, .. } => moniker.into(),
471 RoutingError::PathTooLong { moniker, .. } => moniker,
472
473 RoutingError::BedrockMemberAccessUnsupported { moniker }
474 | RoutingError::BedrockNotPresentInDictionary { moniker, .. }
475 | RoutingError::BedrockNotCloneable { moniker }
476 | RoutingError::BedrockSourceDictionaryCollision { moniker }
477 | RoutingError::BedrockFailedToSend { moniker, .. }
478 | RoutingError::BedrockMissingCapabilityType { moniker, .. }
479 | RoutingError::BedrockWrongCapabilityType { moniker, .. }
480 | RoutingError::ConflictingDictionaryEntries { moniker, .. }
481 | RoutingError::NonDebugRoutesUnsupported { moniker }
482 | RoutingError::DebugRoutesUnsupported { moniker }
483 | RoutingError::RouteUnexpectedDebug { moniker, .. }
484 | RoutingError::RouteUnexpectedUnavailable { moniker, .. }
485 | RoutingError::UnsupportedCapabilityType { moniker, .. }
486 | RoutingError::UnsupportedRouteSource { moniker, .. } => moniker,
487 RoutingError::AvailabilityRoutingError(err) => err.into(),
488 RoutingError::ComponentInstanceError(err) => err.into(),
489 RoutingError::EventsRoutingError(err) => err.into(),
490 RoutingError::PolicyError(err) => err.into(),
491 RoutingError::RightsRoutingError(err) => err.into(),
492
493 RoutingError::CapabilityFromComponentManagerNotFound { .. }
494 | RoutingError::OfferFromComponentManagerNotFound { .. }
495 | RoutingError::RegisterFromComponentManagerNotFound { .. }
496 | RoutingError::UseFromComponentManagerNotFound { .. }
497 | RoutingError::UseFromRootExposeNotFound { .. } => ExtendedMoniker::ComponentManager,
498 }
499 }
500}
501
502impl From<RoutingError> for RouterError {
503 fn from(value: RoutingError) -> Self {
504 Self::NotFound(Arc::new(value))
505 }
506}
507
508impl From<RouterError> for RoutingError {
509 fn from(value: RouterError) -> Self {
510 match value {
511 RouterError::NotFound(arc_dyn_explain) => {
512 arc_dyn_explain.downcast_for_test::<Self>().clone()
513 }
514 err => panic!("Cannot downcast {err} to RoutingError!"),
515 }
516 }
517}
518
519impl RoutingError {
520 pub fn as_fidl_error(&self) -> fcomponent::Error {
522 fcomponent::Error::ResourceUnavailable
523 }
524
525 pub fn storage_from_child_expose_not_found(
526 child_moniker: &ChildName,
527 moniker: &Moniker,
528 capability_id: impl Into<String>,
529 ) -> Self {
530 Self::StorageFromChildExposeNotFound {
531 child_moniker: child_moniker.clone(),
532 moniker: moniker.clone(),
533 capability_id: capability_id.into(),
534 }
535 }
536
537 pub fn use_from_component_manager_not_found(capability_id: impl Into<String>) -> Self {
538 Self::UseFromComponentManagerNotFound { capability_id: capability_id.into() }
539 }
540
541 pub fn register_from_component_manager_not_found(capability_id: impl Into<String>) -> Self {
542 Self::RegisterFromComponentManagerNotFound { capability_id: capability_id.into() }
543 }
544
545 pub fn offer_from_component_manager_not_found(capability_id: impl Into<String>) -> Self {
546 Self::OfferFromComponentManagerNotFound { capability_id: capability_id.into() }
547 }
548
549 pub fn use_from_parent_not_found(moniker: &Moniker, capability_id: impl Into<String>) -> Self {
550 Self::UseFromParentNotFound {
551 moniker: moniker.clone(),
552 capability_id: capability_id.into(),
553 }
554 }
555
556 pub fn use_from_self_not_found(moniker: &Moniker, capability_id: impl Into<String>) -> Self {
557 Self::UseFromSelfNotFound { moniker: moniker.clone(), capability_id: capability_id.into() }
558 }
559
560 pub fn use_from_child_instance_not_found(
561 child_moniker: &ChildName,
562 moniker: &Moniker,
563 capability_id: impl Into<String>,
564 ) -> Self {
565 Self::UseFromChildInstanceNotFound {
566 child_moniker: child_moniker.clone(),
567 moniker: moniker.clone(),
568 capability_id: capability_id.into(),
569 }
570 }
571
572 pub fn use_from_environment_not_found(
573 moniker: &Moniker,
574 capability_type: impl Into<String>,
575 capability_name: &Name,
576 ) -> Self {
577 Self::UseFromEnvironmentNotFound {
578 moniker: moniker.clone(),
579 capability_type: capability_type.into(),
580 capability_name: capability_name.clone(),
581 }
582 }
583
584 pub fn offer_from_parent_not_found(
585 moniker: &Moniker,
586 capability_id: impl Into<String>,
587 ) -> Self {
588 Self::OfferFromParentNotFound {
589 moniker: moniker.clone(),
590 capability_id: capability_id.into(),
591 }
592 }
593
594 pub fn offer_from_self_not_found(moniker: &Moniker, capability_id: impl Into<String>) -> Self {
595 Self::OfferFromSelfNotFound {
596 moniker: moniker.clone(),
597 capability_id: capability_id.into(),
598 }
599 }
600
601 pub fn storage_from_parent_not_found(
602 moniker: &Moniker,
603 capability_id: impl Into<String>,
604 ) -> Self {
605 Self::StorageFromParentNotFound {
606 moniker: moniker.clone(),
607 capability_id: capability_id.into(),
608 }
609 }
610
611 pub fn offer_from_child_instance_not_found(
612 child_moniker: &ChildName,
613 moniker: &Moniker,
614 capability_id: impl Into<String>,
615 ) -> Self {
616 Self::OfferFromChildInstanceNotFound {
617 child_moniker: child_moniker.clone(),
618 moniker: moniker.clone(),
619 capability_id: capability_id.into(),
620 }
621 }
622
623 pub fn offer_from_child_expose_not_found(
624 child_moniker: &ChildName,
625 moniker: &Moniker,
626 capability_id: impl Into<String>,
627 ) -> Self {
628 Self::OfferFromChildExposeNotFound {
629 child_moniker: child_moniker.clone(),
630 moniker: moniker.clone(),
631 capability_id: capability_id.into(),
632 }
633 }
634
635 pub fn use_from_child_expose_not_found(
636 child_moniker: &ChildName,
637 moniker: &Moniker,
638 capability_id: impl Into<String>,
639 ) -> Self {
640 Self::UseFromChildExposeNotFound {
641 child_moniker: child_moniker.clone(),
642 moniker: moniker.clone(),
643 capability_id: capability_id.into(),
644 }
645 }
646
647 pub fn expose_from_self_not_found(moniker: &Moniker, capability_id: impl Into<String>) -> Self {
648 Self::ExposeFromSelfNotFound {
649 moniker: moniker.clone(),
650 capability_id: capability_id.into(),
651 }
652 }
653
654 pub fn expose_from_child_instance_not_found(
655 child_moniker: &ChildName,
656 moniker: &Moniker,
657 capability_id: impl Into<String>,
658 ) -> Self {
659 Self::ExposeFromChildInstanceNotFound {
660 child_moniker: child_moniker.clone(),
661 moniker: moniker.clone(),
662 capability_id: capability_id.into(),
663 }
664 }
665
666 pub fn expose_from_child_expose_not_found(
667 child_moniker: &ChildName,
668 moniker: &Moniker,
669 capability_id: impl Into<String>,
670 ) -> Self {
671 Self::ExposeFromChildExposeNotFound {
672 child_moniker: child_moniker.clone(),
673 moniker: moniker.clone(),
674 capability_id: capability_id.into(),
675 }
676 }
677
678 pub fn capability_from_framework_not_found(
679 moniker: &Moniker,
680 capability_id: impl Into<String>,
681 ) -> Self {
682 Self::CapabilityFromFrameworkNotFound {
683 moniker: moniker.clone(),
684 capability_id: capability_id.into(),
685 }
686 }
687
688 pub fn capability_from_capability_not_found(
689 moniker: &Moniker,
690 capability_id: impl Into<String>,
691 ) -> Self {
692 Self::CapabilityFromCapabilityNotFound {
693 moniker: moniker.clone(),
694 capability_id: capability_id.into(),
695 }
696 }
697
698 pub fn capability_from_component_manager_not_found(capability_id: impl Into<String>) -> Self {
699 Self::CapabilityFromComponentManagerNotFound { capability_id: capability_id.into() }
700 }
701
702 pub fn expose_from_framework_not_found(
703 moniker: &Moniker,
704 capability_id: impl Into<String>,
705 ) -> Self {
706 Self::ExposeFromFrameworkNotFound {
707 moniker: moniker.clone(),
708 capability_id: capability_id.into(),
709 }
710 }
711
712 pub fn unsupported_route_source(
713 moniker: impl Into<ExtendedMoniker>,
714 source: impl Into<String>,
715 ) -> Self {
716 Self::UnsupportedRouteSource { source_type: source.into(), moniker: moniker.into() }
717 }
718
719 pub fn unsupported_capability_type(
720 moniker: impl Into<ExtendedMoniker>,
721 type_name: impl Into<CapabilityTypeName>,
722 ) -> Self {
723 Self::UnsupportedCapabilityType { type_name: type_name.into(), moniker: moniker.into() }
724 }
725}
726
727#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
729#[derive(Error, Debug, Clone, PartialEq)]
730pub enum EventsRoutingError {
731 #[error("filter is not a subset at `{moniker}`")]
732 InvalidFilter { moniker: ExtendedMoniker },
733
734 #[error("event routes must end at source with a filter declaration at `{moniker}`")]
735 MissingFilter { moniker: ExtendedMoniker },
736}
737
738impl From<EventsRoutingError> for ExtendedMoniker {
739 fn from(err: EventsRoutingError) -> ExtendedMoniker {
740 match err {
741 EventsRoutingError::InvalidFilter { moniker }
742 | EventsRoutingError::MissingFilter { moniker } => moniker,
743 }
744 }
745}
746
747#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
748#[derive(Debug, Error, Clone, PartialEq)]
749pub enum RightsRoutingError {
750 #[error(
751 "requested rights ({requested}) greater than provided rights ({provided}) at \"{moniker}\""
752 )]
753 Invalid { moniker: ExtendedMoniker, requested: Rights, provided: Rights },
754
755 #[error(
756 "directory routes must end at source with a rights declaration, it's missing at \"{moniker}\""
757 )]
758 MissingRightsSource { moniker: ExtendedMoniker },
759}
760
761impl RightsRoutingError {
762 pub fn as_zx_status(&self) -> zx::Status {
764 match self {
765 RightsRoutingError::Invalid { .. } => zx::Status::ACCESS_DENIED,
766 RightsRoutingError::MissingRightsSource { .. } => zx::Status::NOT_FOUND,
767 }
768 }
769}
770
771impl From<RightsRoutingError> for ExtendedMoniker {
772 fn from(err: RightsRoutingError) -> ExtendedMoniker {
773 match err {
774 RightsRoutingError::Invalid { moniker, .. }
775 | RightsRoutingError::MissingRightsSource { moniker } => moniker,
776 }
777 }
778}
779
780#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
781#[derive(Debug, Error, Clone, PartialEq)]
782pub enum AvailabilityRoutingError {
783 #[error(
784 "availability requested by the target has stronger guarantees than what \
785 is being provided at the source at `{moniker}`"
786 )]
787 TargetHasStrongerAvailability { moniker: ExtendedMoniker },
788
789 #[error("offer uses void source, but target requires the capability at `{moniker}`")]
790 OfferFromVoidToRequiredTarget { moniker: ExtendedMoniker },
791
792 #[error("expose uses void source, but target requires the capability at `{moniker}`")]
793 ExposeFromVoidToRequiredTarget { moniker: ExtendedMoniker },
794}
795
796impl From<availability::TargetHasStrongerAvailability> for AvailabilityRoutingError {
797 fn from(value: availability::TargetHasStrongerAvailability) -> Self {
798 let availability::TargetHasStrongerAvailability { moniker } = value;
799 AvailabilityRoutingError::TargetHasStrongerAvailability { moniker }
800 }
801}
802
803impl From<AvailabilityRoutingError> for ExtendedMoniker {
804 fn from(err: AvailabilityRoutingError) -> ExtendedMoniker {
805 match err {
806 AvailabilityRoutingError::ExposeFromVoidToRequiredTarget { moniker }
807 | AvailabilityRoutingError::OfferFromVoidToRequiredTarget { moniker }
808 | AvailabilityRoutingError::TargetHasStrongerAvailability { moniker } => moniker,
809 }
810 }
811}
812
813#[async_trait]
816pub trait ErrorReporter: Clone + Send + Sync + 'static {
817 async fn report(
818 &self,
819 request: &RouteRequestErrorInfo,
820 err: &RouterError,
821 route_target: sandbox::WeakInstanceToken,
822 );
823}
824
825pub struct RouteRequestErrorInfo {
827 capability_type: cm_rust::CapabilityTypeName,
828 name: cm_types::Name,
829 availability: cm_rust::Availability,
830}
831
832impl RouteRequestErrorInfo {
833 pub fn availability(&self) -> cm_rust::Availability {
834 self.availability
835 }
836
837 pub fn for_builtin(capability_type: CapabilityTypeName, name: &Name) -> Self {
838 Self { capability_type, name: name.clone(), availability: Availability::Required }
839 }
840}
841
842impl From<&cm_rust::UseDecl> for RouteRequestErrorInfo {
843 fn from(value: &cm_rust::UseDecl) -> Self {
844 RouteRequestErrorInfo {
845 capability_type: value.into(),
846 name: value.source_name().clone(),
847 availability: value.availability().clone(),
848 }
849 }
850}
851
852impl From<&cm_rust::UseConfigurationDecl> for RouteRequestErrorInfo {
853 fn from(value: &cm_rust::UseConfigurationDecl) -> Self {
854 RouteRequestErrorInfo {
855 capability_type: CapabilityTypeName::Config,
856 name: value.source_name().clone(),
857 availability: value.availability().clone(),
858 }
859 }
860}
861
862impl From<&cm_rust::UseEventStreamDecl> for RouteRequestErrorInfo {
863 fn from(value: &cm_rust::UseEventStreamDecl) -> Self {
864 RouteRequestErrorInfo {
865 capability_type: CapabilityTypeName::EventStream,
866 name: value.source_name.clone(),
867 availability: value.availability,
868 }
869 }
870}
871
872impl From<&cm_rust::ExposeDecl> for RouteRequestErrorInfo {
873 fn from(value: &cm_rust::ExposeDecl) -> Self {
874 RouteRequestErrorInfo {
875 capability_type: value.into(),
876 name: value.target_name().clone(),
877 availability: value.availability().clone(),
878 }
879 }
880}
881
882impl From<&cm_rust::OfferDecl> for RouteRequestErrorInfo {
883 fn from(value: &cm_rust::OfferDecl) -> Self {
884 RouteRequestErrorInfo {
885 capability_type: value.into(),
886 name: value.target_name().clone(),
887 availability: value.availability().clone(),
888 }
889 }
890}
891
892impl From<&cm_rust::ResolverRegistration> for RouteRequestErrorInfo {
893 fn from(value: &cm_rust::ResolverRegistration) -> Self {
894 RouteRequestErrorInfo {
895 capability_type: CapabilityTypeName::Resolver,
896 name: value.source_name().clone(),
897 availability: Availability::Required,
898 }
899 }
900}
901
902impl From<&cm_rust::RunnerRegistration> for RouteRequestErrorInfo {
903 fn from(value: &cm_rust::RunnerRegistration) -> Self {
904 RouteRequestErrorInfo {
905 capability_type: CapabilityTypeName::Runner,
906 name: value.source_name().clone(),
907 availability: Availability::Required,
908 }
909 }
910}
911
912impl From<&cm_rust::DebugRegistration> for RouteRequestErrorInfo {
913 fn from(value: &cm_rust::DebugRegistration) -> Self {
914 RouteRequestErrorInfo {
915 capability_type: CapabilityTypeName::Protocol,
916 name: value.source_name().clone(),
917 availability: Availability::Required,
918 }
919 }
920}
921
922impl From<&cm_rust::CapabilityDecl> for RouteRequestErrorInfo {
923 fn from(value: &cm_rust::CapabilityDecl) -> Self {
924 RouteRequestErrorInfo {
925 capability_type: value.into(),
926 name: value.name().clone(),
927 availability: Availability::Required,
928 }
929 }
930}
931
932impl std::fmt::Display for RouteRequestErrorInfo {
933 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
934 write!(f, "{} `{}`", self.capability_type, self.name)
935 }
936}