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