blob: 34ee6a649a3de337385bfb63513c76572ca48bed [file] [log] [blame] [view]
# Troubleshooting components {#troubleshooting-components}
Note: This guide is exclusive to [v2 components][glossary-components-v2].
This document contains tips for troubleshooting the following kinds of problems
when using the [component framework][doc-intro]:
- [Error when trying to use a capability from the namespace](#troubleshoot-use)
- [Test does not start](#troubleshoot-test)
## Got an error when trying to use a capability from the namespace {#troubleshoot-use}
Sometimes, when connecting to a capability such as a [protocol][doc-protocol],
[service][doc-service], or [directory][doc-directory] in your
[namespace][glossary-namespace], the channel returns an error when you try to
use it. For example, consider the following snippet:
```rust
use fuchsia_component::client;
use log::info;
...
let echo = client::connect_to_service::<fidl_fuchsia_echo::EchoMarker>().expect("error connecting to echo");
if let Some(err) = echo.echo_string(Some("Hippos rule!")).await {
info!("Echo failed: {}", err);
}
```
In this Rust example, the code connects to the `Echo` protocol in the namespace
through the usual means, by calling the `connect_to_service` API in the
`fuchsia_component` crate. This call should succeed as long as the protocol was
mapped into the component's namespace by a `use` declaration in the component's
[manifest][doc-manifests]:
```json5
use: [
{ protocol: "/svc/fuchsia.echo.Echo" },
...
],
```
However, when the `connect_to_service` call returns successfully, it does not
necessarily mean the protocol will be available. If it's not available, the
usual symptom is that a call to the protocol over the channel fails. The
snippet above checks for this and logs the error.
There are a few conditions that can cause these errors:
- [Channel was closed after connecting to a capability in the namespace](#troubleshoot-use-routing)
- [Component fails to start](#troubleshoot-use-start)
- [Component terminated or closed the channel](#troubleshoot-use-terminated)
### Channel was closed after connecting to a capability in the namespace {#troubleshoot-use-routing}
When a protocol or service is opened in the namespace, or a directory in the
namespace is used for the first time, component manager will perform
[capability routing][doc-routing] to find the source of the capability. It's
possible that routing will fail if one of the component manifests in the
routing path was configured incorrectly. For example, it's possible that 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.
There are a couple ways to check if a routing failure was the cause of channel
closure:
- Check for an [epitaph][doc-epitaphs] on the closed channel.
- Check the component manager logs with `fx log --only component_manager`
See [checking a closed channel](#troubleshoot-closed-channel) for details on
how to check if a channel was closed and get an epitaph if there was one.
Normally, the epitaph set for a routing failure is `ZX_ERR_UNAVAILABLE`.
For a more detailed description of the error, check the kernel debuglog. Look
for a message beginning with `ERROR: Failed to route` with the requesting
component's [moniker][doc-monikers]. This error should give you a hint about
what went wrong. Example:
```
> [component_manager] ERROR: Failed to route protocol `/svc/fuchsia.echo.Echo`
> from component `/core:0/echo_client:0`: A `use from realm` declaration was
> found at `/echo_client:0` for `/svc/fuchsia.echo.Echo`, but no matching
> `offer` declaration was found in the parent
```
For a self-contained example of failed routing that demonstrates the content of
this section, refer to
[//examples/components/routing_failed][example-routing-failed].
### Component fails to start {#troubleshoot-use-start}
It's possible that the capability was [routed](#troubleshoot-use-routing)
successfully, but something went wrong when the [runner][doc-runners] tried to
start the component. Here's a couple ways this can happen:
- The [`program`][doc-manifests-program] declaration was misconfigured. For
example, the binary's path was spelled incorrectly.
- The binary or some other resource needed to start the component was not
included in its [package][doc-packages].
When this happens, the runner closes the channel with a `PEER_CLOSED` status,
with no epitaph. See [checking a closed channel](#troubleshoot-closed-channel)
for details on how to check if a channel was closed and get an epitaph if there
was one.
Note that just from the state of the channel, it's impossible to distinguish
whether the runner failed to start the component, or the [component terminated
or closed the channel itself](#troubleshoot-use-terminated).
For a more detailed description of the error, check the logs. The log to check
depends on the runner:
- For the ELF runner, check the component manager logs with `fx log --only
component_manager`
- For other runners, check the [logs][doc-logs] of the runner component. You
can do this by running `fx log --tag <runner-name>`.
The form of the error message is runner-dependent. For the ELF runner, look for a message starting
with `ERROR: Failed to start component`:
```
> [component_manager] ERROR: 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 was closed: PEER_CLOSED"
```
In this case, the component failed to start because its binary was not present.
For an example of a component that failed to start due to a misconfigured
component manifest, refer to
[//examples/components/routing_failed][example-routing-failed].
### Component terminated or closed the channel {#troubleshoot-use-terminated}
If you have verified that [routing succeeded](#troubleshoot-routing) and the
[component started successfully](#troubleshoot-use-start), then the final
possibility is that 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 `fx log` that starts like this:
```
[00177.191] 01775:02371> crashsvc: exception received, processing
[00177.191] 01775:02371> <== fatal : process echo_client.cm[21090] thread initial-thread[21092]
<stack trace follows...>
```
Note that you'll see name of the component manifest in the dump (this is
actually the process name).
If the component closed the channel itself, there's no universal way to debug
if this happened. You can look in the component's [logs][doc-logs], or in the
case of a protocol capability, search the source code for the name of the
source code in a language-appropriate format. For example, for the
`fuchsia.Echo` protocol in Rust, you might search for a `use` statement for
`fidl_fuchsia_echo`, then follow the identifier to where it's used.
The final possibility is that a component may have already been started by a
previous capability request, but has since terminated on its own.
### Checking if a channel was closed {#troubleshoot-closed-channel}
If a protocol channel was closed, you'll normally notice when trying to make a
call on it, if the call is awaited on. For example:
```rust
let res = echo.echo_string(Some("Hippos rule!")).await;
match res {
Ok(_) => { info!("Call succeeded!"); }
Err(fidl::Error::ClientWrite(zx::Status::PEER_CLOSED)) => {
error!("Channel was closed");
}
Err(fidl::Error::ClientChannelClosed { status, service_name } => {
error!("Channel to service {} was closed with status: {}", service_name, status);
}
Err(e) => {
error!("Unexpected error: {}", e);
}
};
```
This won't work if the call doesn't return a value, because such calls can't be
awaited on. However, if your protocol pipelines a call that does return a
value, you can check that:
```rust
let (echo_resp, echo_resp_svc) = fidl::endpoints::create_proxy();
let res = echo_async.echo_string(Some("Hippos rule!"), echo_resp_svc);
match res {
Ok(_) => {
info!("EchoString succeeded!");
}
Err(fidl::Error::ClientWrite(zx::Status::PEER_CLOSED)) => {
error!("EchoAsync channel was closed");
}
Err(e) => {
error!("Unexpected error: {}", e);
}
};
let res = echo_resp.get_result().await;
match res {
Ok(_) => { info!("GetResult succeeded!"); }
Err(fidl::Error::ClientWrite(zx::Status::PEER_CLOSED)) => {
error!("EchoResponder channel was closed");
}
Err(fidl::Error::ClientChannelClosed { status, service_name } => {
error!("Channel to service {} was closed with status: {}", service_name, status);
}
Err(e) => {
error!("Unexpected error: {}", e);
}
};
```
If `echo_resp` is closed, it's likely that's indirectly because `echo_async` was closed.
In the case of [routing failure](#troubleshoot-use-routing), component manager
sets an [epitaph][doc-epitaphs] on the channel that was opened through the
namespace. You can get the epitaph on a closed channel as follows:
```rust
let stream = echo.take_event_stream();
match stream.next().await {
Some(m) => {
info!("Received message other than epitaph or peer closed: {:?}", m);
}
Some(Err(fidl::Error::ClientChannelClosed { status, .. })) => {
info!("Echo channel was closed with epitaph, probably due to \
failed routing: {}", status);
}
None => {
info!("Component failed to start or Echo channel was closed by server");
}
}
```
Note: in the `echo_async` example, the epitaph would be set on `echo_async`,
not `echo_resp`.
## Test does not start {#troubleshoot-test}
A Components v2 test is written using [Fuchsia Testing Framework][doc-ftf].
Sometimes, if one of the test components is configured incorrectly, this can
result in the test failing to run.
If this happens, you'll see an error like the following from `fx test`:
```
Test suite encountered error trying to run tests: Error getting test cases: The test protocol was
closed. This may mean `/svc/fuchsia.test.Suite` was not configured properly. Refer to
//docs/development/components/troubleshooting.md#troubleshoot-test.
```
Misconfigurations can happen in a few ways:
- [The test failed to expose `fuchsia.test.Suite` to test manager](#troubleshoot-test-root)
- [The test driver failed to expose `fuchsia.test.Suite` to the root](#troubleshoot-test-routing)
- [The test driver does not use a test runner](#troubleshoot-test-runner)
### The test failed to expose `fuchsia.test.Suite` to test manager {#troubleshoot-test-root}
This happens when the test root fails to expose `fuchsia.test.Suite` from the
[test root][doc-ftf-root]. The simple fix is to add an `expose` declaration:
```json5
// test_root.cml
expose: [
...
{
protocol: "/svc/fuchsia.test.Suite",
from: "self", // If a child component is the test driver, put `from: "#driver"`
},
],
```
### The test driver failed to expose `fuchsia.test.Suite` to the root {#troubleshoot-test-routing}
If the [test driver][doc-ftf-driver] and [test root][doc-ftf-root] are
different components, the test driver must also expose `fuchsia.test.Suite` to
its parent, the test root.
Make sure this is in the driver's CML:
```json5
// test_driver.cml
expose: [
...
{
protocol: "/svc/fuchsia.test.Suite",
from: "self",
},
],
```
If this is the problem, you can expect to see an error like this in the logs:
```
> ERROR: Failed to route protocol `/svc/fuchsia.test.Suite` from component
> `/test_manager:0/...`: An `expose from #driver` declaration was found at `/test_manager:0/...`
> for `/svc/fuchsia.test.Suite`, but no matching `expose` declaration was found in the child
```
### The test driver does not use a test runner {#troubleshoot-test-runner}
The [test driver][doc-ftf-driver] must use the appropriate [test
runner][doc-ftf-runner] corresponding to the language and test framework the
test is written with. For example, the driver of a Rust test needs the
following declaration:
```json5
// test_driver.cml
use: [
{ runner: "rust_test_runner" },
],
```
Also, if the test driver is a child of the [test root][ftf-test-root], you need
to offer it to the driver:
```json5
// test_root.cml
offer: [
{
runner: "rust_test_runner",
to: [ "#driver" ],
},
],
```
[doc-directory]: /docs/concepts/components/v2/capabilities/directory.md
[doc-epitaphs]: /docs/reference/fidl/language/wire-format/README.md#epitaphs
[doc-ftf-driver]: /docs/concepts/testing/fuchsia_testing_framework.md#test-roles
[doc-ftf-root]: /docs/concepts/testing/fuchsia_testing_framework.md#tests-as-components
[doc-ftf-runner]: /docs/concepts/testing/fuchsia_testing_framework.md#test-runners
[doc-ftf]: /docs/concepts/testing/fuchsia_testing_framework.md
[doc-intro]: /docs/concepts/components/v2/introduction.md
[doc-logs]: /docs/development/logs/concepts.md
[doc-manifests-program]: /docs/concepts/components/v2/component_manifests.md#program
[doc-manifests]: /docs/concepts/components/v2/component_manifests.md
[doc-monikers]: /docs/concepts/components/v2/monikers.md
[doc-packages]: /docs/concepts/packages/package.md
[doc-protocol]: /docs/concepts/components/v2/capabilities/protocol.md
[doc-routing]: /docs/concepts/components/v2/component_manifests.md#routing
[doc-runners]: /docs/concepts/components/v2/runners.md
[doc-service]: /docs/concepts/components/v2/capabilities/service.md
[example-routing-failed]: /examples/components/routing_failed/README.md
[glossary-components-v2]: /docs/glossary.md#components-v2
[glossary-namespace]: /docs/glossary.md#namespace