routing/
error.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// Errors produced by `ComponentInstanceInterface`.
21#[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    // The capability routing static analyzer never produces this error subtype, so we don't need
37    // to serialize it.
38    #[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
99// Custom implementation of PartialEq in which two ComponentInstanceError::ResolveFailed errors are
100// never equal.
101impl 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/// Errors produced during routing.
119#[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    // TODO: Could this be distinguished by use/offer/expose?
225    #[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    // TODO: Could this be distinguished by use/offer/expose?
234    #[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
366impl Explain for RoutingError {
367    /// Convert this error into its approximate `zx::Status` equivalent.
368    fn as_zx_status(&self) -> zx::Status {
369        match self {
370            RoutingError::UseFromRootEnvironmentNotAllowed { .. }
371            | RoutingError::DynamicDictionariesNotAllowed { .. } => zx::Status::ACCESS_DENIED,
372            RoutingError::StorageFromChildExposeNotFound { .. }
373            | RoutingError::ComponentNotInIdIndex { .. }
374            | RoutingError::UseFromComponentManagerNotFound { .. }
375            | RoutingError::RegisterFromComponentManagerNotFound { .. }
376            | RoutingError::OfferFromComponentManagerNotFound { .. }
377            | RoutingError::UseFromParentNotFound { .. }
378            | RoutingError::UseFromSelfNotFound { .. }
379            | RoutingError::UseFromChildInstanceNotFound { .. }
380            | RoutingError::UseFromEnvironmentNotFound { .. }
381            | RoutingError::EnvironmentFromParentNotFound { .. }
382            | RoutingError::EnvironmentFromChildExposeNotFound { .. }
383            | RoutingError::EnvironmentFromChildInstanceNotFound { .. }
384            | RoutingError::OfferFromParentNotFound { .. }
385            | RoutingError::OfferFromSelfNotFound { .. }
386            | RoutingError::StorageFromParentNotFound { .. }
387            | RoutingError::OfferFromChildInstanceNotFound { .. }
388            | RoutingError::OfferFromCollectionNotFound { .. }
389            | RoutingError::OfferFromChildExposeNotFound { .. }
390            | RoutingError::CapabilityFromFrameworkNotFound { .. }
391            | RoutingError::CapabilityFromCapabilityNotFound { .. }
392            | RoutingError::CapabilityFromComponentManagerNotFound { .. }
393            | RoutingError::ExposeFromSelfNotFound { .. }
394            | RoutingError::ExposeFromChildInstanceNotFound { .. }
395            | RoutingError::ExposeFromCollectionNotFound { .. }
396            | RoutingError::ExposeFromChildExposeNotFound { .. }
397            | RoutingError::ExposeFromFrameworkNotFound { .. }
398            | RoutingError::UseFromChildExposeNotFound { .. }
399            | RoutingError::UseFromRootExposeNotFound { .. }
400            | RoutingError::UnsupportedRouteSource { .. }
401            | RoutingError::UnsupportedCapabilityType { .. }
402            | RoutingError::EventsRoutingError(_)
403            | RoutingError::BedrockNotPresentInDictionary { .. }
404            | RoutingError::BedrockSourceDictionaryExposeNotFound { .. }
405            | RoutingError::BedrockSourceDictionaryCollision { .. }
406            | RoutingError::BedrockFailedToSend { .. }
407            | RoutingError::RouteSourceShutdown { .. }
408            | RoutingError::BedrockMissingCapabilityType { .. }
409            | RoutingError::BedrockWrongCapabilityType { .. }
410            | RoutingError::BedrockRemoteCapability { .. }
411            | RoutingError::BedrockNotCloneable { .. }
412            | RoutingError::AvailabilityRoutingError(_)
413            | RoutingError::PathTooLong { .. } => zx::Status::NOT_FOUND,
414            RoutingError::BedrockMemberAccessUnsupported { .. }
415            | RoutingError::NonDebugRoutesUnsupported { .. }
416            | RoutingError::DebugRoutesUnsupported { .. }
417            | RoutingError::DictionariesNotSupported { .. } => zx::Status::NOT_SUPPORTED,
418            RoutingError::ComponentInstanceError(err) => err.as_zx_status(),
419            RoutingError::RightsRoutingError(err) => err.as_zx_status(),
420            RoutingError::PolicyError(err) => err.as_zx_status(),
421            RoutingError::SourceCapabilityIsVoid { .. } => zx::Status::NOT_FOUND,
422            RoutingError::RouteUnexpectedDebug { .. }
423            | RoutingError::RouteUnexpectedUnavailable { .. }
424            | RoutingError::MissingPorcelainType { .. } => zx::Status::INTERNAL,
425        }
426    }
427}
428
429impl From<RoutingError> for ExtendedMoniker {
430    fn from(err: RoutingError) -> ExtendedMoniker {
431        match err {
432            RoutingError::BedrockRemoteCapability { moniker, .. }
433            | RoutingError::BedrockSourceDictionaryExposeNotFound { moniker, .. }
434            | RoutingError::CapabilityFromCapabilityNotFound { moniker, .. }
435            | RoutingError::CapabilityFromFrameworkNotFound { moniker, .. }
436            | RoutingError::ComponentNotInIdIndex { source_moniker: moniker, .. }
437            | RoutingError::DictionariesNotSupported { moniker, .. }
438            | RoutingError::EnvironmentFromChildExposeNotFound { moniker, .. }
439            | RoutingError::EnvironmentFromChildInstanceNotFound { moniker, .. }
440            | RoutingError::EnvironmentFromParentNotFound { moniker, .. }
441            | RoutingError::ExposeFromChildExposeNotFound { moniker, .. }
442            | RoutingError::ExposeFromChildInstanceNotFound { moniker, .. }
443            | RoutingError::ExposeFromCollectionNotFound { moniker, .. }
444            | RoutingError::ExposeFromFrameworkNotFound { moniker, .. }
445            | RoutingError::ExposeFromSelfNotFound { moniker, .. }
446            | RoutingError::OfferFromChildExposeNotFound { moniker, .. }
447            | RoutingError::OfferFromChildInstanceNotFound { moniker, .. }
448            | RoutingError::OfferFromCollectionNotFound { moniker, .. }
449            | RoutingError::OfferFromParentNotFound { moniker, .. }
450            | RoutingError::OfferFromSelfNotFound { moniker, .. }
451            | RoutingError::SourceCapabilityIsVoid { moniker, .. }
452            | RoutingError::StorageFromChildExposeNotFound { moniker, .. }
453            | RoutingError::StorageFromParentNotFound { moniker, .. }
454            | RoutingError::UseFromChildExposeNotFound { moniker, .. }
455            | RoutingError::UseFromChildInstanceNotFound { moniker, .. }
456            | RoutingError::UseFromEnvironmentNotFound { moniker, .. }
457            | RoutingError::UseFromParentNotFound { moniker, .. }
458            | RoutingError::UseFromRootEnvironmentNotAllowed { moniker, .. }
459            | RoutingError::DynamicDictionariesNotAllowed { moniker, .. }
460            | RoutingError::RouteSourceShutdown { moniker }
461            | RoutingError::UseFromSelfNotFound { moniker, .. }
462            | RoutingError::MissingPorcelainType { moniker, .. } => moniker.into(),
463            RoutingError::PathTooLong { moniker, .. } => moniker,
464
465            RoutingError::BedrockMemberAccessUnsupported { moniker }
466            | RoutingError::BedrockNotPresentInDictionary { moniker, .. }
467            | RoutingError::BedrockNotCloneable { moniker }
468            | RoutingError::BedrockSourceDictionaryCollision { moniker }
469            | RoutingError::BedrockFailedToSend { moniker, .. }
470            | RoutingError::BedrockMissingCapabilityType { moniker, .. }
471            | RoutingError::BedrockWrongCapabilityType { moniker, .. }
472            | RoutingError::NonDebugRoutesUnsupported { moniker }
473            | RoutingError::DebugRoutesUnsupported { moniker }
474            | RoutingError::RouteUnexpectedDebug { moniker, .. }
475            | RoutingError::RouteUnexpectedUnavailable { moniker, .. }
476            | RoutingError::UnsupportedCapabilityType { moniker, .. }
477            | RoutingError::UnsupportedRouteSource { moniker, .. } => moniker,
478            RoutingError::AvailabilityRoutingError(err) => err.into(),
479            RoutingError::ComponentInstanceError(err) => err.into(),
480            RoutingError::EventsRoutingError(err) => err.into(),
481            RoutingError::PolicyError(err) => err.into(),
482            RoutingError::RightsRoutingError(err) => err.into(),
483
484            RoutingError::CapabilityFromComponentManagerNotFound { .. }
485            | RoutingError::OfferFromComponentManagerNotFound { .. }
486            | RoutingError::RegisterFromComponentManagerNotFound { .. }
487            | RoutingError::UseFromComponentManagerNotFound { .. }
488            | RoutingError::UseFromRootExposeNotFound { .. } => ExtendedMoniker::ComponentManager,
489        }
490    }
491}
492
493impl From<RoutingError> for RouterError {
494    fn from(value: RoutingError) -> Self {
495        Self::NotFound(Arc::new(value))
496    }
497}
498
499impl From<RouterError> for RoutingError {
500    fn from(value: RouterError) -> Self {
501        match value {
502            RouterError::NotFound(arc_dyn_explain) => {
503                arc_dyn_explain.downcast_for_test::<Self>().clone()
504            }
505            err => panic!("Cannot downcast {err} to RoutingError!"),
506        }
507    }
508}
509
510impl RoutingError {
511    /// Convert this error into its approximate `fuchsia.component.Error` equivalent.
512    pub fn as_fidl_error(&self) -> fcomponent::Error {
513        fcomponent::Error::ResourceUnavailable
514    }
515
516    pub fn storage_from_child_expose_not_found(
517        child_moniker: &ChildName,
518        moniker: &Moniker,
519        capability_id: impl Into<String>,
520    ) -> Self {
521        Self::StorageFromChildExposeNotFound {
522            child_moniker: child_moniker.clone(),
523            moniker: moniker.clone(),
524            capability_id: capability_id.into(),
525        }
526    }
527
528    pub fn use_from_component_manager_not_found(capability_id: impl Into<String>) -> Self {
529        Self::UseFromComponentManagerNotFound { capability_id: capability_id.into() }
530    }
531
532    pub fn register_from_component_manager_not_found(capability_id: impl Into<String>) -> Self {
533        Self::RegisterFromComponentManagerNotFound { capability_id: capability_id.into() }
534    }
535
536    pub fn offer_from_component_manager_not_found(capability_id: impl Into<String>) -> Self {
537        Self::OfferFromComponentManagerNotFound { capability_id: capability_id.into() }
538    }
539
540    pub fn use_from_parent_not_found(moniker: &Moniker, capability_id: impl Into<String>) -> Self {
541        Self::UseFromParentNotFound {
542            moniker: moniker.clone(),
543            capability_id: capability_id.into(),
544        }
545    }
546
547    pub fn use_from_self_not_found(moniker: &Moniker, capability_id: impl Into<String>) -> Self {
548        Self::UseFromSelfNotFound { moniker: moniker.clone(), capability_id: capability_id.into() }
549    }
550
551    pub fn use_from_child_instance_not_found(
552        child_moniker: &ChildName,
553        moniker: &Moniker,
554        capability_id: impl Into<String>,
555    ) -> Self {
556        Self::UseFromChildInstanceNotFound {
557            child_moniker: child_moniker.clone(),
558            moniker: moniker.clone(),
559            capability_id: capability_id.into(),
560        }
561    }
562
563    pub fn use_from_environment_not_found(
564        moniker: &Moniker,
565        capability_type: impl Into<String>,
566        capability_name: &Name,
567    ) -> Self {
568        Self::UseFromEnvironmentNotFound {
569            moniker: moniker.clone(),
570            capability_type: capability_type.into(),
571            capability_name: capability_name.clone(),
572        }
573    }
574
575    pub fn offer_from_parent_not_found(
576        moniker: &Moniker,
577        capability_id: impl Into<String>,
578    ) -> Self {
579        Self::OfferFromParentNotFound {
580            moniker: moniker.clone(),
581            capability_id: capability_id.into(),
582        }
583    }
584
585    pub fn offer_from_self_not_found(moniker: &Moniker, capability_id: impl Into<String>) -> Self {
586        Self::OfferFromSelfNotFound {
587            moniker: moniker.clone(),
588            capability_id: capability_id.into(),
589        }
590    }
591
592    pub fn storage_from_parent_not_found(
593        moniker: &Moniker,
594        capability_id: impl Into<String>,
595    ) -> Self {
596        Self::StorageFromParentNotFound {
597            moniker: moniker.clone(),
598            capability_id: capability_id.into(),
599        }
600    }
601
602    pub fn offer_from_child_instance_not_found(
603        child_moniker: &ChildName,
604        moniker: &Moniker,
605        capability_id: impl Into<String>,
606    ) -> Self {
607        Self::OfferFromChildInstanceNotFound {
608            child_moniker: child_moniker.clone(),
609            moniker: moniker.clone(),
610            capability_id: capability_id.into(),
611        }
612    }
613
614    pub fn offer_from_child_expose_not_found(
615        child_moniker: &ChildName,
616        moniker: &Moniker,
617        capability_id: impl Into<String>,
618    ) -> Self {
619        Self::OfferFromChildExposeNotFound {
620            child_moniker: child_moniker.clone(),
621            moniker: moniker.clone(),
622            capability_id: capability_id.into(),
623        }
624    }
625
626    pub fn use_from_child_expose_not_found(
627        child_moniker: &ChildName,
628        moniker: &Moniker,
629        capability_id: impl Into<String>,
630    ) -> Self {
631        Self::UseFromChildExposeNotFound {
632            child_moniker: child_moniker.clone(),
633            moniker: moniker.clone(),
634            capability_id: capability_id.into(),
635        }
636    }
637
638    pub fn expose_from_self_not_found(moniker: &Moniker, capability_id: impl Into<String>) -> Self {
639        Self::ExposeFromSelfNotFound {
640            moniker: moniker.clone(),
641            capability_id: capability_id.into(),
642        }
643    }
644
645    pub fn expose_from_child_instance_not_found(
646        child_moniker: &ChildName,
647        moniker: &Moniker,
648        capability_id: impl Into<String>,
649    ) -> Self {
650        Self::ExposeFromChildInstanceNotFound {
651            child_moniker: child_moniker.clone(),
652            moniker: moniker.clone(),
653            capability_id: capability_id.into(),
654        }
655    }
656
657    pub fn expose_from_child_expose_not_found(
658        child_moniker: &ChildName,
659        moniker: &Moniker,
660        capability_id: impl Into<String>,
661    ) -> Self {
662        Self::ExposeFromChildExposeNotFound {
663            child_moniker: child_moniker.clone(),
664            moniker: moniker.clone(),
665            capability_id: capability_id.into(),
666        }
667    }
668
669    pub fn capability_from_framework_not_found(
670        moniker: &Moniker,
671        capability_id: impl Into<String>,
672    ) -> Self {
673        Self::CapabilityFromFrameworkNotFound {
674            moniker: moniker.clone(),
675            capability_id: capability_id.into(),
676        }
677    }
678
679    pub fn capability_from_capability_not_found(
680        moniker: &Moniker,
681        capability_id: impl Into<String>,
682    ) -> Self {
683        Self::CapabilityFromCapabilityNotFound {
684            moniker: moniker.clone(),
685            capability_id: capability_id.into(),
686        }
687    }
688
689    pub fn capability_from_component_manager_not_found(capability_id: impl Into<String>) -> Self {
690        Self::CapabilityFromComponentManagerNotFound { capability_id: capability_id.into() }
691    }
692
693    pub fn expose_from_framework_not_found(
694        moniker: &Moniker,
695        capability_id: impl Into<String>,
696    ) -> Self {
697        Self::ExposeFromFrameworkNotFound {
698            moniker: moniker.clone(),
699            capability_id: capability_id.into(),
700        }
701    }
702
703    pub fn unsupported_route_source(
704        moniker: impl Into<ExtendedMoniker>,
705        source: impl Into<String>,
706    ) -> Self {
707        Self::UnsupportedRouteSource { source_type: source.into(), moniker: moniker.into() }
708    }
709
710    pub fn unsupported_capability_type(
711        moniker: impl Into<ExtendedMoniker>,
712        type_name: impl Into<CapabilityTypeName>,
713    ) -> Self {
714        Self::UnsupportedCapabilityType { type_name: type_name.into(), moniker: moniker.into() }
715    }
716}
717
718/// Errors produced during routing specific to events.
719#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
720#[derive(Error, Debug, Clone, PartialEq)]
721pub enum EventsRoutingError {
722    #[error("filter is not a subset at `{moniker}`")]
723    InvalidFilter { moniker: ExtendedMoniker },
724
725    #[error("event routes must end at source with a filter declaration at `{moniker}`")]
726    MissingFilter { moniker: ExtendedMoniker },
727}
728
729impl From<EventsRoutingError> for ExtendedMoniker {
730    fn from(err: EventsRoutingError) -> ExtendedMoniker {
731        match err {
732            EventsRoutingError::InvalidFilter { moniker }
733            | EventsRoutingError::MissingFilter { moniker } => moniker,
734        }
735    }
736}
737
738#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
739#[derive(Debug, Error, Clone, PartialEq)]
740pub enum RightsRoutingError {
741    #[error(
742        "requested rights ({requested}) greater than provided rights ({provided}) at \"{moniker}\""
743    )]
744    Invalid { moniker: ExtendedMoniker, requested: Rights, provided: Rights },
745
746    #[error(
747        "directory routes must end at source with a rights declaration, it's missing at \"{moniker}\""
748    )]
749    MissingRightsSource { moniker: ExtendedMoniker },
750}
751
752impl RightsRoutingError {
753    /// Convert this error into its approximate `zx::Status` equivalent.
754    pub fn as_zx_status(&self) -> zx::Status {
755        match self {
756            RightsRoutingError::Invalid { .. } => zx::Status::ACCESS_DENIED,
757            RightsRoutingError::MissingRightsSource { .. } => zx::Status::NOT_FOUND,
758        }
759    }
760}
761
762impl From<RightsRoutingError> for ExtendedMoniker {
763    fn from(err: RightsRoutingError) -> ExtendedMoniker {
764        match err {
765            RightsRoutingError::Invalid { moniker, .. }
766            | RightsRoutingError::MissingRightsSource { moniker } => moniker,
767        }
768    }
769}
770
771#[cfg_attr(feature = "serde", derive(Deserialize, Serialize), serde(rename_all = "snake_case"))]
772#[derive(Debug, Error, Clone, PartialEq)]
773pub enum AvailabilityRoutingError {
774    #[error(
775        "availability requested by the target has stronger guarantees than what \
776    is being provided at the source at `{moniker}`"
777    )]
778    TargetHasStrongerAvailability { moniker: ExtendedMoniker },
779
780    #[error("offer uses void source, but target requires the capability at `{moniker}`")]
781    OfferFromVoidToRequiredTarget { moniker: ExtendedMoniker },
782
783    #[error("expose uses void source, but target requires the capability at `{moniker}`")]
784    ExposeFromVoidToRequiredTarget { moniker: ExtendedMoniker },
785}
786
787impl From<availability::TargetHasStrongerAvailability> for AvailabilityRoutingError {
788    fn from(value: availability::TargetHasStrongerAvailability) -> Self {
789        let availability::TargetHasStrongerAvailability { moniker } = value;
790        AvailabilityRoutingError::TargetHasStrongerAvailability { moniker }
791    }
792}
793
794impl From<AvailabilityRoutingError> for ExtendedMoniker {
795    fn from(err: AvailabilityRoutingError) -> ExtendedMoniker {
796        match err {
797            AvailabilityRoutingError::ExposeFromVoidToRequiredTarget { moniker }
798            | AvailabilityRoutingError::OfferFromVoidToRequiredTarget { moniker }
799            | AvailabilityRoutingError::TargetHasStrongerAvailability { moniker } => moniker,
800        }
801    }
802}
803
804// Implements error reporting upon routing failure. For example, component
805// manager logs the error.
806#[async_trait]
807pub trait ErrorReporter: Clone + Send + Sync + 'static {
808    async fn report(
809        &self,
810        request: &RouteRequestErrorInfo,
811        err: &RouterError,
812        route_target: sandbox::WeakInstanceToken,
813    );
814}
815
816/// What to print in an error if a route request fails.
817pub struct RouteRequestErrorInfo {
818    capability_type: cm_rust::CapabilityTypeName,
819    name: cm_types::Name,
820    availability: cm_rust::Availability,
821}
822
823impl RouteRequestErrorInfo {
824    pub fn availability(&self) -> cm_rust::Availability {
825        self.availability
826    }
827
828    pub fn for_builtin(capability_type: CapabilityTypeName, name: &Name) -> Self {
829        Self { capability_type, name: name.clone(), availability: Availability::Required }
830    }
831}
832
833impl From<&cm_rust::UseDecl> for RouteRequestErrorInfo {
834    fn from(value: &cm_rust::UseDecl) -> Self {
835        RouteRequestErrorInfo {
836            capability_type: value.into(),
837            name: value.source_name().clone(),
838            availability: value.availability().clone(),
839        }
840    }
841}
842
843impl From<&cm_rust::UseConfigurationDecl> for RouteRequestErrorInfo {
844    fn from(value: &cm_rust::UseConfigurationDecl) -> Self {
845        RouteRequestErrorInfo {
846            capability_type: CapabilityTypeName::Config,
847            name: value.source_name().clone(),
848            availability: value.availability().clone(),
849        }
850    }
851}
852
853impl From<&cm_rust::UseEventStreamDecl> for RouteRequestErrorInfo {
854    fn from(value: &cm_rust::UseEventStreamDecl) -> Self {
855        RouteRequestErrorInfo {
856            capability_type: CapabilityTypeName::EventStream,
857            name: value.source_name.clone(),
858            availability: value.availability,
859        }
860    }
861}
862
863impl From<&cm_rust::ExposeDecl> for RouteRequestErrorInfo {
864    fn from(value: &cm_rust::ExposeDecl) -> Self {
865        RouteRequestErrorInfo {
866            capability_type: value.into(),
867            name: value.target_name().clone(),
868            availability: value.availability().clone(),
869        }
870    }
871}
872
873impl From<&cm_rust::OfferDecl> for RouteRequestErrorInfo {
874    fn from(value: &cm_rust::OfferDecl) -> Self {
875        RouteRequestErrorInfo {
876            capability_type: value.into(),
877            name: value.target_name().clone(),
878            availability: value.availability().clone(),
879        }
880    }
881}
882
883impl From<&cm_rust::ResolverRegistration> for RouteRequestErrorInfo {
884    fn from(value: &cm_rust::ResolverRegistration) -> Self {
885        RouteRequestErrorInfo {
886            capability_type: CapabilityTypeName::Resolver,
887            name: value.source_name().clone(),
888            availability: Availability::Required,
889        }
890    }
891}
892
893impl From<&cm_rust::RunnerRegistration> for RouteRequestErrorInfo {
894    fn from(value: &cm_rust::RunnerRegistration) -> Self {
895        RouteRequestErrorInfo {
896            capability_type: CapabilityTypeName::Runner,
897            name: value.source_name().clone(),
898            availability: Availability::Required,
899        }
900    }
901}
902
903impl From<&cm_rust::DebugRegistration> for RouteRequestErrorInfo {
904    fn from(value: &cm_rust::DebugRegistration) -> Self {
905        RouteRequestErrorInfo {
906            capability_type: CapabilityTypeName::Protocol,
907            name: value.source_name().clone(),
908            availability: Availability::Required,
909        }
910    }
911}
912
913impl From<&cm_rust::CapabilityDecl> for RouteRequestErrorInfo {
914    fn from(value: &cm_rust::CapabilityDecl) -> Self {
915        RouteRequestErrorInfo {
916            capability_type: value.into(),
917            name: value.name().clone(),
918            availability: Availability::Required,
919        }
920    }
921}
922
923impl std::fmt::Display for RouteRequestErrorInfo {
924    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
925        write!(f, "{} `{}`", self.capability_type, self.name)
926    }
927}