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