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