Skip to main content

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