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