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