blob: c802297658ff2c8002ac0b1a2c7280f9be343874 [file] [log] [blame] [view] [edit]
# Run components
This document demonstrates how to add components directly to the component
instance tree during development and interact with them at runtime.
Fuchsia provides a few abstractions on top of [component framework][glossary.component-framework]
for specific use cases. If you are building components using one of the
following frameworks, refer to the corresponding guides instead:
* **Session components:** [Building and running a session][run-session]
* **Test components:** [Run Fuchsia tests][run-test]
Note: For more details on the commands described in this guide, see the
[`ffx component` reference][ffx-reference].
## Concepts {#concepts}
You should understand the following concepts before running a component:
* 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.
* Component instances progress through four major lifecycle states: create,
start, stop, and destroy.
* A [component moniker][glossary.moniker] identifies component instances
within the tree using their topological path.
* Component instances are declared **statically** as a
[child][manifest-children] of another component in their
[component manifest][glossary.component-manifest] or created **dynamically**
at runtime in a [component collection][manifest-collections]. Each instance
consists of a component `name` and `url`.
* A [component URL][glossary.component-url] identifies a component. Component
URLs are resolved by the component framework, often to a resource inside a
package.
For more details on component execution, see
[Component lifecycle][lifecycle-doc].
## Component instances {#instances}
The first step to running a component is adding a new component instance to the
tree. The position of the component instance within the tree determines its
available [capabilities][glossary.capability].
### Discover static components
Static components are *declared* as children of another component instance in
the tree. You can use `ffx component show` to determine the moniker and
component URL of a static component instance:
```posix-terminal
ffx component show {{ '<var label="component">COMPONENT_NAME</var>' }}
```
Replace `COMPONENT_NAME` with the name of a component. The following example
shows the command output for the `pkg-resolver` component:
```none {:.devsite-disable-click-to-copy}
$ ffx component show pkg-resolver
{{ '<strong>' }}Moniker: /core/pkg-resolver{{ '</strong>' }}
{{ '<strong>' }}URL: fuchsia-pkg://fuchsia.com/pkg-resolver#meta/pkg-resolver.cm{{ '</strong>' }}
Type: CML static component
Component State: Resolved
Execution State: Running
...
```
Static component instances cannot be created or destroyed at runtime.
### Manage dynamic components
Dynamic components are *created* at runtime inside of a collection. You can use
`ffx component create` to create a new component instance, providing a target
moniker within an existing collection and a component URL for resolving the
component:
```posix-terminal
ffx component create {{ '<var label="moniker">TARGET_MONIKER</var>' }} {{ '<var label="url">COMPONENT_URL</var>' }}
```
Replace `TARGET_MONIKER` with the destination moniker of the new component
inside an existing collection and `COMPONENT_URL` with the location where the
component is being served. For example, the following command creates a new
component instance named `hello-world` inside the `ffx-laboratory` collection:
```none {:.devsite-disable-click-to-copy}
$ ffx component create /core/ffx-laboratory:hello-world fuchsia-pkg://fuchsia.com/hello-world-rust#meta/hello-world-rust.cm
URL: fuchsia-pkg://fuchsia.com/hello-world-rust#meta/hello-world-rust.cm
Moniker: /core/ffx-laboratory:hello-world
Creating component instance...
```
Similarly, use `ffx component destroy` to destroy a dynamic component instance
by providing its moniker:
```posix-terminal
ffx component destroy {{ '<var label="moniker">TARGET_MONIKER</var>' }}
```
Replace `TARGET_MONIKER` with the moniker of the component to destroy. The
following example destroys the `hello-world` component created above:
```none {:.devsite-disable-click-to-copy}
$ ffx component destroy /core/ffx-laboratory:hello-world
Moniker: /core/ffx-laboratory:hello-world
Destroying component instance...
```
## Component execution {#execute}
Once a component instance exists in the tree, you can start and stop the target
instance using `ffx component`.
### Start the instance
Use `ffx component start` to explicitly start a component instance:
```posix-terminal
ffx component start {{ '<var label="moniker">TARGET_MONIKER</var>' }}
```
Replace `TARGET_MONIKER` with the moniker of the component to start. The
following example starts the `hello-world` component created previously:
```none {:.devsite-disable-click-to-copy}
$ ffx component start /core/ffx-laboratory:hello-world
Moniker: /core/ffx-laboratory:hello-world
Starting component instance...
```
### Stop the instance
Use `ffx component stop` to terminate execution of a running component instance
using its moniker:
```posix-terminal
ffx component stop {{ '<var label="moniker">TARGET_MONIKER</var>' }}
```
Replace `TARGET_MONIKER` with the moniker of the component to stop. The
following example stops to the `hello-world` component started above:
```none {:.devsite-disable-click-to-copy}
$ ffx component stop /core/ffx-laboratory:hello-world
Moniker: /core/ffx-laboratory:hello-world
Stopping component instance...
```
Note: You can add the `--recursive` flag to stop all child components. For more
details, see the [`ffx component` reference][ffx-reference].
### Run a component {#run}
The `ffx component run` command provides a quickstart to run basic components
during development. It is a shortcut for `ffx component create` followed by
`ffx component start`:
```posix-terminal
ffx component run {{ '<var label="moniker">TARGET_MONIKER</var>' }} {{ '<var label="url">COMPONENT_URL</var>' }}
```
Replace `TARGET_MONIKER` with the destination moniker of the new component
inside an existing collection and `COMPONENT_URL` with the location where the
component is being served. For example, the following command creates a new
component instance named `hello-world-rust` inside the `ffx-laboratory`
collection:
```none {:.devsite-disable-click-to-copy}
$ ffx component run /core/ffx-laboratory:hello-world-rust fuchsia-pkg://fuchsia.com/hello-world-rust#meta/hello-world-rust.cm
URL: fuchsia-pkg://fuchsia.com/hello-world-rust#meta/hello-world-rust.cm
Moniker: /core/ffx-laboratory:hello-world-rust
Creating component instance...
Starting component instance...
```
The example above is equivalent to running the following individual `ffx`
commands:
```none {:.devsite-disable-click-to-copy}
$ ffx component create /core/ffx-laboratory:hello-world-rust fuchsia-pkg://fuchsia.com/hello-world-rust#meta/hello-world-rust.cm
$ ffx component start /core/ffx-laboratory:hello-world-rust
```
# Ways to update a component {#updating}
When you make changes to your component, you'll often want to update one of its
instances running on the device. For example, you may change the component's
binary, and restart the component to run with the new binary. Or you may change
its manifest to add new capability routes and want to make those capability
routes available on the device.
The `ffx component reload` command is the fastest and most complete way to
reload a component. But it's not the only way and understanding the other
methods may allow more precise operations for special use cases.
The methods are summarized here and explained in full below.
### Summary
| Command | Description | Updates | Updates | Preserves |
: : : package : manifest : resources :
| -------------------- | ----------- | ------- | -------- | --------- |
| ffx component reload | stops, | yes | yes | yes |
: : updates, : : : :
: : and starts : : : :
| ffx component | destroys, | yes | yes | no |
: destroy/create/start : then starts : : : :
| ffx component run | destroys, | yes | yes | no |
: --recreate : then starts : : : :
| ffx component | stops and | no | no | yes |
: stop/start : starts : : : :
: : without : : : :
: : destroying : : : :
> * "Updates package" means that the code is updated when the package is
> reloaded.
> * "Updates manifest" means that the manifest cache is reloaded, updating the
> routing and other information contained in the FIDL files.
> * "Preserves resources" means that resources such as storage that would be
> released by a destroy command are instead preserved.
### Reload {#reloading}
Update your component's code and manifest while retaining resources with:
```posix-terminal
ffx component reload {{ '<var label="moniker">TARGET_MONIKER</var>' }}
```
This command will first shut down the component, then reload and restart it. The
command updates the package and manifest without destroying the component or
releasing resources.
The `reload` command preserves your component's resources such as storage. This
preservation can be helpful if it is slow to initialize, acquire, or recreate
resources in a specific state for debugging.
Reloading is also faster when destroying the component is expensive, such as
when it requires shutting down and restarting a session or the target
device/emulator.
### Destroy/create/start {#destroy_create_stop}
To fully reload the component and drop acquired resources, you can first destroy
the existing component instance, then restart it. Use:
```none {:.devsite-disable-click-to-copy}
$ ffx component destroy {{ '<var label="moniker">TARGET_MONIKER</var>' }}
$ ffx component create {{ '<var label="moniker">TARGET_MONIKER</var>' }} {{ '<var label="url">COMPONENT_URL</var>' }}
$ ffx component start {{ '<var label="moniker">TARGET_MONIKER</var>' }}
```
This sequence will reload both the package and the manifest, so code and
capability changes will be updated. However, destroying the component will also
free any resources it uses. This full reset may be what you want if your goal is
to start with a completely reinitialized component.
### Run --recreate {#run_recreate}
A convenient command that is analogous to the destroy/create/start sequence is
the `run` command with `--recreate`:
```posix-terminal
ffx component run {{ '<var label="moniker">TARGET_MONIKER</var>' }} {{ '<var label="url">COMPONENT_URL</var>' }} --recreate
```
### Stop/start {#start_stop}
Although it's not primarily a way to do updates, a side effect of just stopping,
then starting your component is that it will be partially updated.
```none {:.devsite-disable-click-to-copy}
$ ffx component stop {{ '<var label="moniker">TARGET_MONIKER</var>' }}
$ ffx component start {{ '<var label="moniker">TARGET_MONIKER</var>' }}
```
Assuming a package manager such as `ffx serve` is running, the latest version of
the component's code will be loaded and run. However, due to the way caching
works in the Fuchsia component framework, the manifest will not be updated. The
manifest contains your component's routing and other information as defined in
the `*.cm` files. So if you change your component's capability routes, stopping
and starting the component will not pick up these changes.
## `ffx-laboratory` {#ffx-laboratory}
The `ffx-laboratory` is a component collection that provides a restricted set of
capabilities for development. The following capabilities are offered to
components in this collection:
* [Protocol capabilities][capability-protocol]
* [`fuchsia.logger.LogSink`][fidl-logger]: Record log messages
* [`fuchsia.process.Launcher`][fidl-launcher]: Create new processes
* [Storage capabilities][capability-storage]
* `tmp`: Temporary storage (non-persistent)
* `data`: Emulated persistent storage backed by `/tmp`
* `cache`: Emulated cache storage backed by `/tmp`
* [Directory capabilities][capability-directory]
* `/dev`: Device driver `devfs` provided by Driver Manager
* `/boot`: Read-only `bootfs` provided by Component Manager
The `ffx-laboratory` is a [`transient`][manifest-collections] collection.
Component instances in this collection will persist even after they stop. To
destroy a component instance in this collection, use the `ffx component destroy`
command.
## Troubleshooting
This section contains common issues you may encounter while running your
components during development.
### Unable to resolve the component
When using `ffx component start` or `ffx component run` you may encounter the
following error if component framework cannot resolve the component instance:
```none {:.devsite-disable-click-to-copy}
$ ffx component run /core/ffx-laboratory:hello-world fuchsia-pkg://fuchsia.com/hello-world#meta/hello-world.cm
URL: fuchsia-pkg://fuchsia.com/hello-world#meta/hello-world.cm
Moniker: /core/ffx-laboratory:hello-world
Creating component instance...
Starting component instance...
Lifecycle protocol could not bind to component instance: InstanceCannotResolve
```
This occurs when the component URL does not resolve to a valid component
manifest.
To address this issue, verify the following:
* The [component URL][component-url] is formatted correctly.
* You have a [package server running][package-server].
* Your package server is registered with the target.
* Your [component is published][package-updates] to the package server.
### Component instance already exists
When using `ffx component create` or `ffx component run` you may encounter the
following error if the component instance already exists:
```none {:.devsite-disable-click-to-copy}
$ ffx component run /core/ffx-laboratory:hello-world fuchsia-pkg://fuchsia.com/hello-world#meta/hello-world.cm
URL: fuchsia-pkg://fuchsia.com/hello-world#meta/hello-world.cm
Moniker: /core/ffx-laboratory:hello-world
Creating component instance...
Component instance already exists. Use --recreate to destroy and recreate a new instance, or --name to create a new instance with a different name.
```
This occurs when the target moniker is already in use by another component
instance.
To address this issue, manually destroy the instance using the `ffx component
destroy` command:
```none {:.devsite-disable-click-to-copy}
$ ffx component destroy /core/ffx-laboratory:hello-world
Moniker: /core/ffx-laboratory:hello-world
Destroying component instance...
```
If you are using `ffx component run`, add the `--recreate` flag to destroy the
instance and recreate it:
```none {:.devsite-disable-click-to-copy}
$ ffx component run /core/ffx-laboratory:hello-world fuchsia-pkg://fuchsia.com/hello-world#meta/hello-world.cm --recreate
URL: fuchsia-pkg://fuchsia.com/hello-world#meta/hello-world.cm
Moniker: /core/ffx-laboratory:hello-world
Creating component instance...
Component instance already exists. Destroying...
Recreating component instance...
Starting component instance...
```
Alternatively, add the `--name` flag to create a new instance with a different
name:
```none {:.devsite-disable-click-to-copy}
$ ffx component run /core/ffx-laboratory:hello-world fuchsia-pkg://fuchsia.com/hello-world#meta/hello-world.cm --name hello-world-2
URL: fuchsia-pkg://fuchsia.com/hello-world#meta/hello-world.cm
Moniker: /core/ffx-laboratory:hello-world-2
Creating component instance...
Starting component instance...
```
[capability-directory]: /docs/concepts/components/v2/capabilities/directory.md
[capability-protocol]: /docs/concepts/components/v2/capabilities/protocol.md
[capability-storage]: /docs/concepts/components/v2/capabilities/storage.md
[component-select]: /docs/development/tools/ffx/commands/component-select.md
[component-url]: /docs/reference/components/url.md
[fidl-launcher]: https://fuchsia.dev/reference/fidl/fuchsia.process#Launcher
[fidl-logger]: https://fuchsia.dev/reference/fidl/fuchsia.logger#LogSink
[ffx-reference]: https://fuchsia.dev/reference/tools/sdk/ffx.md#component
[glossary.capability]: /docs/glossary/README.md#capability
[glossary.component-framework]: /docs/glossary/README.md#component-framework
[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-url]: /docs/glossary/README.md#component-url
[glossary.moniker]: /docs/glossary/README.md#moniker
[lifecycle-doc]: /docs/concepts/components/v2/lifecycle.md
[manifest-children]: https://fuchsia.dev/reference/cml#children
[manifest-collections]: https://fuchsia.dev/reference/cml#collections
[package-server]: /docs/development/build/package_update.md#connecting_host_and_target
[package-updates]: /docs/development/build/package_update.md#triggering_package_updates
[run-session]: /docs/development/sessions/building-and-running-a-session.md
[run-test]: /docs/development/testing/run_fuchsia_tests.md