This document demonstrates how to connect


[](https://fuchsia.dev/docs/glossary#component)


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 [](https://fuchsia.dev/docs/glossary#namespace) for a component using [](https://fuchsia.dev/docs/glossary#component-declaration) that describe the [](https://fuchsia.dev/docs/glossary#capability) the component requires to function. The capabilities the component exposes to others are assembled into an [](https://fuchsia.dev/docs/glossary#exposed-directory) .
- Every component receives a handle to the server end of a [`Directory`](https://fuchsia.dev/reference/fidl/fuchsia.io#Directory) channel called the [](https://fuchsia.dev/docs/glossary#outgoing-directory) . The component's program makes discoverable any capabilities that it provides through this directory.
- At runtime, the [](https://fuchsia.dev/docs/glossary#component-instance-tree) describes parent and child relationships between [](https://fuchsia.dev/docs/glossary#component-instance) . The component instance tree and the capability routes over that tree are collectively referred to as the [](https://fuchsia.dev/docs/glossary#component-topology) .
- Parent components declare child components either statically in their [](https://fuchsia.dev/docs/glossary#component-manifest) or dynamically using a [](https://fuchsia.dev/docs/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](https://fuchsia.dev/docs/concepts/components/v2/realms) and
[Capabilities](https://fuchsia.dev/docs/concepts/components/v2/capabilities/README).

## Connecting capabilities through routing

> [!NOTE]
> **Note:** For a complete example using routed capabilities, see [`//examples/components/routing`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/examples/components/routing/).

Components interact with each other through capabilities. Capabilities served by
a component need to be declared in that component's manifest and, for them to be
usable by others, routed to parent/child components through `expose` and `offer`
declarations. Other components that use that capability also need to declare
their use in their manifests. In order for their programs to use the capability
at runtime, the used capability must be routed to that component - either
offered from a parent or exposed by a child.

*Capability routing* refers to the recursive process, performed by the component
manager, of identifying a serving component by following individual routing
steps described in manifest files. Capability routing is initiated when:

- A component's program opens a path in its [](https://fuchsia.dev/docs/glossary#namespace) .
- A component's program opens a path in another component's [](https://fuchsia.dev/docs/glossary#exposed-directory) .
- A developer invokes `ffx component route`.
- Starting a component that depends on a Resolver or Runner whose backing resolver or runner capabilities have not been routed.

Routing is performed lazily: while a capability may be *configured* to be
provided by a parent or child (directly or indirectly through further
delegation), the target component may not have been resolved yet when the
routing operation is initiated. Practically, this means that the full route from
the requesting component to the final serving component may not be known until
routing is attempted.

### Provide a capability implementation

Components that provide a capability must declare the capability in their
component manifest using a [`capabilities`](https://fuchsia.dev/reference/cml#capabilities) declaration.

See the following example that declares a FIDL
[protocol capability](https://fuchsia.dev/docs/concepts/components/v2/capabilities/protocol) in the providing component's manifest:

    {
        include: [
            "inspect/client.shard.cml",
            "syslog/client.shard.cml",
        ],

        // Information about the program to run.
        program: {
            // Use the built-in ELF runner.
            runner: "elf",

            // The binary to run for this component.
            binary: "bin/echo_server_rust",
        },

    // Capabilities provided by this component.
    capabilities: \[
    { protocol: "fidl.examples.routing.echo.Echo" },
    \],
        expose: [
            {
                protocol: "fidl.examples.routing.echo.Echo",
                from: "self",
            },
        ],
    }

At runtime, the server component provides an implementation of the capability by
serving it in its outgoing directory using the [fuchsia.io](https://fuchsia.dev/reference/fidl/fuchsia.io)
protocol. The generated FIDL bindings wrap this handle and enable the provider
to begin receiving incoming requests:

### Rust

    // Wrap protocol requests being served.
    enum IncomingRequest {
    Echo(EchoRequestStream),
    }

    #[fuchsia::main(logging = false)]
    async fn main() -> Result<(), anyhow::Error> {
    let mut service_fs = ServiceFs::new_local();

        // Initialize inspect
        component::health().set_starting_up();
        let _inspect_server_task = inspect_runtime::publish(
            component::inspector(),
    inspect_runtime::PublishOptions::default(),
    );

        // Serve the Echo protocol
        service_fs.dir("svc").add_fidl_service(IncomingRequest::Echo);
        service_fs.take_and_serve_directory_handle().context("failed to serve outgoing namespace")?;

    // Component is serving and ready to handle incoming requests
    component::health().set_ok();

    // Attach request handler for incoming requests
    service_fs
    .for_each_concurrent(None, \|request: IncomingRequest\| async move {
    match request {
    IncomingRequest::Echo(stream) =\> handle_echo_request(stream).await,
                }
            })
            .await;

        Ok(())
    }

    // Handler for incoming service requests
    async fn handle_echo_request(mut stream: EchoRequestStream) {
    while let Some(event) = stream.try_next().await.expect("failed to serve echo service") {
    let EchoRequest::EchoString { value, responder } = event;
    responder.send(value.as_ref().map(\|s\| \&\*\*s)).expect("failed to send echo response");
    }
    }

### C++

    // Handler for incoming service requests
    class EchoImplementation : public fidl::Server\<fidl_examples_routing_echo::Echo\> {
    public:
    void EchoString(EchoStringRequest\& request, EchoStringCompleter::Sync\& completer) override {
    completer.Reply({{.response = request.value()}});
    }
    };

    int main(int argc, const char** argv) {
      async::Loop loop(&kAsyncLoopConfigAttachToCurrentThread);
    async_dispatcher_t\* dispatcher = loop.dispatcher();

      // Initialize inspect
      inspect::ComponentInspector inspector(loop.dispatcher(), inspect::PublishOptions{});
      inspector.Health().StartingUp();

    component::OutgoingDirectory outgoing_directory = component::OutgoingDirectory(dispatcher);
    zx::result result = outgoing_directory.ServeFromStartupInfo();
    if (result.is_error()) {
    FX_LOGS(ERROR) \<\< "Failed to serve outgoing directory: " \<\< result.status_string();
    return -1;
    }

    result = outgoing_directory.AddUnmanagedProtocol\<fidl_examples_routing_echo::Echo\>(
    \[dispatcher\](fidl::ServerEnd\<fidl_examples_routing_echo::Echo\> server_end) {
            fidl::BindServer(dispatcher, std::move(server_end), std::make_unique<EchoImplementation>());
          });
      if (result.is_error()) {
        FX_LOGS(ERROR) << "Failed to add Echo protocol: " << result.status_string();
        return -1;
      }

      // Component is serving and ready to handle incoming requests
      inspector.Health().Ok();

      return loop.Run();
    }

### Connect to routed capabilities

Client components declare capabilities they may request in their component
manifest with a [`use`](https://fuchsia.dev/reference/cml#use) declaration.

See the following example of a client component's manifest that uses the FIDL
protocol provided by the previous component:

    {
        include: [
            // Enable logging on stdout
            "syslog/client.shard.cml",
        ],

        // Information about the program to run.
        program: {
            // Use the built-in ELF runner.
            runner: "elf",

            // The binary to run for this component.
            binary: "bin/echo_client_rust",

            // Program arguments
            args: [ "Hello Fuchsia!" ],
        },


    // Capabilities used by this component.
    use: \[
    { protocol: "fidl.examples.routing.echo.Echo" },
        ],
    }

At runtime, the client component opens paths populated in its namespace using
the [fuchsia.io](https://fuchsia.dev/reference/fidl/fuchsia.io) protocol in order to acquire capabilities
provided by other components. The Fuchsia component library works with the
generated FIDL bindings to provide a structured interface for communicating over
the channel:

### Rust

    #[fuchsia::main]
    async fn main() -> Result<(), anyhow::Error> {
        // Parse arguments, removing binary name
        let mut args: Vec<String> = std::env::args().collect();
        args.remove(0);

    // Connect to FIDL protocol
    let echo = connect_to_protocol::\<EchoMarker\>().expect("error connecting to echo");

    // Send messages over FIDL interface
    for message in args {
    let out = echo.echo_string(Some(\&message)).await.expect("echo_string failed");
    log::info!("Server response: {}", out.as_ref().expect("echo_string got empty result"));
    }

        Ok(())
    }

### C++

    int main(int argc, const char* argv[], char* envp[]) {
    // Set tags for logging.
    fuchsia_logging::LogSettingsBuilder builder;
    builder.WithTags({"echo_client"}).BuildAndInitialize();

      // Connect to FIDL protocol
    zx::result client_end = component::Connect\<fidl_examples_routing_echo::Echo\>();
    if (client_end.is_error()) {
        FX_LOGS(ERROR) << "Failed to connect to Echo protocol: " << client_end.status_string();
    return EXIT_FAILURE;
      }
      fidl::SyncClient client(std::move(client_end.value()));

      // Send messages over FIDL interface for each argument
      fidl::StringPtr response = nullptr;
      for (int i = 1; i < argc; i++) {
        fidl::Result response = client->EchoString({argv[i]});

        if (response.is_error()) {
          FX_LOGS(ERROR) << "echo_string failed: " << response.error_value();
          return EXIT_FAILURE;
        }
        if (!response->response().has_value()) {
          FX_LOGS(ERROR) << "echo_string got empty result";
          return EXIT_FAILURE;
        }
        const std::string& response_value = response->response().value();
        FX_LOG_KV(INFO, "Server response", FX_KV("response", response_value));
      }

      return 0;
    }

It is the responsibility of the component's parent to route to it all necessary
capabilities.

#### Mark some used capabilities as optional

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 (the default)
but its parent offers the capability as `optional`, then the
[static capability analyzer](https://fuchsia.dev/docs/development/components/build#troubleshoot-build-analyzer) will generate an error and
connection attempts at runtime will always fail.

##### 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


[](https://fuchsia.dev/docs/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_NOT_FOUND` epitaph.

Usage of `libc` methods like `open()` or `stat()` will return `ENOENT`.

### Route capabilities

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`](https://fuchsia.dev/reference/cml#expose): Routes a capability up to the component's parent.
- [`offer`](https://fuchsia.dev/reference/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:

       {
           include: [
               "inspect/client.shard.cml",
               "syslog/client.shard.cml",
           ],

           // Information about the program to run.
           program: {
               // Use the built-in ELF runner.
               runner: "elf",

               // The binary to run for this component.
               binary: "bin/echo_server_rust",
           },

           // Capabilities provided by this component.
           capabilities: [
               { protocol: "fidl.examples.routing.echo.Echo" },
           ],
       expose: \[
       {
       protocol: "fidl.examples.routing.echo.Echo",
       from: "self",
       },
       \],
       }

2. 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:

       {
           // Two children: a server and client.
           children: [
               {
                   name: "echo_server",
                   url: "#meta/echo_server.cm",
               },
               {
                   name: "echo_client",
                   url: "#meta/echo_client.cm",
               },
           ],
       offer: \[
       // Route Echo protocol from server to client.
       {
       protocol: "fidl.examples.routing.echo.Echo",
       from: "#echo_server",
       to: "#echo_client",
       },

       // Route diagnostics protocols to both children.
       {
       dictionary: "diagnostics",
       from: "parent",
       to: \[
       "#echo_client",
       "#echo_server",
       \],
       },
       \],
       }

#### Optional dependencies

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 its 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

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

> [!NOTE]
> **Note:** For a complete example using child components, see [`//examples/components/lifecycle`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/examples/components/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:

    {
        // ...

        // Statically declared child components
        children: [
            {
                name: "lifecycle",
                url: "lifecycle#meta/default.cm",
            },
        ],

        // Collection to hold dynamically created child components
        collections: [
            {
                name: "echo",
                durability: "transient",
            },
        ],

        // Capabilities required by this component
        use: [
            {
                protocol: "fuchsia.component.Binder",
                from: "#lifecycle",
            },
            {
                protocol: "fuchsia.component.Realm",
                from: "framework",
            },
        ],

        // Capabilities required by child components
        offer: [
            {
                dictionary: "diagnostics",
                from: "parent",
                to: [
                    "#echo",
                    "#lifecycle",
                ],
            },
        ],
    }

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

The Component Framework provides the [`fuchsia.component.Binder`](https://fuchsia.dev/reference/fidl/fuchsia.component#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:

    {
        // ...

        // Capabilities exposed from this component to parent.
        expose: [
            {
                // Expose this protocol so that parent component can start it
                // by binding to this capability.
                protocol: "fuchsia.component.Binder",
                from: "framework",
            },
        ],
    }

### Create dynamic children

To create a new child component at runtime, use the
[`fuchsia.component.Realm`](https://fuchsia.dev/reference/fidl/fuchsia.component#Realm) protocol to create the component inside
of an existing collection. Call the [`CreateChild`](https://fuchsia.dev/reference/fidl/fuchsia.component#Realm.CreateChild)
method with the following parameters:

- [`CollectionRef`](https://fuchsia.dev/reference/fidl/fuchsia.component.decl/#CollectionRef): Describes the collection where the component will be added.
- [`Child`](https://fuchsia.dev/reference/fidl/fuchsia.component.decl/#Child): Component declaration, including its name and
  component URL.

### Rust

    use fidl_fuchsia_component::{BinderMarker, CreateChildArgs, RealmMarker};
    use fidl_fuchsia_component_decl::{Child, ChildRef, CollectionRef, StartupMode};

    // ...

    // Use the fuchsia.component.Realm protocol to create a dynamic
    // child instance in the collection.
    async fn create_dynamic_child() {
        let realm = client::connect_to_protocol::<RealmMarker>()
            .expect("failed to connect to fuchsia.component.Realm");

        let collection_ref = CollectionRef { name: String::from("echo") };
        let child_decl = Child {
            name: Some(String::from("lifecycle_dynamic")),
            url: Some(String::from("echo_server#meta/default.cm")),
            startup: Some(StartupMode::Lazy),
            ..Default::default()
        };

        realm
            .create_child(&collection_ref, &child_decl, CreateChildArgs::default())
            .await
            .expect("create_child failed")
            .expect("failed to create child");
    }

### C++

    #include <fuchsia/component/cpp/fidl.h>
    #include <fuchsia/component/decl/cpp/fidl.h>

    // ...

    // Use the fuchsia.component.Realm protocol to create a dynamic
    // child instance in the collection.
    void CreateDynamicChild() {
      fuchsia::component::decl::CollectionRef collection_ref = {
          .name = "echo",
      };
      fuchsia::component::decl::Child child_decl;
      child_decl.set_name("lifecycle_dynamic");
      child_decl.set_url("echo_server#meta/default.cm");
      child_decl.set_startup(fuchsia::component::decl::StartupMode::LAZY);

      realm_proxy_->CreateChild(std::move(collection_ref), std::move(child_decl),
                                fuchsia::component::CreateChildArgs(),
                                [&](fuchsia::component::Realm_CreateChild_Result result) {
                                  ZX_ASSERT(!result.is_err());
                                  FX_LOGS(INFO) << "Dynamic child instance created.";

                                  ConnectDynamicChild();
                                });
    }

### Connect to child capabilities

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`](https://fuchsia.dev/reference/fidl/fuchsia.component#Realm) protocol to open the child's
   exposed directory. Call the [`OpenExposedDir`](https://fuchsia.dev/reference/fidl/fuchsia.component#Realm.OpenExposedDir)
   method with the child component's name and the collection name:

   ### Rust

       use fidl_fuchsia_component::{BinderMarker, CreateChildArgs, RealmMarker};
       use fidl_fuchsia_component_decl::{Child, ChildRef, CollectionRef, StartupMode};

       // ...
       // Connect to the fidl.examples.routing.echo capability exposed by the child
       // instance, and send a request.
       async fn connect_dynamic_child(message: String) {
           // Open the child's exposed directory
           let exposed_dir = client::open_childs_exposed_directory(
               String::from("lifecycle_dynamic"),
               Some(String::from("echo")),
           )
           .await
           .expect("failed to open exposed directory");

           // ...
       }

   ### C++

       #include <fuchsia/component/cpp/fidl.h>
       #include <fuchsia/component/decl/cpp/fidl.h>

       // ...

       // Use the fuchsia.component.Realm protocol to open the exposed directory of
       // the dynamic child instance.
       void ConnectDynamicChild() {
         fuchsia::component::decl::ChildRef child_ref = {
             .name = "lifecycle_dynamic",
             .collection = "echo",
         };

         fidl::InterfaceHandle<fuchsia::io::Directory> exposed_dir;
         realm_proxy_->OpenExposedDir(
             child_ref, exposed_dir.NewRequest(),
             [this, exposed_dir = std::move(exposed_dir)](
                 fuchsia::component::Realm_OpenExposedDir_Result result) mutable {
               ZX_ASSERT(!result.is_err());
               std::shared_ptr<sys::ServiceDirectory> svc = std::make_shared<sys::ServiceDirectory>(
                   sys::ServiceDirectory(std::move(exposed_dir)));

               SendEchoRequest(svc);
             });
       }

2. Connect to the child's exposed capabilities using the exposed directory
   handle as the root:

   ### Rust

       // Access the fidl.examples.routing.echo capability provided there
       let echo = client::connect_to_protocol_at_dir_root::<EchoMarker>(&exposed_dir)
           .expect("failed to connect to fidl.examples.routing.echo");

       let response = echo
           .echo_string(Some(&message))
           .await
           .expect("echo_string failed")
           .expect("echo_string got empty result");
       info!("Server response: {}", response);

   ### C++

       // Connect to the fidl.examples.routing.echo capability exposed by the child's
       // service directory.
       void SendEchoRequest(std::shared_ptr<sys::ServiceDirectory> svc_directory) {
         // Connect to the protocol inside the child's exposed directory
         svc_directory->Connect(echo_proxy_.NewRequest());

         // Send a protocol request
         echo_proxy_->EchoString(message_, [&](fidl::StringPtr response) {
           FX_LOGS(INFO) << "Server response: " << response;
           DestroyDynamicChild();
         });
       }

### Destroy dynamic children

When the dynamic child is no longer needed, use the
[`fuchsia.component.Realm`](https://fuchsia.dev/reference/fidl/fuchsia.component#Realm) protocol to destroy the component
instance. Call the [`DestroyChild`](https://fuchsia.dev/reference/fidl/fuchsia.component#Realm.DestroyChild) method with a
[`ChildRef`](https://fuchsia.dev/reference/fidl/fuchsia.component.decl/#ChildRef) representing the child inside the collection.

### Rust

    use fidl_fuchsia_component::{BinderMarker, CreateChildArgs, RealmMarker};
    use fidl_fuchsia_component_decl::{Child, ChildRef, CollectionRef, StartupMode};

    // ...

    // Use the fuchsia.component.Realm protocol to destroy the dynamic
    // child instance running in the collection.
    async fn destroy_dynamic_child() {
        let realm = client::connect_to_protocol::<RealmMarker>()
            .expect("failed to connect to fuchsia.component.Realm");

        let child_ref = ChildRef {
            name: String::from("lifecycle_dynamic"),
            collection: Some(String::from("echo")),
        };

        realm
            .destroy_child(&child_ref)
            .await
            .expect("destroy_child failed")
            .expect("failed to destroy child");
    }

### C++

    #include <fuchsia/component/cpp/fidl.h>
    #include <fuchsia/component/decl/cpp/fidl.h>

    // ...

    // Use the fuchsia.component.Realm protocol to destroy the dynamic
    // child instance running in the collection.
    void DestroyDynamicChild() {
      fuchsia::component::decl::ChildRef child_ref = {
          .name = "lifecycle_dynamic",
          .collection = "echo",
      };

      realm_proxy_->DestroyChild(std::move(child_ref),
                                 [&](fuchsia::component::Realm_DestroyChild_Result result) {
                                   ZX_ASSERT(!result.is_err());
                                   FX_LOGS(INFO) << "Dynamic child instance destroyed.";

                                   // Terminate the loop
                                   loop_->Quit();
                                 });
    }

This causes the component to stop if it is currently running. To handle this
event in your component, see [listen for stop events](https://fuchsia.dev/fuchsia-src/development/components/connect#lifecycle-notifications).

## Controlling component 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](https://fuchsia.dev/docs/concepts/components/v2/lifecycle).

### Lifecycle notifications

The ELF runner notifies components of lifecycle events using the
[`fuchsia.process.lifecycle.Lifecycle`](https://fuchsia.dev/reference/fidl/fuchsia.process.lifecycle#Lifecycle) protocol.

To listen for stop notifications in your child component:

1. Subscribe to the [lifecycle event](https://fuchsia.dev/docs/concepts/components/v2/elf_runner#lifecycle) in your component
   manifest:

   ### Rust

       // Information about the program to run.
       program: {
           // Use the built-in ELF runner.
           runner: "elf",

           // The binary to run for this component.
           binary: "bin/lifecycle_example_rust",

       // Subscribe to component lifecycle events
       lifecycle: { stop_event: "notify" },
       },

   ### C++

       // Information about the program to run.
       program: {
           // Use the built-in ELF runner.
           runner: "elf",

           // The binary to run for this component.
           binary: "bin/lifecycle_example_cpp",

       // Subscribe to component lifecycle events
       lifecycle: { stop_event: "notify" },
       },

2. Register a lifecycle handler using the startup handle provided by the
   runner:

   ### Rust

       use fidl_fuchsia_process_lifecycle::{LifecycleRequest, LifecycleRequestStream};

       // ...

       #[fuchsia::main(logging_tags = ["lifecycle", "example"])]
       async fn main() {
           // Take the lifecycle handle provided by the runner
           match fuchsia_runtime::take_startup_handle(HandleInfo::new(HandleType::Lifecycle, 0)) {
               Some(lifecycle_handle) => {
                   info!("Lifecycle channel received.");
                   // Begin listening for lifecycle requests on this channel
                   let x: zx::Channel = lifecycle_handle.into();
                   let async_x = AsyncChannel::from(fuchsia_async::Channel::from_channel(x));
                   let mut req_stream = LifecycleRequestStream::from_channel(async_x);
                   info!("Awaiting request to close...");
                   if let Some(request) =
                       req_stream.try_next().await.expect("Failure receiving lifecycle FIDL message")
                   {
                       match request {
                           LifecycleRequest::Stop { control_handle: c } => {
                               info!("Received request to stop. Shutting down.");
                               c.shutdown();
                               process::exit(0);
                           }
                       }
                   }

                   // We only arrive here if the lifecycle channel closed without
                   // first sending the shutdown event, which is unexpected.
                   process::abort();
               }
               None => {
                   // We did not receive a lifecycle channel, exit abnormally.
                   error!("No lifecycle channel received, exiting.");
                   process::abort();
               }
           }
       }

   ### C++

       #include <fuchsia/process/lifecycle/cpp/fidl.h>

       // ...

       // Implementation of the fuchsia.process.lifecycle FIDL protocol
       class LifecycleHandler : public fuchsia::process::lifecycle::Lifecycle {
        public:
         explicit LifecycleHandler(async::Loop* loop) : loop_(loop) {
           // Get the PA_LIFECYCLE handle, and instantiate the channel with it
           zx::channel channel = zx::channel(zx_take_startup_handle(PA_LIFECYCLE));
           // Bind to the channel and start listening for events
           bindings_.AddBinding(
               this, fidl::InterfaceRequest<fuchsia::process::lifecycle::Lifecycle>(std::move(channel)),
               loop_->dispatcher());
           FX_LOGS(INFO) << "Lifecycle channel received.";
         }

         // This is the Stop event we must override - see the pure virtual function we
         // need to override at the declaration of fuchsia::process::lifecycle::Lifecycle
         void Stop() override {
           FX_LOGS(INFO) << "Received request to stop. Shutting down.";
           // Shut down our loop - it's important to call Shutdown() here vs. Quit()
           loop_->Shutdown();
           // Close the binding
           bindings_.CloseAll();
         }

        private:
         async::Loop* loop_;
         fidl::BindingSet<fuchsia::process::lifecycle::Lifecycle> bindings_;
       };

### Start with parent

[Component manifests](https://fuchsia.dev/docs/concepts/components/v2/component_manifests) let you mark a child as
[`eager`](https://fuchsia.dev/reference/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:

      [component_manager] ERROR: protocol `fuchsia.component.CoreBinder` was not available for target `startup`:
          failed to resolve `fuchsia-pkg://fuchsia.com/your_component#meta/your_component.cm`:
          package not found: remote resolver responded with PackageNotFound
          For more, run `ffx component doctor `startup`

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**](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/sys/core/README.md) to ensure they can be
safely excluded from test builds and product images.

An `eager` component should also be in the same [package set](https://fuchsia.dev/docs/concepts/packages/package#types_of_packages)
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:

    fx list-packages --verbose my-package

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:

    $ 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:

    fx list-packages --base

### Reboot on terminate

[Component manifests](https://fuchsia.dev/docs/concepts/components/v2/component_manifests) let you control the termination policy of
your component using [`on_terminate`](https://fuchsia.dev/reference/cml#children). Components with the
"reboot-on-terminate" policy set cause the system to gracefully reboot if the
component terminates for any reason other than successful exit.

> [!NOTE]
> **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.

To enable this feature, do the following:

1. Mark the child as `on_terminate: "reboot"` in the parent's component manifest:

       // core.cml
       {
           children: [
               ...
               {
                   name: "system-update-checker",
                   url: "fuchsia-pkg://fuchsia.com/system-update-checker#meta/system-update-checker.cm",
                   startup: "eager",
                   on_terminate: "reboot",
               },
           ],
       }

2. Add the component's moniker to component manager's security policy allowlist
   at
   [`//src/security/policy/component_manager_policy.json5`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/security/policy/component_manager_policy.json5):

       // //src/security/policy/component_manager_policy.json5
       {
           security_policy: {
               ...
               child_policy: {
                   reboot_on_terminate: [
                       ...
                       "/core/system-update-checker",
                   ],
               },
           },
       }

## Errors

### Signaling mechanism

When routing is initiated by a requesting client by performing a
[`Directory.Open()`](https://fuchsia.dev/reference/fidl/fuchsia.io#Directory) request on its namespace, or on
the


[](https://fuchsia.dev/docs/glossary#exposed-directory)


, it passes the server-end
handle of a zircon object that will provide the capability once routed. Errors
will result in that handle's object being closed with an epitaph. The epitaph
payload is always a Zircon status code.

Since routing is lazy and *asynchronous*, this message may arrive at any time
after the routing operation is initiated.
> NOTE: once routing has *succeeded* , the serving component can *also* close the
> same object with a status code of their choice. It is impossible for a client
> to discern if the object was closed by component manager or by the serving
> component, or another party delegated to thereafter.

The same error signaling mechanism is used for `libc`-like calls like `open()`.

See the section [Troubleshooting](https://fuchsia.dev/fuchsia-src/development/components/connect#troubleshooting) for practical examples.

### Error status codes

The following error codes may be sent by component manager to indicate a failed
routing operation:

- `ZX_ERR_NOT_FOUND`: the capability was unable to be routed for one of the following reasons:
  - An optional capability was not provided in this configuration.
  - A configuration error in any one of the components along the route path.
  - The serving component is incompatible with this version of Fuchsia.
  - A bug in the program of the serving component.
  - A bug in any of the [Resolvers](https://fuchsia.dev/docs/concepts/components/v2/capabilities/resolver) or [Runners](https://fuchsia.dev/docs/concepts/components/v2/capabilities/runner) involved in completing the routing operation.
- `ZX_ERR_ACCESS_DENIED`: the capability was unable to be routed because the requesting component is not allowed to access it. For example:
  - A [policy allow-list](https://cs.opensource.google/fuchsia/fuchsia/+/main:/src/security/policy/component_manager_policy.json5) for the capability exists but does not include the requesting component.
  - The requesting component asked for rights greater than what was provided to it (ie, asking for read/write on a directory provided as read-only).
- `ZX_ERR_TIMED_OUT`: one of the routing steps timed out.
- `ZX_ERR_INTERNAL`: component manager itself encountered an unexpected error, indicating a bug in the platform.

`NOT_FOUND`, `ACCESS_DENIED`, and `INTERNAL` errors will reproduce for the same
capability so long as no software on the platform is updated. A software update,
even for a single component, can change a capability's route and might affect
the availability of that capability.

### Principles of routing error semantics

- *Minimality*: since the error signaling path is shared between component manager and the serving component, component manager leaves the majority of the error space for the serving component to utilize.
- *Client perspective* : while routing depends on many individual sub-operations that can each fail for a variety of reasons including errors on the part of other component authors, the error semantics are tailored to the requesting client and the needs of the requesting client. For example, user-error on the part of an intermediate component author will still return `NOT_FOUND` for the requesting client.

## Troubleshooting

This section contains common issues you may encounter trying to `use` and
connect to capabilities from your component with suggested solutions.

### Capability routing failed

Component manager performs [capability routing](https://fuchsia.dev/docs/concepts/components/v2/capabilities/README) 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:

- Use `ffx component route` to check the routing for your component. This
  can either be used with the moniker of your component or your component's
  URL. For example:

      # check with the moniker
      ffx component route /core/ffx-laboratory:echo_realm/echo_client

      # check with a partial URL
      ffx component route echo_client.cm

- Use `ffx component capability` to find all components that use or expose a
  specific capability. This helps you verify if a capability is available in
  the component topology.

      ffx component capability fuchsia.example.Echo

- Use `ffx component explore` to open an interactive shell inside your
  component's namespace. You can list the contents of `/svc` (or other
  routed directories) to see if the capability is actually available in the
  namespace.

  From the interactive shell, you can check for the capability:

      ls /svc

- Check the component logs with `ffx log` for a message beginning with `Failed
  to route` that explains where the routing chain failed. For example:

      [echo_client][][W] protocol `fidl.examples.routing.echo.Echo` was not available for target `/core/ffx-laboratory:echo_realm/echo_client`:
          `fidl.examples.routing.echo.Echo` was not offered to `/core/ffx-laboratory:echo_realm/echo_client` by parent
          For more, run `ffx component doctor /core/ffx-laboratory:echo_realm/echo_client`

- Check for an [epitaph on the closed channel](https://fuchsia.dev/fuchsia-src/development/components/connect#troubleshooting). The epitaph
  set for the most common routing failures is `ZX_ERR_NOT_FOUND`:

      [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: NOT_FOUND"

  See [routing errors](https://fuchsia.dev/fuchsia-src/development/components/connect#errors) for more.

For a self-contained example of failed capability routing, see
[`//examples/components/routing_failed`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/examples/components/routing_failed/).

### Receiving errors from routing

When capability routing fails, the underlying FIDL channel closes. FIDL protocol
bindings return an error status if the channel was closed. Consider the
following example:

### 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!"); }
        Err(fidl::Error::ClientChannelClosed { status, service_name } =\> {
            error!("Channel to service {} was closed with status: {}", service_name, status);
        }
        Err(e) => {
            error!("Unexpected error: {}", e);
        }
    };

### C++

    fuchsia::examples::EchoPtr echo_proxy;
    auto context = sys::ComponentContext::Create();
    context->svc()->Connect(echo_proxy.NewRequest());

    // Sets an error handler that will be called if an error causes the underlying
    // channel to be closed.
    echo_proxy.set_error_handler(\[\&loop\](zx_status_t status) {
      printf("Channel was closed with status: %d\\n", status);
      // ...
    });

    echo_proxy->EchoString("Hippos rule!", [&](std::string response) {
      // ...
    });

> [!NOTE]
> **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](https://fuchsia.dev/docs/reference/fidl/language/wire-format/README#epitaph_control_message_ordinal_0xffffffff) set on the channel. To retrieve the epitaph on
a closed channel, do the following:

### 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++

    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);
    });

### Component failed to 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](https://fuchsia.dev/docs/concepts/components/v2/capabilities/runner):

- 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:

      [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 fuchsia.io.File was closed: PEER_CLOSED"

- For other runners, check the [logs](https://fuchsia.dev/docs/concepts/components/diagnostics/README#logs) of the runner component. You
  can do this by running the following command:

      ffx log --tags runner-name

To address the issue, verify the following:

- The [`program`](https://fuchsia.dev/reference/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](https://fuchsia.dev/docs/concepts/packages/package).

For an example of a component that failed to start due to a misconfigured
component manifest, see
[`//examples/components/routing_failed`](https://cs.opensource.google/fuchsia/fuchsia/+/main:/examples/components/routing_failed/).

### Component terminated or closed the channel

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:

    [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](https://fuchsia.dev/docs/concepts/components/diagnostics/README#logs) for error messages.
- Use `ffx debug fidl` to examine the FIDL connection traffic with [`fidlcat`](https://fuchsia.dev/docs/development/monitoring/fidlcat/README) for errors or unexpected behavior.

[](https://issues.fuchsia.dev/issues/new?component=1439230&template=1881640&description=Issue+on:+https://fuchsia.dev/docs/development/components/connect.md "Report a bug or suggest improvements on this page") [](https://cs.opensource.google/fuchsia/fuchsia/+/main:docs/development/components/connect.md "View the source code of this page") [](https://ci.android.com/edit?repo=fuchsia/fuchsia/main&file=docs/development/components/connect.md&cloneRepo=fuchsia/fuchsia:refs/heads/main&fullPath=fuchsia/docs/development/components/connect.md "Edit the source code of this page")