blob: 180e350e2799144b39b1b8bee6a694ea956618db [file] [log] [blame] [view]
# Connect components
This document demonstrates how to connect components together using capabilities
and additional tools for parent components to manage their children.
## Concepts
You should understand the following concepts before continuing with this guide:
* The Component Framework assembles the
[namespace][glossary.namespace] for a component using
[component declarations][glossary.component-declaration] that describe the
[capabilities][glossary.capability] the component requires to function.
The capabilities the component exposes to others are assembled into an
[exposed directory][glossary.exposed-directory].
* Every component receives a handle to the server end of a
[`Directory`][fidl-fuchsia.io.Directory] channel called the
[outgoing directory][glossary.outgoing-directory].
The component's executable makes discoverable any capabilities that it provides
through this directory.
* At runtime, the
[component instance tree][glossary.component-instance-tree] connects individual
[component instances][glossary.component-instance] together in a hierarchy of
parent and child relationships. The component instance tree and the capability
routes over that tree are collectively referred to as the
[component topology][glossary.component-topology].
* Parent components declare child components either statically in their
[component manifest][glossary.component-manifest] or dynamically using a
[component collection][glossary.component-collection]. A collection is a container
for dynamic children that may be created and destroyed at runtime using the
`fuchsia.component.Realm` framework protocol.
For more details on these concepts, see [Realms][doc-realms] and
[Capabilities][doc-capabilities].
## Connecting capabilities {#capabilities}
Note: For a complete example using routed capabilities, see
[`//examples/components/routing`][example-routing].
Components interact with each other through their capabilities. Capabilities implemented
in a component need to be declared in that component's manifest and routed through its
parent/child components. Other components that use that capability also need to declare
their use in their manifests. This capability routing describes which component should act
as the provider for any given client. Once the proper components are identified, the
component manager initiates connections between components.
### Provide a capability implementation {#provide-capability}
Components that implement a capability must declare the implementation in their
component manifest using a [`capabilities`][cml-capabilities] declaration.
See the following example that declares a FIDL [protocol capability][doc-protocol] in the
providing component's manifest:
```json5
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/rust/echo_server/meta/echo_server.cml" region_tag="example_snippet" adjust_indentation="auto" highlight="16,17,18,19" %}
```
At runtime, the provider component provides an implementation of the capability by serving
it through the outgoing directory using the [fuchsia.io][fidl-fuchsia.io] protocol.
The generated FIDL bindings wrap this handle and enable the provider to begin receiving
incoming requests:
* {Rust}
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/rust/echo_server/src/main.rs" region_tag="main_body" adjust_indentation="auto" highlight="1,2,3,4,8,14,15,16,21,22,23,24,25,26,27,28" %}
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/rust/echo_server/src/main.rs" region_tag="handler" adjust_indentation="auto" highlight="1,2,3,4,5,6,7" %}
```
* {C++}
```cpp
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/cpp/echo_server/main.cc" region_tag="handler" adjust_indentation="auto" highlight="1,2,3,4,5,6" %}
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/cpp/echo_server/main.cc" region_tag="main_body" adjust_indentation="auto" highlight="3,9,10,11,12,13,14,15,16,17" %}
```
### Connect to routed capabilities {#connect-routes}
Client components request capabilities in their component manifest with a [`use`][cml-use]
declaration.
See the following example of a client component's manifest that uses the FIDL protocol provided
by the previous component:
```json5
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/rust/echo_client/meta/echo_client.cml" region_tag="example_snippet" adjust_indentation="auto" highlight="19,20,21,22" %}
```
At runtime, the client component connects to the capability handles populated in its namespace
using the [fuchsia.io][fidl-fuchsia.io] protocol. The Fuchsia component library works
with the generated FIDL bindings to wrap these handles and provide a structured interface
for communicating over the channel:
* {Rust}
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/rust/echo_client/src/main.rs" region_tag="main_body" adjust_indentation="auto" highlight="7,8,9,10,11,12,13,14" %}
```
* {C++}
```cpp
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/cpp/echo_client/main.cc" region_tag="main_body" adjust_indentation="auto" highlight="2,3,4,5,7,8,10" %}
```
#### Mark some used capabilities as optional {#optional-use}
Not all capabilities used by a component are required for it to operate
successfully. Sometimes a component can still execute without issue if a
capability is missing, and its presence will merely enable some additional or
alternative behavior.
To enable the component framework to understand which capabilities a component
requires and which capabilities are optional for a component, use the
`availability` field.
```
use: [
{
// It is ok if this protocol is unavailable
protocol: "fuchsia.examples.Echo1",
availability: "optional",
},
{
// This protocol MUST be provided for the component to function correctly.
protocol: "fuchsia.examples.Echo2",
availability: "required",
},
]
```
If a component has a `required` use declaration for a capability but its parent
offers the capability as `optional`, then the [static capability
analyzer][static-analyzer] will generate an error and connection attempts at
runtime will always fail.
##### Consuming optional capabilities {#consuming-optional-capabilities}
In the case that a component's parent has `offer`ed a capabilitity
with `availability: "optional"`, the capability may not be usable at runtime.
An entry in the component's [namespace][glossary.namespace] will be present
whether the capability is available or not. Any attempt to open the path for
that capability will result in the handle provided to the `Directory.Open()`
call being closed with a `ZX_ERR_UNAVAILABLE` epitaph.
Usage of `libc` methods like `open()` or `stat()` will return `ENOENT`.
### Route capabilities {#route-capability}
Components may only access capabilities routed to them. Capabilities can originate
from anywhere in the component topology as long as a valid capability route exists
as a chain of the following declarations from the capability provider to any
consumers:
* [`expose`][cml-expose]: Routes a capability up to the component's parent.
* [`offer`][cml-offer]: Routes a capability down to one of the component's children.
To connect capability providers with components requesting those capabilities,
do the following:
1. Add an `offer` or `expose` declaration to the capability provider component:
```json5
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/rust/echo_server/meta/echo_server.cml" region_tag="example_snippet" adjust_indentation="auto" highlight="20,21,22,23,24,25" %}
```
1. For each intermediate component in the component instance tree, include additional
`expose` and `offer` declarations until you reach the consuming component containing
a `use` declaration:
```json5
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/routing/meta/echo_realm.cml" region_tag="example_snippet" highlight="13,14,15,16,17,18,19,21,22,23,24,25,26,27,28,29,30" %}
```
#### Optional dependencies {#optional-offer}
When a component has an optional dependency on a capability, it is then up to
that component's parent to decide if the component will receive that capability
or not. When offering a capability, a component may set the `availability` field
to either `optional`, `required`, or `same_as_target`. Each value has the
following semantics:
- `optional`: The target of the offer must declare it's ability to handle the
absence of this capability by marking it's `use` declaration as `optional`. If
the target cannot do this, (i.e. the target has an availability of `required`
for this capability), then routing the capability will cause an error.
- `required`: The target must receive this capability. If the offer source is
`parent` and the component's parent (the target's grandparent) offered this as
an optional capability, then routing the capability will cause an error
because the parent cannot guarantee the capability's availability.
- `same_as_target`: The availability of this capability is determined by the
target's expectations. If the target has an optional dependency on this
capability, then this offer will also be optional. If the target has a
required dependency on this capability, then this offer will also be required.
```
offer: [
{
// child-1 MUST receive the protocol 'fuchsia.logger.LogSink'.
protocol: "fuchsia.logger.LogSink",
to: "#child-1",
from: "#child-2",
availability: "required",
},
{
// child-1 MUST be able to handle the absence of the protocol
// 'fuchsia.tracing.provider.Registry'.
protocol: "fuchsia.tracing.provider.Registry",
to: "#child-1",
from: "parent",
availability: "optional",
},
{
// child-1 decides if it must receive the protocol
// 'fuchsia.posix.socket.Provider', or if it must be able to support its
// absence.
protocol: "fuchsia.posix.socket.Provider",
to: "#child-1",
from: "parent",
availability: "same_as_target",
},
]
```
Like with use declarations, the `availability` field may be omitted, in which
case it defaults to `required`.
#### Transitionally dependencies {#transitional-offer}
The component framework allows components to soft-transition into using and offering
both optional and required capabilities. With the transitional availability marker, a
component using a capability, will not cause Scrutiny validation errors whether or
not the parent is required, optional, or same as target. Note, though this field exists
to enable soft-transitions, components should ultimately settle on either optional or required.
To use this feature, the child component will mark its availability as "transitional":
```
use: [
{
// It is ok if this protocol is offered as "required" or "optional"
protocol: "fuchsia.examples.Echo",
availability: "transitional",
},
```
## Managing child components {#children}
Note: For a complete example using child components, see
[`//examples/components/lifecycle`][example-lifecycle].
Components can interact with each other from anywhere in the component topology through
capabilities as long as a valid capability route exists between them. There are additional
methods that enable parent components to interact with their direct children.
The following example component declares a single static child named `lifecycle` and
a collection named `echo` where additional child components may be created at runtime:
```json5
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/meta/manager.cml" region_tag="example_snippet" adjust_indentation="auto" %}
```
Notice that a collection behaves like a static child instance in the parent component's
manifest — you can give it a name and offer specific capabilities to it. All child
components in the collection may access the set of capabilities offered to it.
### Start child components {#start-child}
The Component Framework provides the [`fuchsia.component.Binder`][fidl-Binder] protocol
for parent components to explicitly start a child that may not expose any other capabilities.
Since this capability is provided by the framework, child components only need to expose it
from their component manifest:
```json5
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/meta/lifecycle.cml" region_tag="example_snippet" adjust_indentation="auto" %}
```
### Create dynamic children {#create-child}
To create a new child component at runtime, use the [`fuchsia.component.Realm`][fidl-Realm]
protocol to create the component inside of an existing collection. Call the
[`CreateChild`][fidl-Realm.CreateChild] method with the following parameters:
* [`CollectionRef`][fidl-decl.CollectionRef]: Describes the collection where the component
will be added.
* [`Child`][fidl-decl.Child]: Component declaration, including its name and component URL.
* {Rust}
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/manager.rs" region_tag="imports" adjust_indentation="auto" %}
// ...
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/manager.rs" region_tag="create_child" adjust_indentation="auto" %}
```
* {C++}
```cpp
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/manager.cc" region_tag="imports" adjust_indentation="auto" %}
// ...
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/manager.cc" region_tag="create_child" adjust_indentation="auto" %}
```
### Connect to child capabilities {#connect-child}
Because the parent of a dynamic component is not known at build time, its exposed capabilities
cannot be named in capability routes expressed in the component manifest.
To connect with the capabilities exposed by a dynamic child instance:
1. Use the [`fuchsia.component.Realm`][fidl-Realm] protocol to open the child's
exposed directory. Call the [`OpenExposedDir`][fidl-Realm.OpenExposedDir]
method with the child component's name and the collection name:
* {Rust}
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/manager.rs" region_tag="imports" adjust_indentation="auto" %}
// ...
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/manager.rs" region_tag="connect_child" adjust_indentation="auto" %}
```
* {C++}
```cpp
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/manager.cc" region_tag="imports" adjust_indentation="auto" %}
// ...
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/manager.cc" region_tag="connect_child" adjust_indentation="auto" %}
```
2. Connect to the child's exposed capabilities using the exposed directory handle
as the root:
* {Rust}
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/manager.rs" region_tag="echo_send" adjust_indentation="auto" %}
```
* {C++}
```cpp
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/manager.cc" region_tag="echo_send" adjust_indentation="auto" %}
```
### Destroy dynamic children {#destroy-child}
When the dynamic child is no longer needed, use the [`fuchsia.component.Realm`][fidl-Realm]
protocol to destroy the component instance. Call the [`DestroyChild`][fidl-Realm.DestroyChild]
method with a [`ChildRef`][fidl-decl.ChildRef] representing the child inside the collection.
* {Rust}
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/manager.rs" region_tag="imports" adjust_indentation="auto" %}
// ...
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/manager.rs" region_tag="destroy_child" adjust_indentation="auto" %}
```
* {C++}
```cpp
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/manager.cc" region_tag="imports" adjust_indentation="auto" %}
// ...
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/manager.cc" region_tag="destroy_child" adjust_indentation="auto" %}
```
This causes the component to stop if it is currently running. To handle this event in
your component, see [listen for stop events](#lifecycle-notifications).
## Controlling component lifecycle {#lifecycle}
The Component Framework provides features to modify and interact with various parts of
the component lifecycle.
For more details on lifecycle concepts, see [Component lifecycle][doc-lifecycle].
### Lifecycle notifications {#lifecycle-notifications}
The ELF runner notifies components of lifecycle events using the
[`fuchsia.process.lifecycle.Lifecycle`][fidl-Lifecycle] protocol.
To listen for stop notifications in your child component:
1. Subscribe to the [lifecycle event][elf-lifecycle] in your component manifest:
* {Rust}
```json5
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/meta/lifecycle.cml" region_tag="lifecycle_event" adjust_indentation="auto" highlight="9,10" %}
```
* {C++}
```json5
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/meta/lifecycle.cml" region_tag="lifecycle_event" adjust_indentation="auto" highlight="9,10" %}
```
1. Register a lifecycle handler using the startup handle provided by the runner:
* {Rust}
```rust
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/lifecycle.rs" region_tag="imports" adjust_indentation="auto" %}
// ...
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/rust/src/lifecycle.rs" region_tag="lifecycle_handler" adjust_indentation="auto" %}
```
* {C++}
```cpp
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/lifecycle.cc" region_tag="imports" adjust_indentation="auto" %}
// ...
{% includecode gerrit_repo="fuchsia/fuchsia" gerrit_path="examples/components/lifecycle/cpp/lifecycle.cc" region_tag="lifecycle_handler" adjust_indentation="auto" %}
```
### Start with parent {#eager}
[Component manifests][doc-manifests] let you mark a child as [`eager`][cml-children],
which causes the component framework to implicitly start that child with the parent.
If the eager child fails to start for any reason (such as a missing component),
component manager exhibits the following behavior:
- If the parent is not the root component, the parent will start but the
component that bound to it will observe a dropped connection (just like any
other failed binding).
- If the parent is the root component, component manager will crash, with an
error message like:
```none {:.devsite-disable-click-to-copy}
[component_manager] ERROR: Required protocol `fuchsia.appmgr.Startup` was not
available for target component `/startup`:
failed to resolve "fuchsia-pkg://fuchsia.com/your_component#meta/your_component.cm":
package not found: remote resolver responded with PackageNotFound
```
Components marked as `eager` can cause system crashes when they are not present if their
ancestors are also marked `eager` up to the root component. This is important because
many build configurations create system images containing a subset of the available components.
To avoid this problem, declare these components using [**core realm shards**][core-shard] to
ensure they can be safely excluded from test builds and product images.
An `eager` component should also be in the same [package set][doc-package-set] as its parent
since the component will be started at the same time as its parent. Typically, `eager`
components should be in the product's base package set.
To determine if your package is in the base package set, run the following command:
```posix-terminal
fx list-packages --verbose {{ '<var label="package name">my-package</var>' }}
```
This command outputs a list of the package sets where the matching package is found.
For example, `system-update-checker` is in the `base` and `universe` package sets:
```none {:.devsite-disable-click-to-copy}
$ fx list-packages --verbose system-update-checker
system-update-checker [base universe]
```
You can also look at all the packages in the base package set using the `--base` option:
```posix-terminal
fx list-packages --base
```
### Reboot on terminate {#reboot-on-terminate}
[Component manifests][doc-manifests] let you control the termination policy of your component
using [`on_terminate`][cml-children]. Components with the "reboot-on-terminate" policy set
cause the system to gracefully reboot if the component terminates for any reason (including
successful exit).
Note: This is a special feature intended for use only by system components deemed critical
to the system's function. Therefore, its use is governed by a security policy allowlist.
If you believe you need this option, please reach out to the
[Component Framework team][cf-dev-list].
To enable this feature, do the following:
1. Mark the child as `on_terminate: reboot` in the parent's component manifest:
```json5
// core.cml
{
children: [
...
{
name: "system-update-checker",
url: "fuchsia-pkg://fuchsia.com/system-update-checker#meta/system-update-checker.cm",
startup: "eager",
{{ '<strong>' }}on_terminate: "reboot",{{ '</strong>' }}
},
],
}
```
1. Add the component's moniker to component manager's security policy allowlist at
[`//src/security/policy/component_manager_policy.json5`][src-security-policy]:
```json5
// //src/security/policy/component_manager_policy.json5
{
security_policy: {
...
child_policy: {
reboot_on_terminate: [
...
"/core/system-update-checker",
],
},
},
}
```
## Troubleshooting {#troubleshooting}
This section contains common issues you may encounter trying to `use` and connect to
capabilities from your component.
When component connections fail, the underlying FIDL channel closes. FIDL protocol
bindings return an error status if the channel was closed. Consider the following example:
* {Rust}
```rust
let echo = connect_to_protocol::<EchoMarker>()
.context("Failed to connect to echo service")?;
let res = echo.echo_string(Some("Hippos rule!")).await;
match res {
Ok(_) => { info!("Call succeeded!"); }
{{ '<strong>' }}Err(fidl::Error::ClientChannelClosed { status, service_name } => { {{ '</strong>' }}
{{ '<strong>' }}error!("Channel to service {} was closed with status: {}", service_name, status); {{ '</strong>' }}
{{ '<strong>' }}} {{ '</strong>' }}
Err(e) => {
error!("Unexpected error: {}", e);
}
};
```
* {C++}
```cpp
fuchsia::examples::EchoPtr echo_proxy;
auto context = sys::ComponentContext::Create();
context->svc()->Connect(echo_proxy.NewRequest());
{{ '<strong>' }}// Sets an error handler that will be called if an error causes the underlying {{ '</strong>' }}
{{ '<strong>' }}// channel to be closed. {{ '</strong>' }}
{{ '<strong>' }}echo_proxy.set_error_handler([&loop](zx_status_t status) { {{ '</strong>' }}
{{ '<strong>' }}printf("Channel was closed with status: %d\n", status); {{ '</strong>' }}
{{ '<strong>' }}// ... {{ '</strong>' }}
{{ '<strong>' }}}); {{ '</strong>' }}
echo_proxy->EchoString("Hippos rule!", [&](std::string response) {
// ...
});
```
Note: If the protocol method doesn't return a value (such as a one-way method),
the error status is only set if the channel was closed prior to the method call.
To determine the underlying cause of a channel closure, you can inspect the optional
[epitaph][doc-epitaphs] set on the channel. To retrieve the epitaph on a closed channel,
do the following:
* {Rust}
```rust
let stream = echo.take_event_stream();
match stream.next().await {
Some(Err(fidl::Error::ClientChannelClosed { status, .. })) => {
info!("Channel was closed with epitaph: {}", status);
}
Some(m) => {
info!("Received message other than epitaph or peer closed: {:?}", m);
}
None => {
info!("Component failed to start or channel was closed by server");
}
}
```
* {C++}
```cpp
echo_proxy.set_error_handler([&loop](zx_status_t status) {
// If an Epitaph was present on the channel, its error value will be passed as
// the parameter.
printf("Channel was closed with epitaph: %d\n", status);
});
```
### Capability routing failed {#troubleshoot-use-routing}
Component manager performs [capability routing][doc-capabilities] to find the source
of a given capability once your component attempts to access the capability. Routing
can fail if one of the component manifests in the routing path is configured incorrectly.
For example, an `offer` or `expose` declaration is missing from some component in the path,
or one of the components in the chain could not be resolved.
Do the following to check if a routing failure was the cause of channel closure:
* Check the component logs with `ffx log` for a message beginning with `Failed to route`
that explains where the routing chain failed. For example:
```none {:.devsite-disable-click-to-copy}
[echo_client][][W] Required protocol
`fidl.examples.routing.echo.Echo` was not available for target component
`/core/ffx-laboratory:echo_realm/echo_client`:
A `use from parent` declaration was found at `/core/ffx-laboratory:echo_realm/echo_client`
for `fidl.examples.routing.echo.Echo`, but no matching `offer` declaration was found in the parent
```
* Check for an [epitaph on the closed channel](#troubleshooting).
Normally, the epitaph set for a routing failure is `ZX_ERR_UNAVAILABLE`:
```none {:.devsite-disable-click-to-copy}
[echo_client][][I] Connecting to Echo protocol failed with error
"A FIDL client's channel to the service fidl.examples.routing.echo.Echo was closed: UNAVAILABLE"
```
For a self-contained example of failed capability routing, see
[`//examples/components/routing_failed`][example-routing-failed].
### Component failed to start {#troubleshoot-use-start}
You may encounter an error if capability routing was successful, but an issue occurred
resolving or starting the component. The form of the error message depends on the
[component runner][doc-runners]:
* For the ELF runner, check the component manager logs with
`ffx log --filter component_manager`. Look for a message starting with
`Failed to start component`. For example:
```none {:.devsite-disable-click-to-copy}
[component_manager] WARN: Failed to start component
`fuchsia-pkg://fuchsia.com/components-routing-failed-example#meta/echo_server_bad.cm`:
unable to load component with url "fuchsia-pkg://fuchsia.com/components-routing-failed-example#meta/echo_server_bad.cm":
error loading executable: "reading object at \"bin/routing_failed_echo_server_oops\" failed:
A FIDL client's channel to the service (anonymous) File was closed: PEER_CLOSED"
```
* For other runners, check the [logs][doc-logs] of the runner component. You
can do this by running the following command:
```posix-terminal
ffx log --tags {{ '<var label="component runner">runner-name</var>' }}
```
To address the issue, verify the following:
* The [`program`][cml-program] declaration in your component manifest is configured properly.
For example, verify that the binary's path is spelled correctly.
* The binary itself and all other resource needed to start the component are included in the
[package][doc-packages].
For an example of a component that failed to start due to a misconfigured
component manifest, see [`//examples/components/routing_failed`][example-routing-failed].
### Component terminated or closed the channel {#troubleshoot-use-terminated}
If you have verified that routing succeeded and the component started successfully,
you may be experiencing an issue where the source component closed the channel itself.
This can happen while the component was running, or can be a side effect of the
component terminating.
If the component terminated because it crashed, you can look for a crash report
in `ffx log` that contains the component name in the dump:
```none {:.devsite-disable-click-to-copy}
[33860.645][klog][klog][I] crashsvc: exception received, processing
[33860.645][klog][klog][I] <== fatal : process echo_client.cm[21090] thread initial-thread[21092]
<stack trace follows...>
```
If the source component closed the channel itself, here are some tips to further troubleshoot
the cause:
* Refer to the source component's [logs][doc-logs] for error messages.
* Use `ffx debug fidl` to examine the FIDL connection traffic with
[`fidlcat`][doc-fidlcat] for errors or unexpected behavior.
[cf-dev-list]: https://groups.google.com/a/fuchsia.dev/g/component-framework-dev
[core-shard]: /src/sys/core/README.md
[cml-capabilities]: https://fuchsia.dev/reference/cml#capabilities
[cml-children]: https://fuchsia.dev/reference/cml#children
[cml-expose]: https://fuchsia.dev/reference/cml#expose
[cml-offer]: https://fuchsia.dev/reference/cml#offer
[cml-program]: https://fuchsia.dev/reference/cml#program
[cml-use]: https://fuchsia.dev/reference/cml#use
[doc-capabilities]: /docs/concepts/components/v2/capabilities/README.md
[doc-epitaphs]: /docs/reference/fidl/language/wire-format/README.md#epitaph_control_message_ordinal_0xffffffff
[doc-fidlcat]: /docs/development/monitoring/fidlcat/README.md
[doc-lifecycle]: /docs/concepts/components/v2/lifecycle.md
[doc-logs]: /docs/concepts/components/diagnostics/logs/README.md
[doc-manifests]: /docs/concepts/components/v2/component_manifests.md
[doc-packages]: /docs/concepts/packages/package.md
[doc-package-set]: /docs/concepts/packages/package.md#types_of_packages
[doc-protocol]: /docs/concepts/components/v2/capabilities/protocol.md
[doc-realms]: /docs/concepts/components/v2/realms.md
[doc-runners]: /docs/concepts/components/v2/capabilities/runners.md
[elf-lifecycle]: /docs/concepts/components/v2/elf_runner.md#lifecycle
[example-lifecycle]: /examples/components/lifecycle/
[example-routing]: /examples/components/routing/
[example-routing-failed]: /examples/components/routing_failed/
[fidl-Binder]: https://fuchsia.dev/reference/fidl/fuchsia.component#Binder
[fidl-decl.Child]: https://fuchsia.dev/reference/fidl/fuchsia.component.decl/#Child
[fidl-decl.ChildRef]: https://fuchsia.dev/reference/fidl/fuchsia.component.decl/#ChildRef
[fidl-decl.CollectionRef]: https://fuchsia.dev/reference/fidl/fuchsia.component.decl/#CollectionRef
[fidl-fuchsia.io]: https://fuchsia.dev/reference/fidl/fuchsia.io
[fidl-fuchsia.io.Directory]: https://fuchsia.dev/reference/fidl/fuchsia.io#Directory
[fidl-Lifecycle]: https://fuchsia.dev/reference/fidl/fuchsia.process.lifecycle#Lifecycle
[fidl-Realm]: https://fuchsia.dev/reference/fidl/fuchsia.component#Realm
[fidl-Realm.CreateChild]: https://fuchsia.dev/reference/fidl/fuchsia.component#Realm.CreateChild
[fidl-Realm.DestroyChild]: https://fuchsia.dev/reference/fidl/fuchsia.component#Realm.DestroyChild
[fidl-Realm.OpenExposedDir]: https://fuchsia.dev/reference/fidl/fuchsia.component#Realm.OpenExposedDir
[glossary.capability]: /docs/glossary/README.md#capability
[glossary.component-collection]: /docs/glossary/README.md#component-collection
[glossary.component-declaration]: /docs/glossary/README.md#component-declaration
[glossary.component-instance]: /docs/glossary/README.md#component-instance
[glossary.component-instance-tree]: /docs/glossary/README.md#component-instance-tree
[glossary.component-manifest]: /docs/glossary/README.md#component-manifest
[glossary.component-topology]: /docs/glossary/README.md#component-topology
[glossary.exposed-directory]: /docs/glossary/README.md#exposed-directory
[glossary.namespace]: /docs/glossary/README.md#namespace
[glossary.outgoing-directory]: /docs/glossary/README.md#outgoing-directory
[src-security-policy]: /src/security/policy/component_manager_policy.json5
[static-analyzer]: /docs/development/components/build.md#troubleshoot-build-analyzer