blob: 7c51e07d0a3f7c05cf231acd0cd5c3f59d3550d7 [file] [log] [blame] [view] [edit]
# Migrating system components
This document provides instructions for migrating a system component from
[Components v1][glossary.components-v1] to
[Components v2][glossary.components-v2]. A *system component* is a component
that exists to provide services to other components in the system. Typically, in
Components v1 the mapping of service to component is registered in a
[sysmgr configuration file][sysmgr-config].
To migrate your system component from v1 to v2, do the following:
- [Background](#background)
- [Migrate the component manifest](#create-component-manifest)
- [Migrate the tests](#migrate-tests)
{% dynamic if user.is_googler %}
For important additional considerations and resources you should review
go/tq-cf-v2-migration-resources.
{% dynamic endif %}
Depending on the features your component supports, you may need to explore the
following sections for additional guidance:
- [Diagnostics capabilities](#diagnostics)
- [Other common situations](#other-situations)
- [Converting CMX features](#cmx-features)
For more details on the components migration effort, see
[State of the Components v2 Migration][components-migration-status].
## Background {#background}
You should familiarize yourself with the following topics:
- [Introduction to the Fuchsia Component Framework][components-intro]:
Components v2 comprises a set of concepts and APIs that are distinct from
Components v1 or traditional OS program models.
- [Introduction to the Test Runner Framework][trf-intro]: Test Runner
Framework is built on the Component Framework. You need to be familiar with
these concepts before you migrate tests.
## Migrate the component manifest {#create-component-manifest}
Create a minimal CML [CML file][glossary.component-manifest] and configure it
with GN so that it gets compiled and installed in your package.
Note: Unlike CMX, CML is JSON5, which allows comments and trailing commas. Take
advantage of this when writing your CML file!
1. Determine where your CMX file is located in the source tree (for example,
[`fonts.cmx`][example-fonts]). Create a file in the same directory that has
the same filename but with a `.cml` extension, with the following contents:
```json5
// fonts.cml
{
include: [
// Enable system logging
"syslog/client.shard.cml",
],
}
```
Note: Your CML file will live side-by-side with the CMX file for now. Do not
delete the CMX file yet.
1. Find the build rule that defines your component. Normally, this is a
`fuchsia_component` rule. For example, see the fonts
[`BUILD.gn`][example-package-rule].
```gn
fuchsia_component("fonts") {
manifest = "meta/fonts.cmx"
deps = [ ":font_provider" ]
}
```
1. Update the `manifest` element of the associated `fuchsia_component` rule to
point to your new `.cml` file instead:
```gn
fuchsia_component("fonts") {
manifest = "meta/fonts.cml"
deps = [ ":font_provider" ]
}
```
1. Build the target for your package:
```posix-terminal
fx build
```
You are ready to start writing your v2 component manifest.
### Adding the executable {#component-executable}
Add the [`program`][manifests-program] section of your CML file along with the
appropriate runner declaration.
Note: The [runner][glossary.runner] declaration is necessary even if your
component is launched using the ELF runner. This is the default in CMX but must
be explicitly specified in CML.
```json
// fonts.cmx
{
"include": [
"syslog/client.shard.cmx"
],
{{ '<strong>' }}"program": {
"binary": "bin/font_provider"
},{{ '</strong>' }}
...
}
```
```json5
// fonts.cml
{
include: [
// Enable system logging
"syslog/client.shard.cml",
],
{{ '<strong>' }}program: {
runner: "elf",
binary: "bin/font_provider",
},{{ '</strong>' }}
}
```
### Declaring required services {#required-services}
Add [`use`][manifests-use] declarations to your CML file. These are the
approximate equivalent of the [`services`][cmx-services] list in CMX.
```json
// fonts.cmx
{
"include": [
"syslog/client.shard.cmx"
],
"program": {
"binary": "bin/font_provider"
},
{{ '<strong>' }}"sandbox": {
"services": [
"fuchsia.logger.LogSink",
"fuchsia.pkg.FontResolver"
]
...
}{{ '</strong>' }}
}
```
Convert each element of the `services` list to a `use` declaration for the
corresponding service `protocol`.
```json5
// fonts.cml
{
include: [
// Enable system logging
"syslog/client.shard.cml",
],
program: {
runner: "elf",
binary: "bin/font_provider",
},
{{ '<strong>' }}use: [
{
protocol: [ "fuchsia.pkg.FontResolver" ],
},
],{{ '</strong>' }}
}
```
### Exposing available services {#available-services}
In [Components v1][glossary.components-v1], you typically declare information
about services exposed by a component in a
[sysmgr configuration file][sysmgr-config]. These files are referenced by
`config_data` targets in the build, and specify mappings of services to
components in the `sys` [environment][glossary.environment].
Note: The most common location of this service mapping is
[`services.config`][example-services-config], which defines service mappings
that apply to every product configuration.
1. Identify all service mappings, if any, for your component. You can use
[CodeSearch][code-search] to find service mappings. Here is a
[sample search][sysmgr-config-search].
```json
// services.config
{
"services": {
...
"fuchsia.fonts.Provider": "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx",
...
}
}
```
1. For each service mapping, add an [`expose`][manifests-expose] declaration
and a corresponding [`capabilities`][manifests-capabilities] entry with the
service `protocol`.
```json5
// fonts.cml
{
include: [
// Enable system logging
"syslog/client.shard.cml",
],
program: {
runner: "elf",
binary: "bin/font_provider",
},
{{ '<strong>' }}capabilities: [
{
protocol: [ "fuchsia.fonts.Provider" ],
},
],{{ '</strong>' }}
use: [
{
protocol: [ "fuchsia.pkg.FontResolver" ],
},
],
{{ '<strong>' }}expose: [
{
protocol: "fuchsia.fonts.Provider",
from: "self",
},
],{{ '</strong>' }}
}
```
1. Build your updated package:
```posix-terminal
fx build
```
1. Verify that your package includes the compiled v2 component manifest (with a
`.cm` extension).
```posix-terminal
ffx scrutiny shell "search.components --url {{ '<var label="component">my_component.cm</var>' }}$"
```
Note: it is valid to `use` from `self` in the unusual case that your component
both consumes and publishes the same protocol. You'll know this is the case
when the "services" section in your `.cmx` references a protocol that is mapped
to the same component's URL in a `services.config` file.
## Migrate the tests {#migrate-tests}
In most cases, tests for v1 components are themselves v1 components. The first
step is to identify all tests that exercise your component’s functionality.
Typically this is a `fuchsia_test_package` or `fuchsia_unittest_package` rule.
For example, see the fonts [`BUILD.gn`][example-package-rule].
A test may include or depend on components that are separate from the test
component. Here are some things to look for:
- Is your test self-contained in one file (a unit test)? Or does it launch
other components (an integration test)?
- Does your test have a CMX with [`fuchsia.test facets`][fuchsia-test-facets],
such as `injected-services` or `system-services`?
- Does your test create environments in-process? If so, does it create a
separate environment for each test case?
### Update the test configuration {#update-test-config}
The migration procedure varies depending on the testing framework features in
your v1 component:
- [Test has no service dependencies](#no-injected-services): The test component's
manifest is generated by a `fuchsia_unittest_*` GN rule, or the CMX does not
contain [fuchsia.test facets][fuchsia-test-facets].
- [Test depends on system services](#system-services): The test has a CMX that
contains [`system-services`][system-services] test facets.
- [Test depend on injected services](#injected-services): The test has a CMX that
contains [`injected-services`][fuchsia-test-facets] test facets.
Note: For more details on the services and capabilities provided to components
by the Test Runner Framework, see the
[test manager documentation][trf-test-manager].
#### No service dependencies {#no-injected-services}
Test components that do not use [fuchsia.test facets][fuchsia-test-facets] can
migrate to Components v2 using the same basic procedure described in
[Migrate the component manifest](#create-component-manifest).
Consider the following example test component:
```json
// my_component_test.cmx
{
"include": [
"syslog/client.shard.cmx"
],
"program": {
"binary": "bin/my_component_test"
}
}
```
To migrate this test to the Test Runner Framework, do the following:
1. Create a CML file that points to the test binary that includes the
appropriate [test runner][trf-test-runners]:
Note: See [test runners][trf-provided-test-runners] that are provided by the
framework.
```json5
// my_component_test.cml
{
include: [
// Select the appropriate test runner shard here:
// rust, gtest, go, etc.
"//src/sys/test_runners/rust/default.shard.cml",
// For common includes such as the below, typically you will find
// a `.cmx` and a `.cml` equivalent at the same path.
"syslog/client.shard.cml",
],
program: {
binary: "bin/my_component_test",
}
}
```
1. Update the build definitions for your test to reference the new CML file:
```gn
fuchsia_unittest_package("my_component_tests") {
manifest = "meta/my_component_test.cml"
deps = [ ":my_component_test" ]
}
```
In the example above, the test component's manifest is simple enough that it can
be generated for you at build time by `fuchsia_unittest_package()` or
`fuchsia_unittest_component()`.
This is the [preferred practice][unit-tests-with-generated-manifests] for simple
unit tests.
To allow the GN target to generate your CML file, simply edit it to remove the
`manifest`.
```gn
fuchsia_unittest_package("my_component_tests") {
{{ '<strike>' }}manifest = "meta/my_component_test.cml"{{ '</strike>' }}
deps = [ ":my_component_test" ]
}
```
#### System service dependencies {#system-services}
For tests that use [`system-services`][system-services] test facets, consider if
they can be converted to [injected services](#injected-services) instead.
Injecting services is the preferred method because it promotes hermetic test
behavior.
For certain non-hermetic tests, the Test Runner Framework provides the test
realm with the following services:
| Service | Description |
| ----------------------------------- | ------------------------------------- |
| `fuchsia.scheduler.ProfileProvider` | Profile provider for scheduler |
| `fuchsia.sysmem.Allocator` | Allocates system memory buffers |
| `fuchsia.tracing.provider.Registry` | Register to trace provider |
| `fuchsia.vulkan.loader.Loader` | Vulkan library provider |
| `fuchsia.sys.Loader` | CFv1 loader service to help with |
: : migration. :
| `fuchsia.sys.Environment` | CFv1 environment service to help with |
: : migration. :
Consider the following example test component that uses a single system service,
`fuchsia.sysmem.Allocator`:
```json
// my_component_test.cmx
{
"facets": {
"fuchsia.test": {
"system-services": [
"fuchsia.sysmem.Allocator"
]
}
},
"program": {
"binary": "bin/my_component_test"
},
"sandbox": {
"services": [
"fuchsia.sysmem.Allocator"
]
}
}
```
To migrate this test to the Test Runner Framework, declare each available system
service with the other [required services](#required-services) in your test
component manifest. Since this test uses the `fuchsia.sysmem.Allocator`
system capability, it also needs to be marked as `hermetic: "false"` as shown
below.
```json5
// my_component_test.cml
{
include: [
// Select the appropriate test runner shard here:
// rust, gtest, go, etc.
"//src/sys/test_runners/rust/default.shard.cml",
],
program: {
binary: "bin/my_component_test",
},
{{ '<strong>' }}facets: {
"fuchsia.test": {
type: "system"
},
},
use: [
{
protocol: [ "fuchsia.sysmem.Allocator" ],
},
],{{ '</strong>' }}
}
```
#### Injected service dependencies {#injected-services}
For tests that use other [fuchsia.test facets][fuchsia-test-facets], such as
`injected-services`, your test component manifest must declare each dependent
component and route the provided capabilities to the test component.
In the following example, suppose there's a single injected service,
`fuchsia.pkg.FontResolver`:
```json
// my_component_test.cmx
{
"facets": {
"fuchsia.test": {
"injected-services": {
"fuchsia.pkg.FontResolver":
"fuchsia-pkg://fuchsia.com/font_provider_test#meta/mock_font_resolver.cmx"
}
}
},
"program": {
"binary": "bin/my_component_test"
},
"sandbox": {
"services": [
"fuchsia.pkg.FontResolver"
]
}
}
```
To migrate this test to the Test Runner Framework, do the following:
1. Create a CML file for the test component that points to the test binary and
includes the appropriate [test runner][trf-test-runners]:
Note: See [test runners][trf-provided-test-runners] that are provided by the
framework.
```json5
// my_component_test.cml (test component)
{
include: [
// Select the appropriate test runner shard here:
// rust, gtest, go, etc.
"//src/sys/test_runners/rust/default.shard.cml",
],
program: {
// Binary containing tests
binary: "bin/font_provider_test",
},
use: [
...
],
}
```
1. You need CML files for each component that provides a capability needed in
the test. If there is an existing CML file for the component providing the
injected service, you may be able to reuse it. Otherwise **if the mock
component is being ported to v2**, create a new CML file. If the **mock
component has not been ported to v2 yet**, wrap the component using
`cmx_runner`.
* {CML component}
```json5
// mock_font_resolver.cml (capability provider)
{
program: {
runner: "elf",
binary: "bin/mock_font_resolver",
},
use: [
// mock_font_resolver's dependencies.
{
protocol: [ "fuchsia.proto.SomeProtocol" ],
},
],
capabilities: [
{
protocol: [ "fuchsia.pkg.FontResolver" ],
},
],
expose: [
{
protocol: "fuchsia.pkg.FontResolver",
from: "self",
},
],
}
```
* {Wrapped CMX component}
```json5
// mock_font_resolver.cml (capability provider)
{
include: [
// Use `cmx_runner` to wrap the component.
"//src/sys/test_manager/cmx_runner/default.shard.cml",
"syslog/client.shard.cml",
],
program: {
// wrap v1 component
legacy_url: "fuchsia-pkg://fuchsia.com/font_provider_test#meta/mock_font_resolver.cmx",
},
use: [
// if `mock_font_resolver.cmx` depends on some other protocol.
{
protocol: [ "fuchsia.proto.SomeProtocol" ],
},
// Note: Wrapped legacy component can only use protocol capabilities.
],
// expose capability provided by mock component.
capabilities: [
{
protocol: [ "fuchsia.pkg.FontResolver" ],
},
],
expose: [
{
protocol: "fuchsia.pkg.FontResolver",
from: "self",
},
],
}
```
Note: The CML files for the capability providers can be distributed in the
same package that contained the v1 test. Follow the same instructions in
[Migrate the component manifest](#create-component-manifest) that you used
to package your component.
1. Add the capability provider(s) as children of the test component, and route
the capabilities from each provider.
```json5
// my_component_test.cml (test component)
{
...
// Add capability providers
children: [
{
name: "font_resolver",
url: "#meta/mock_font_resolver.cm",
},
],
// Route capabilities to the test
use: [
{
protocol: [ "fuchsia.pkg.FontResolver" ],
from: "#font_resolver",
},
],
offer: [
{
// offer dependencies to mock font provider.
protocol: [ "fuchsia.proto.SomeProtocol" ],
from: "#some_other_child",
},
],
}
```
1. Package the test component and capability provider(s) together into a
single hermetic `fuchsia_test_package()`:
* {CML component}
```gn
# Test component
fuchsia_component("my_component_test") {
testonly = true
manifest = "meta/my_component_test.cml"
deps = [ ":bin_test" ]
}
fuchsia_component("mock_font_resolver") {
testonly = true
manifest = "meta/mock_font_resolver.cml"
deps = [ ":mock_font_resolver_bin" ]
}
# Hermetic test package
fuchsia_test_package("my_component_tests") {
test_components = [ ":my_component_test" ]
deps = [ ":mock_font_resolver" ]
}
```
* {Wrapped CMX component}
```gn
# Test component
fuchsia_component("my_component_test") {
testonly = true
manifest = "meta/my_component_test.cml"
deps = [ ":bin_test" ]
}
fuchsia_component("mock_font_resolver") {
testonly = true
manifest = "meta/mock_font_resolver.cml"
deps = [ {{ '<var label="legacy_component">"//path/to/legacy(v1)_component"</var>' }} ]
}
# Hermetic test package
fuchsia_test_package("my_component_tests") {
test_components = [ ":my_component_test" ]
deps = [ ":mock_font_resolver" ]
}
```
For more details on providing external capabilities to tests, see
[Integration testing topologies][integration-test].
### Verify the migrated tests {#verify-tests}
Build and run your test and verify that it passes. Like any other test, use `fx
test` to invoke the test:
```posix-terminal
fx build && fx test my_component_tests
```
Your component is now tested in Components v2.
If your test doesn't run correctly or doesn't start at all, try following the
advice in [Troubleshooting components][troubleshooting-components].
## Add the new component {#add-component-to-topology}
Now you're ready to add your new component to the
[v2 component topology][components-topology]. This defines the relationship
between your component and the rest of the system.
Take another look at any sysmgr configuration file(s) that defines service
mappings to your component, which you identified while
[migrating the component manifest](#create-component-manifest). The steps below
refer to the collection of all these services as your component’s "exposed
services".
```json
// services.config
{
"services": {
...
"fuchsia.fonts.Provider": "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx",
...
}
}
```
### Add the component to core {#add-component-to-core}
- [Add a core realm shard](#add-core-shard): Your component is **not** present
in *all* products (eg. maybe it is present on workstation, but not
terminal). Using a [core realm shard][core-realm-rfc] allows the component
to be safely excluded where it isn't available.
- [Add directly to core](#add-core-direct): Your component is present on all
product and test build configurations. In this case you can add the
component directly to `core.cml`.
#### Add a core realm shard {#add-core-shard}
1. Create a [manifest shard][manifests-shard]. A manifest shard uses generally
the syntax as a manifest, but *may* reference objects that don't exist
within the manifest itself. In this case we reference the `session-manager` child
which is not defined here, but we know is defined in `core`'s manifest.
```json5
// component.core_shard.cml
{
children: [
{
name: "font_provider",
url: "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cm",
},
],
offer: [
{
protocol: "fuchsia.fonts.Provider",
from: "#font_provider",
to: [ "#session-manager" ],
},
],
}
```
1. Create a target in your `BUILD.gn` that defines the `core_shard`.
```gn
# font_provider/BUILD.gn
import("//src/sys/core/build/core_shard.gni")
core_shard("font_provider_shard") {
shard_file = "component.core_shard.cml"
}
```
1. Add the core realm shard to the appropriate products. For example, you can
add the component to the workstation product by modifying
`//products/workstation.gni` by adding the build target path to the
`core_realm_shards` array. If your component is present on all products that
derive from core and you are adding it via a shard, modify
`//products/core.gni`.
```gn
# //products/workstation.gni
...
core_realm_shards += [
...
"//path/to/font_provider:font_provider_shard",
]
...
```
#### Add directly to core {#add-core-direct}
Add your component as a child instance of the [`core.cml`][cs-core-cml]
component, and offer its exposed services to dependent components. You need to choose a name
for your component instance and identify its component URL (you should be able
to get this from the config mapping).
```json5
// core.cml
{
children: [
...
{
name: "font_provider",
url: "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cm",
},
],
offer: [
...
{
protocol: "fuchsia.fonts.Provider",
from: "#font_provider",
to: [ "#session-manager" ],
},
],
}
```
#### Learn your component moniker {#component-moniker}
If you added your component to `core.cml` as explained here, then it's easy to
infer your component [moniker][moniker] as `/core/component_name` where
`component_name` is the name of the child you added to `core.cml`.
You can see this hierarchy using `ffx component list` as well:
```
/
bootstrap
archivist
...
core
...
appmgr
app
sysmgr.cmx
sys
build-info.cmx
cobalt.cmx
...
battery_manager
font_provider
...
startup
```
### Make your component's services available to v1 components {#route-to-v1}
It is very common for there to be components in the v1 `sys` realm that depend
on your component's exposed services, or for them to be used by
[shell binaries](#shell-binaries). Make your component's services available to
the v1 `sys` realm by adding a declaration like the following to your core
realm shard or `core.cml`.
```json5
// core.cml
{
use: [
{
protocol: "fuchsia.fonts.FontProvider",
from: "#font_provider",
},
],
}
```
Note: You do _not_ need to offer the service to `appmgr`. `core` itself proxies
to and from the v1 `sys` realm, which is why we have `core` `use` the service.
### Offer services to your component {#offer-services}
To work properly, your component must be offered all services that appear in its
[`use`][manifests-use] declarations. These services may be provided by v1 or v2
components. Look in the sysmgr config files and `core.cml` to find the
originating components ([example search][sysmgr-config-search]).
There are three possible cases:
- [v1 component provides service](#v1-component-provides-service): The
provider of the service is a v1 component.
- [v2 component in `core.cml` provides service](#v2-core-cml-provides-service):
The provider of the service is a v2 component that's a child of `core.cml`.
- The provider of the service is a v2 component that's not child of
`core.cml`. If this is the case, reach out to
[component-framework-dev][cf-dev-list] for assistance.
Note: You must also route all services requested by any manifest shards listed
in your manifest's [`include`][manifests-include].
#### v1 component provides service {#v1-component-provides-service}
You’ll reach this case if a mapping for the service exists in a sysmgr config
file. To make the service available to your component, you offer it from `core`:
```json5
// core.cml
{
offer: [
...
{
protocol: "fuchsia.pkg.FontResolver",
from: "self",
to: [ "#font_provider" ],
},
...
],
}
```
Note: You do _not_ offer the service from `appmgr`. `core` itself proxies
to and from the v1 `sys` realm, which is why we have `core` offer the service.
#### v2 component in core.cml provides service {#v2-core-cml-provides-service}
Route the service from the component in `core` that exposes it to your component
in `core.cml`:
```json5
// core.cml
{
offer: [
...
{
protocol: [ "fuchsia.pkg.FontResolver" ],
from: "#font_resolver",
to: [ "#font_provider" ],
},
...
],
}
```
### Resolve dependency cycles {#dependency-cycles}
In Components v1, `appmgr` represents a collection of multiple components with
many capabilities. This increases the chance that a v2 component routes multiple
capabilities into and out of `appmgr` for a given component. Components that
both offer services to `appmgr` and consume services offered by `appmgr` create
a **dependency cycle** that you may need to resolve during the migration.
```none
Strong dependency cycles were found. Break the cycle by removing a dependency or
marking an offer as weak. Cycles: { { ... }, { ... } }
```
To avoid build-time errors resulting from dependency cycles, apply the
`weak_for_migration` tag to one of the capability routes. For example:
```json5
// core.cml
{
offer: [
{
protocol: [ "fuchsia.pkg.FontResolver" ],
from: "#appmgr",
to: [ "#font_provider" ],
{{ '<strong>' }}dependency: "weak_for_migration",{{ '</strong>' }}
},
{
protocol: "fuchsia.fonts.Provider",
from: "#font_provider",
to: [ "#appmgr" ],
},
]
}
```
You can apply `weak_for_migration` to either capability in a dependency cycle.
Determine which side is most appropriate for your component. In most cases, the
convention is to apply `weak_for_migration` on the capability offered from
`appmgr` until everything is migrated out of Components v1.
### Remove sysmgr configuration entries {#remove-config-entries}
Before you test your component, remove the service mappings in
[`services.config`][example-services-config] and other sysmgr configuration
files you identified previously.
Without this step, sysmgr will report errors attempting to load services from
your v1 component instead of using the new capabilities routed to it through
`core.cml`.
```json
// services.config
{
"services": {
...
// Delete these lines
"fuchsia.fonts.Provider": "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cmx",
...
}
}
```
### Test your component {#test-component}
Manually verify that your component and its dependencies still work. Perform
manual verification of capability routing as it is usually outside the scope of
hermetic tests. The `verify routes` command built into [scrutiny][fx-scrutiny]
reports routing errors in the static component topology of the current build.
This can help you find missing `offer` or `expose` declarations before
performing runtime tests.
```posix-terminal
ffx scrutiny verify routes
```
Note: Scrutiny can only verify routes in the v2 component topology. It cannot
look into `appmgr` and the `sys` environment to review usage from v1 components.
If your component manifest contains additional system features that haven't been
migrated at this point, see [Other common situations](#other-situations) and
[Converting CMX features](#cmx-features) for additional guidance.
If your component or one of the components that depends on it isn't working
correctly, try following the advice in
[Troubleshooting components][troubleshooting-components].
Once your component has been registered in the v2 topology and all tests have
been converted, you can delete the Components v1 definition of your component.
Find and remove any CMX files for your component and its tests, including any
remaining references to it from the package rule(s) you modified when you
[migrated the component manifest](#create-component-manifest).
## Diagnostics capabilities {#diagnostics}
This section provides guidance on migrating the capabilities for diagnostics
features to Components v2.
### Inspect {#inspect}
{% dynamic if user.is_googler %}
Note: If your component shares Inspect data in product feedback reports, you may
also need to update the approved selectors to reference the new component
moniker. For more details on updating feedback selectors, see
[go/tq-diagnostics-migration](http://go/tq-diagnostics-migration).
{% dynamic endif %}
If your component is using [Inspect][inspect], you'll need to expose additional
information to the framework. You can quickly determine if your component uses
Inspect by looking for one of the following library dependencies in the
component's `BUILD.gn`:
- `//sdk/lib/sys/inspect/cpp`
- `//src/lib/diagnostics/inspect/rust`
- `dart_package_label.fuchsia_inspect`
In Components v1, `appmgr` provides access to the component's `/diagnostics`
directory, which contains Inspect data. Components v2 requires a component to
explicitly expose `/diagnostics` to the framework. This allows the
[Archivist][archivist] to read Inspect data for snapshots,
[`ffx inspect`][ffx-inspect], and more.
Note: For more details on the differences in data collection between Components
v1 and Components v2, see the [Archivist documentation][archivist].
When [migrating the component manifest](#create-component-manifest), you can add
Inspect capabilities to your v2 component by including the following manifest
shard:
```json5
// my_component.cml
{
// Expose the diagnostics directory capability for Inspect
include: [ "inspect/client.shard.cml" ],
...
}
```
#### Component moniker for selectors
As [explained previously](#component-moniker), it's possible to infer the
component moniker using `ffx component list`. Alternatively you can use `ffx
inspect list` to see available components for querying inspect data. Your
component moniker should appear in the `ffx inspect list` output up after
adding the `client.shard.cml` above.
#### Inspect data in tests {#inspect-tests}
If your test components read Inspect diagnostics data, migrate to the
`fuchsia.diagnostics.ArchiveAccessor` service provided by the
[Archivist][archivist]. Consider the following approaches you may be currently
using from Components v1 to accomplish this:
- Injected services. The test CMX contains
`fuchsia.diagnostics.ArchiveAccessor` as an `injected-service`, reading
isolated inspect data from an embedded Archivist limited to test components:
```json
{
"fuchsia.test": {
"injected-services": {
"fuchsia.diagnostics.ArchiveAccessor":
"fuchsia-pkg://fuchsia.com/archivist-for-embedding#meta/archivist-for-embedding.cmx",
...
}
},
...
}
```
It means the test is reading isolated inspect data from an embedded
Archivist that only sees test components.
- Directly from the [Hub](#hub).
In v2, there's an Archivist running inside each test. Instead of instantiating
another Archivist in your test, you can use that embedded Archivist Accessor
protocol directly in your test. Therefore you'll need to do the following:
1. When [migrating tests](#migrate-tests), add the protocol capability to your
test component:
```json5
// my_component_test.cml (test component)
{
use: [
{
protocol: [ "fuchsia.diagnostics.ArchiveAccessor" ],
},
]
}
```
1. Update your program to use the `ArchiveReader` library, which is available
in [C++][archive-cpp], [Rust][archive-rust], and [Dart][archive-dart]. See the
[Inspect Codelab][archive-codelab] for more details on using these libraries.
Note: For components in other languages, use the `ArchiveAccessor`
[FIDL protocol][archive-fidl] directly.
1. Update any monikers used in your test's diagnostic selectors.
- If you declare a child component in the test CML, check the
[Integration Testing docs][integration-test-monikers] to learn more about your moniker.
- If you are using `RealmBuilder`, check the [Realm Builder docs][realm-builder-monikers] to
learn more about your moniker.
### Logging {#logging}
If your component requires access to [logging][logs], you'll need to declare the
`fuchsia.logger.LogSink` capability in your manifest. In Components v1, you may
have included `diagnostics/syslog/client.shard.cmx` or referenced the protocol
directly under `services` in your CMX file.
You can add syslog capabilities to your v2 component by including the following
manifest shard:
```json5
// my_component.cml
{
// Expose the LogSink capability for syslog
include: [ "syslog/client.shard.cml" ],
...
}
```
Additionally, Components v1 redirects `stderr` and `stdout` to `debuglog`, but
in Components v2 they have no default destination. The `debuglog` is typically
used for low-level debugging information from the kernel and device drivers. If
your component writes log data to these streams, consider the following:
- [Redirect to syslog](#syslog-redirect): Forward print statements to use the
system's standard `syslog` buffer instead. This buffer is larger and capable
of attributing logs per-component.
- [Redirect to debuglog](#debuglog-redirect): If you have integration tests or
other use cases that require preserving the default Components v1 behavior
for log messages, direct the streams back to the `debuglog` buffer.
#### Redirecting to syslog {#syslog-redirect}
To send `stderr` and `stdout` to [syslog][syslog] in your v2 component, you'll
need to configure the ELF runner to forward the streams. This enables forwarding
for all print statements, including those generated by libraries or runtime
code.
When [migrating your component manifest](#create-component-manifest), include
the following manifest shard to enable forwarding:
```json5
// my_component.cml
{
// Enable forwarding of stdio to syslog
include: [ "syslog/elf_stdio.shard.cml" ],
...
}
```
Note: Logging directly to `syslog` from your code provides additional features
to your component, such as severity levels. To take advantage of these features,
consider migrating your code to use the logging libraries highlighted in the
[`syslog` documentation][syslog].
#### Redirecting to debuglog {#debuglog-redirect}
Your component may have external dependencies that rely on log messages in
[debuglog][debug-log]. One common use case is integration tests that directly
parse log messages from the `stdout` of an emulator process using the
[emulatortest][emulatortest] framework. In these cases, you'll need to manually
direct log messages back to the `debuglog` buffer.
1. When [migrating your component manifest](#create-component-manifest),
request the `fuchsia.boot.WriteOnlyLog` capability.
```json5
// my_component.cml
{
use: [
...
{
protocol: [
"fuchsia.boot.WriteOnlyLog",
],
},
],
}
```
1. When [adding your component](#add-component-to-topology), add the following
to offer this capability to your component from `core`:
```json5
// core.cml
{
offer: [
...
{
protocol: [ "fuchsia.boot.WriteOnlyLog" ],
from: "parent",
to: [ "#my_component" ],
},
],
}
```
1. Direct `stderr` and `stdout` to `debuglog` in your program. You can use
libraries for the initialization if your component is written in
[Rust][debug-log-rust] or [C++][debug-log-cpp].
Note: If the component isn't written in C++ or Rust you can use the existing
libraries as a template for how to perform the initialization.
### Hub {#hub}
The hub provides access to detailed structural information about component
instances at runtime. In Components v1, `appmgr` provides the [v1 Hub][hub-v1]
through a specific directory structure populated in your component's namespace
under `/hub`. In Components v2, many v1 Hub use cases have preferred alternative
approaches.
When migrating to Components v2, consider the following alternatives:
- [Observing lifecycle events](#events): Clients watching the filesystem to
observe component instance changes should use
[event capabilities][event-capabilities] instead.
- [Reading inspect data](#inspect-tests): Clients reading Inspect data from
`out/diagnostics` should migrate to the
`fuchsia.diagnostics.ArchiveAccessor` service instead.
- [Connecting to exposed services](#injected-services): Clients connecting to
services exposed through a component's `out/svc` directory should route
these services and capability providers into their tests instead, similar to
`injected-services`.
For other use cases, follow the instructions in this section to migrate to the
[v2 Hub][hub-v2] provided by Component Manager.
Note: Features of the Hub are designed to support test components only. If you
need to access the Hub outside of the test realm, reach out to
[component-framework-dev][cf-dev-list] for assistance.
#### Route the hub directory
When [migrating tests](#migrate-tests), you'll need to route the `hub`
[directory capability][directory-capabilities] to your test component if any
components in the test realm need to read data from the v2 Hub.
Following the example in [Test uses injected services](#injected-services), add
the `hub` directory capability to your CML file:
```json5
//my_component_test.cml
{
use: [
{
directory: "hub",
from: "framework",
rights: [ "r*" ],
path: "/hub",
},
]
}
```
#### Update hub reference paths
Update your code to reference the content path from the v2 Hub directory
structure. Here are some examples of path differences between the Hub
implementations:
| [v1 Hub][hub-v1] Path | [v2 Hub][hub-v2] Path |
| --------------------- | --------------------- |
| `/hub/c/{{ '<var>' }}component-name{{ '</var>' }}/{{ '<var>' }}instance-id{{ '</var>' }}/url` | `/hub/url` |
| `/hub/c/{{ '<var>' }}component-name{{ '</var>' }}/{{ '<var>' }}instance-id{{ '</var>' }}/in/{{ '<var>' }}svc-path{{ '</var>' }}` | `/hub/exec/in/{{ '<var>' }}svc-path{{ '</var>' }}` |
| `/hub/c/{{ '<var>' }}component-name{{ '</var>' }}/{{ '<var>' }}instance-id{{ '</var>' }}/process-id` | `/hub/exec/runtime/elf/process-id` |
| `/hub/c/{{ '<var>' }}child-component{{ '</var>' }}` | `/hub/children/{{ '<var>' }}child-component{{ '</var>' }}` |
Note: The `hub` directory routed to your component is scoped to the current
realm. To access hub contents from the parent realm, route the hub from `parent`
instead of `framework`. This feature is not available with the v1 Hub.
## Other common situations {#other-situations}
This section provides guidance on migrating components that use other common
capabilities or features.
### Resolvers
If your component is not part of the `base` package set for your product, you
must route the `universe` resolver to it. Resolvers are routed to components
using environments, and `core.cml` has a shared environment named
`full-resolver-env` for components outside of `base`.
Use the `list-packages` command to report the package sets where your component
package is included.
```posix-terminal
fx list-packages --verbose {{ '<var label="package name">my-package</var>' }}
```
If the package is not listed with the `base` tag, follow the remaining
instructions in this section.
When [adding your component](#add-component-to-topology), assign the shared
`full-resolver-env` as your component's `environment`.
```json5
// core.cml
{
children: [
...
{
name: "my_component",
url: "fuchsia-pkg://fuchsia.com/my-pkg#meta/my_component.cm",
{{ '<strong>' }}environment: "#full-resolver-env",{{ '</strong>' }}
},
],
}
```
### Start on boot {#start-on-boot}
Note: Starting component on boot is an area of active development. It is highly
recommended that you reach out to [component-framework-dev][cf-dev-list] before
migrating this behavior.
If your component appears in a sysmgr config `startup_services` or `apps` block
you should make your component an `eager` component in its parent's manifest.
```json5
// parent.cml
{
children: [
...
{
name: "font_provider",
url: "fuchsia-pkg://fuchsia.com/fonts#meta/fonts.cm",
startup: "eager",
},
],
}
```
Additionally you need to ensure that all your component's ancestors up to
`/core` are `eager` components. If your component is present on *all* products
that derive from the `core` you can [add it to core directly](#add-core-direct),
otherwise you need to use [core realm variability](#add-core-shard) to allow
products without your component to continue to boot.
The `eager` component should be in the base package set; `eager` is generally
incompatible with being outside the base package set.
For more details on how `eager` impacts component startup see,
[lifecycle][eager-lifecycle] and [component manifests][eager-manifest].
### critical_components {#critical-components}
[`critical_components`][sysmgr-critical-components] is a sysmgr feature that
allows a component to mark itself as critical to system operation:
```json
{
...
"critical_components": [
"fuchsia-pkg://fuchsia.com/system-update-checker#meta/system-update-checker.cmx"
]
}
```
The equivalent feature in Components v2 is called "reboot-on-terminate". If your
component appears in `critical_components` you should mark it as `on_terminate:
reboot` in the parent component's 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",
},
],
}
```
Also, you'll need to add the component's moniker to component manager's security
policy allowlist at
[`//src/security/policy/component_manager_policy.json5`][src-security-policy]:
```
// //src/security/policy/component_manager_policy.json5
{
security_policy: {
...
child_policy: {
reboot_on_terminate: [
...
"/core/system-update-checker",
],
},
},
}
```
### Shell binaries
Your project may contain a `fuchsia_shell_package()` build target designed to
execute in a shell environment. Many of these packages also contain a CMX file
to support invoking the binary as a v1 component. When
[routing your services](#route-to-v2) to the `sys` environment, include any
services required by shell binaries.
Note: If your component requires `shell-commands` directory access to invoke
shell binaries, see [directory features](#directory-features) for more details.
Shell binaries are run in the `sys` [environment][glossary.environment], and
have access to all the capabilities provided there. Capabilities are not defined
by the CMX manifest file unless shell binaries are invoked as a component using
the `run` command.
When working with shell binaries, consider the following:
- If you only need access to the binary through a shell interface, remove the
unused CMX file entirely. Do not replace it with a corresponding CML file.
- If you need to access the binary from somewhere else in the v2 component
topology (such as tests), migrate the functionality into a new v2 component
instead.
Note: There is no v2 equivalent of using `run` to invoke a shell binary **as a
component**. If you require this feature for your component, reach out to
[component-framework-dev][cf-dev-list].
### Lifecycle
If your component serves the `fuchsia.process.lifecycle.Lifecycle` protocol,
follow these instructions to migrate to the lifecycle handle provided by the
ELF runner in Components v2.
1. Remove your component's entry in the `appmgr`
[allowlist][cs-appmgr-allowlist]:
```cpp
// Remove this entry.
lifecycle_allowlist.insert(component::Moniker{
.url = "fuchsia-pkg://fuchsia.com/my_package#meta/my_component.cmx", .realm_path = {"app", "sys"}});
```
1. When [migrating your component manifest](#create-component-manifest), add
the lifecycle stop event:
```json5
// my_component.cml
{
include: [
"syslog/client.shard.cml",
],
program: {
runner: "elf",
binary: "bin/my_binary",
{{ '<strong>' }}lifecycle: { stop_event: "notify" },{{ '</strong>' }}
},
...
}
```
1. Get the `fuchsia.process.lifecycle.Lifecycle` channel provided by the ELF
runner:
* {Rust}
```rust
use fuchsia_runtime::{take_startup_handle, HandleInfo, HandleType};
let lifecycle_channel = take_startup_handle(HandleInfo::new(HandleType::Lifecycle, 0));
// Serve the Lifecycle protocol on `lifecycle_channel`
```
A more complete sample is available in the [examples][rust-lifecycle].
* {C++}
```cpp
#include <lib/zx/channel.h>
#include <zircon/processargs.h>
zx::channel lifecyecle_channel = zx_take_startup_handle(PA_LIFECYCLE);
// Serve the Lifecycle protocol on `lifecycle_channel`
```
You can refer to [fshost code][fshost-lifecycle] for a sample
implementation.
More information about the Lifecycle protocol is available in the [ELF runner
documentation][elf-runner-docs].
## Converting CMX features {:#cmx-features}
This section provides guidance on migrating additional CMX
[`sandbox`][cmx-services] features. If there's a feature in your CMX file that's
not in this list, reach out to [component-framework-dev][cf-dev-list].
### Storage features {#storage-features}
If your component uses any of the following features, follow the instructions in
this section to migrate storage access:
| Feature | Description | Storage Capability | Path |
| ----------------------------- | ----------- | ------------------ | -------- |
| `isolated-persistent-storage` | Isolated | `data` | `/data` |
: : persistent : : :
: : storage : : :
: : directory : : :
| `isolated-cache-storage` | Managed | `cache` | `/cache` |
: : persistent : : :
: : storage : : :
: : directory : : :
| `isolated-temp` | Managed | `temp` | `/tmp` |
: : in-memory : : :
: : storage : : :
: : directory : : :
These features are supported in v2 components using
[storage capabilities][storage-capabilities].
#### Declare the required storage capabilities
When [migrating your component manifest](#create-component-manifest), add the
following to your CML file:
```json5
// my_component.cml
{
use: [
...
{
storage: "{{ '<var label="storage">data</var>' }}",
path: "{{ '<var label="storage path">/data</var>' }}",
},
],
}
```
#### Route storage from the parent realm
When [adding your component](#add-component-to-topology), you'll need to offer
the appropriate storage path to your component from its parent realm.
```json5
// core.cml
{
children: [
...
{
name: "my_component",
url: "fuchsia-pkg://fuchsia.com/my-package#meta/my_component.cm",
},
],
offer: [
...
{{ '<strong>' }}{
storage: "{{ '<var label="storage">data</var>' }}",
from: "self",
to: [ "#my_component" ],
},{{ '</strong>' }}
]
}
```
Note: If the appropriate storage capability is not currently provided by your
component's parent realm, reach out to [component-framework-dev][cf-dev-list]
for assistance.
#### Update component storage index
Components that use storage use a [component ID index][component-id-index] to
preserve access to persistent storage contents across the migration, such as
[`core_component_id_index.json5`][example-component-id-index]. You must update
the component index to map the new component moniker to the same instance within
the component that provides the storage capability.
Find any instances of your current v1 component in component index files:
```json5
// core_component_id_index.json5
{
instances: [
...
{
instance_id: "...",
appmgr_moniker: {
url: "fuchsia-pkg://fuchsia.com/my-package#meta/my_component.cmx",
realm_path: [ ... ]
},
},
],
}
```
Replace the `appmgr_moniker` for your component instance with the new moniker in
the migrated v2 realm, keeping the same `instance_id`:
```json5
// core_component_id_index.json5
{
instances: [
...
{
instance_id: "...",
moniker: "/core/my_component",
},
],
}
```
Note: If you are migrating your component to a realm other than `core`, the
moniker should reflect that.
#### Storage capabilities in tests
When [migrating tests](#migrate-tests), you will need to route storage access
to your test component if any of the components in the test realm access a
storage path.
Following the example in [Test uses injected services](#injected-services), add
the following to route storage access to your test component:
```json5
// my_component_test.cml (test component)
}
use: [
...
{{ '<strong>' }}{
storage: "{{ '<var label="storage">data</var>' }}",
path: "{{ '<var label="storage path">/data</var>' }}",
},{{ '</strong>' }}
],
}
```
Note: Storage capabilities are backed by in-memory storage in tests and contents
will not persist once the test exits.
### Directory features {#directory-features}
If your component uses any of the following features, follow the instructions in
this section to migrate directory access:
Feature | Description | Directory Capability | Path
----------------------- | ------------------------------------------- | ----------------------- | ----
`factory-data` | Read-only factory partition data | `factory` | `/factory`
`durable-data` | Persistent data that survives factory reset | `durable` | `/durable`
`shell-commands` | Executable directory of shell binaries | `bin` | `/bin`
`root-ssl-certificates` | Read-only root certificate data | `root-ssl-certificates` | `/config/ssl`
These features are supported in v2 components using
[directory capabilities][directory-capabilities].
#### Declare the required directory capabilities
When [migrating your component manifest](#create-component-manifest), add the
following to your CML file:
```json5
// my_component.cml
{
use: [
...
{
directory: "{{ '<var label="directory">root-ssl-certificates</var>' }}",
rights: [ "r*" ],
path: "{{ '<var label="directory path">/config/ssl</var>' }}",
},
],
}
```
Note: Unlike storage locations, which are isolated per-component, directories
are a shared resource. You may need to also determine the **subdirectory** your
component needs to access in order to complete this migration.
#### Route directory from the parent realm
When [adding your component](#add-component-to-topology), you'll need to offer
the directory capabilities to your component.
```json5
// core.cml
{
children: [
...
{
name: "my_component",
url: "fuchsia-pkg://fuchsia.com/my-package#meta/my_component.cm",
},
],
offer: [
...
{{ '<strong>' }}{
directory: "{{ '<var label="directory">root-ssl-certificates</var>' }}",
from: "parent",
to: [ "#my_component" ],
},{{ '</strong>' }}
],
}
```
Note: If the appropriate directory capability is not currently provided by your
component's parent realm, reach out to [component-framework-dev][cf-dev-list]
for assistance.
#### Directory paths in tests
When [migrating tests](#migrate-tests), you need to route the directory
capabilities to your test component if any of the components in the test realm
require directory access.
Test Runner Framework only allows the following directory capabilities to be
used by non-hermetic tests:
Capability | Description | Path
----------------------- | ------------------------------- | -------------
`root-ssl-certificates` | Read-only root certificate data | `/config/ssl`
Following the example in [Test uses injected services](#injected-services), add
the following to route directory access to your test component:
```json5
// my_component_test.cml (test component)
{
use: [
...
{{ '<strong>' }}{
directory: "{{ '<var label="directory">root-ssl-certificates</var>' }}",
rights: [ "r*" ],
path: "{{ '<var label="directory path">/config/ssl</var>' }}",
},{{ '</strong>' }}
],
}
```
Note: If the appropriate directory capability is not currently provided by the
Test Runner Framework, reach out to [component-framework-dev][cf-dev-list] for
assistance.
### Configuration data {#config-data}
If your component uses any of the following features, follow the instructions in
this section to migrate directory access:
| Feature | Description | Directory Capability | Path |
| ------------- | ------------------ | -------------------- | -------------- |
| `config-data` | Read-only | `config-data` | `/config/data` |
: : configuration data : : :
These features are supported in v2 components using
[directory capabilities][directory-capabilities].
For more details using data files, see
[product-specific configuration with `config_data()`][config-data].
Consider [packaging your data files hermetically with `resource()`][resource-data]
if your component doesn't need to accept data files from arbitrary parts of the
source tree. Using `resource()` is simpler and more efficient.
#### Declare the required directory capabilities
When [migrating your component manifest](#create-component-manifest), add the
following to your CML file:
```json5
// my_component.cml
{
use: [
...
{
directory: "config-data",
rights: [ "r*" ],
path: "/config/data",
},
],
}
```
#### Route directory from the parent realm
When [adding your component](#add-component-to-topology), you'll need to offer
the directory capability with the appropriate subdirectory to your component.
```json5
// core.cml
{
children: [
...
{
name: "my_component",
url: "fuchsia-pkg://fuchsia.com/my-package#meta/my_component.cm",
},
],
offer: [
...
{{ '<strong>' }}{
directory: "config-data",
from: "parent",
to: [ "#my_component" ],
subdir: "{{ '<var label="package name">my-package</var>' }}",
},{{ '</strong>' }}
],
}
```
#### Configuration data in tests
When [migrating tests](#migrate-tests), you need to route the directory
capability with the appropriate subdirectory to your test component if any of
the components in the test realm require directory access.
The name of the subdirectory should match the name of the package that contains
the component.
Following the example in [Test uses injected services](#injected-services), add
the following to route directory access to your test component:
```json5
// my_component_test.cml (test component)
{
use: [
...
{{ '<strong>' }}{
directory: "config-data",
rights: [ "r*" ],
path: "/config/data",
subdir: "{{ '<var label="package name">my-package</var>' }}",
},{{ '</strong>' }}
],
}
```
### Device directories {#devices}
If your component uses any of the following features, follow the instructions in
this section to migrate device access:
Feature | Description | Path
------- | -------------------------------- | --------------
`dev` | Device driver entries in `devfs` | `/dev/class/*`
[Device filesystem][device-model] access is supported in Components v2 using
[directory capabilities][directory-capabilities].
Consider the following example using Components v1 to access
`/dev/class/input-report`:
```json
// my_component.cmx
{
"program": { ... },
"sandbox": {
"dev": [
"{{ '<var label="device subpath">class/input-report</var>' }}"
]
}
}
```
#### Declare the required device capabilities
When [migrating your component manifest](#create-component-manifest), add the
device path as a directory capability to your CML file:
```json5
// my_component.cml
{
use: [
...
{
directory: "{{ '<var label="device">dev-input-report</var>' }}",
rights: [ "r*" ],
path: "/dev/{{ '<var label="device subpath">class/input-report</var>' }}",
},
],
}
```
#### Route device subdirectory from the parent realm
When [adding your component](#add-component-to-topology), you'll need to offer
the appropriate device path to your component from its parent realm.
```json5
// core.cml
{
children: [
...
{
name: "my_component",
url: "fuchsia-pkg://fuchsia.com/my-package#meta/my_component.cm",
},
],
offer: [
...
{{ '<strong>' }}{
directory: "dev",
from: "parent",
as: "{{ '<var label="device">dev-input-report</var>' }}",
to: [ "#my_component" ],
subdir: "{{ '<var label="device subpath">class/input-report</var>' }}",
},{{ '</strong>' }}
],
}
```
#### Device directories in tests
When [migrating tests](#migrate-tests), you need to route the directory
capabilities to your test component if any of the components in the test realm
require directory access.
Test Runner Framework only allows the following device directories to be used by
non-hermetic tests:
Capability | Description
---------------------------- | -----------------------------
`dev-input-report` | Input method events
`dev-display-controller` | Graphical display controller
`dev-goldfish-address-space` | Goldfish address space device
`dev-goldfish-control` | Goldfish control device
`dev-goldfish-pipe` | Goldfish pipe device
`dev-gpu` | GPU device
Following the example in [Test uses injected services](#injected-services), add
the following to route directory access to your test component:
```json5
// my_component_test.cml (test component)
{
use: [
...
{{ '<strong>' }}{
directory: "{{ '<var label="device">dev-input-report</var>' }}",
rights: [ "r*" ],
path: "/dev/{{ '<var label="device subpath">class/input-report</var>' }}",
},{{ '</strong>' }}
],
}
```
Note: If the appropriate device directory is not currently provided by the Test
Runner Framework, reach out to [component-framework-dev][cf-dev-list] for
assistance.
### Event capabilities {#events}
If your component uses any of the following features, follow the instructions in
this section:
Feature | Description | Path
------- | -------------------------------- | ----------
`hub` | Observing component path changes | `/hub/c/*`
`hub` | Observing realm path changes | `/hub/r/*`
These features are supported in v2 components using
[event capabilities][event-capabilities].
#### Event sources in tests
When [migrating tests](#migrate-tests), you'll need to inject any components you
wish to observe into the test realm and route the appropriate lifecycle events
for those components to your test component.
Following the example in [Test uses injected services](#injected-services),
route the `fuchsia.sys2.EventSource` capability and the appropriate events to
your test component:
```json5
// my_component_test.cml (test component)
{
children: [
{
name: "my_component",
url: "fuchsia-pkg://fuchsia.com/my-package#meta/my_component.cm",
},
],
use: [
{
protocol: [ "fuchsia.sys2.EventSource" ],
},
{
event: [ "{{ '<var label="event name">started</var>' }}" ],
from: "framework",
modes: [ "async" ],
},
],
}
```
Note: The `EventSource` capability comes from the test realm (`parent`), but the
events come from the Component Manager (`framework`). This sets the event scope
to only components in the test realm. For more details on event scope,
see [event-capabilities][event-capabilities].
### Build Info {#build-info}
When migrating the `build-info` feature, instead use the
`fuchsia.buildinfo.Provider` [protocol][build-info-fidl]. This protocol is the
only supported method of retrieving build information moving forward. To use
this protocol, add it [while declaring required services](#required-services).
### Vulkan {#vulkan}
When migrating the `vulkan` feature or code that uses a `//src/lib/vulkan/*.shard.cmx`
shard, instead use the `vulkan/client.shard.cml` [shard][manifests-shard] as
described in the [Vulkan documentation][vulkan].
[glossary.component-manifest]: /docs/glossary/README.md#component-manifest
[glossary.components-v1]: /docs/glossary/README.md#components-v1
[glossary.components-v2]: /docs/glossary/README.md#components-v2
[glossary.environment]: /docs/glossary/README.md#environment
[glossary.runner]: /docs/glossary/README.md#runner
[archive-codelab]: /docs/development/diagnostics/inspect/codelab/codelab.md
[archive-cpp]: /sdk/lib/inspect/contrib/cpp
[archive-fidl]: https://fuchsia.dev/reference/fidl/fuchsia.diagnostics#ArchiveAccessor
[archive-rust]: /src/lib/diagnostics/reader/rust
[archive-dart]: /sdk/dart/fuchsia_inspect/lib/src/reader
[archivist]: /docs/reference/diagnostics/inspect/tree.md#archivist
[build-info-fidl]: https://fuchsia.dev/reference/fidl/fuchsia.buildinfo#Provider
[cf-dev-list]: https://groups.google.com/a/fuchsia.dev/g/component-framework-dev
[cmx-services]: /docs/concepts/components/v1/component_manifests.md#sandbox
[code-search]: https://cs.opensource.google/fuchsia
[component-id-index]: /docs/development/components/component_id_index.md
[components-intro]: /docs/concepts/components/v2/introduction.md
[components-topology]: /docs/concepts/components/v2/topology.md
[components-migration-status]: /docs/contribute/open_projects/components/migration.md
[config-data]: /docs/development/components/data.md#product-specific_configuration_with_config_data
[core-realm-rfc]: /docs/contribute/governance/rfcs/0089_core_realm_variations.md
[cs-appmgr-cml]: /src/sys/appmgr/meta/appmgr.cml
[cs-appmgr-allowlist]: https://cs.opensource.google/fuchsia/fuchsia/+/main:src/sys/appmgr/main.cc;l=125;drc=ddf6d10ce8cf63268e21620638ea02e9b2b7cd20
[cs-core-cml]: /src/sys/core/meta/core.cml
[debug-log]: /docs/development/diagnostics/logs/recording.md#debuglog_handles
[debug-log-cpp]: /src/sys/lib/stdout-to-debuglog/cpp
[debug-log-rust]: /src/sys/lib/stdout-to-debuglog/rust
[device-model]: /docs/concepts/drivers/device_driver_model/device-model.md
[directory-capabilities]: /docs/concepts/components/v2/capabilities/directory.md
[emulatortest]: /tools/emulator/emulatortest
[eager-lifecycle]: /docs/concepts/components/v2/lifecycle.md#eager
[eager-manifest]: /docs/concepts/components/v2/component_manifests.md#children
[elf-runner-docs]: /docs/concepts/components/v2/elf_runner.md#lifecycle
[event-capabilities]: /docs/concepts/components/v2/capabilities/event.md
[example-component-id-index]: /src/sys/appmgr/config/core_component_id_index.json5
[example-fonts]: https://fuchsia.googlesource.com/fuchsia/+/cd29e692c5bfdb0979161e52572f847069e10e2f/src/fonts/meta/fonts.cmx
[example-package-rule]: https://fuchsia.googlesource.com/fuchsia/+/cd29e692c5bfdb0979161e52572f847069e10e2f/src/fonts/BUILD.gn
[example-services-config]: /src/sys/sysmgr/config/services.config
[fshost-lifecycle]: /src/storage/fshost/main.cc
[integration-test]: /docs/concepts/testing/v2/integration_testing.md
[integration-test-monikers]: /docs/concepts/testing/v2/integration_testing.md#test-component-moniker
[realm-builder-monikers]: /docs/development/components/v2/realm_builder.md#test-component-moniker
[trf-intro]: /docs/concepts/testing/v2/test_runner_framework.md
[trf-provided-test-runners]: /src/sys/test_runners
[trf-test-manager]: /docs/concepts/testing/v2/test_runner_framework.md#the_test_manager
[trf-test-runners]: /docs/concepts/testing/v2/test_runner_framework.md#test-runners
[trf-test-suite]: /docs/concepts/testing/v2/test_runner_framework.md#test-suite-protocol
[fuchsia-test-facets]: /docs/concepts/testing/v1_test_component.md
[fx-scrutiny]: https://fuchsia.dev/reference/tools/fx/cmd/scrutiny
[hub-v1]: /docs/concepts/components/v1/hub.md
[hub-v2]: /docs/concepts/components/v2/hub.md
[inspect]: /docs/development/diagnostics/inspect/README.md
[logs]: /docs/development/diagnostics/logs/README.md
[manifests-capabilities]: /docs/concepts/components/v2/component_manifests.md#capabilities
[manifests-expose]: /docs/concepts/components/v2/component_manifests.md#expose
[manifests-include]: /docs/concepts/components/v2/component_manifests.md#include
[manifests-program]: /docs/concepts/components/v2/component_manifests.md#program
[manifests-shard]: /docs/development/components/build.md#component-manifest-shards
[manifests-use]: /docs/concepts/components/v2/component_manifests.md#use
[moniker]: /docs/concepts/components/v2/monikers.md
[protocol-capabilities]: /docs/concepts/components/v2/capabilities/protocol.md
[resource-data]: /docs/development/components/data.md#hermetic_data_files_with_resource
[rust-lifecycle]: /examples/components/lifecycle
[src-security-policy]: /src/security/policy/component_manager_policy.json5
[storage-capabilities]: /docs/concepts/components/v2/capabilities/storage.md
[syslog]: /docs/development/diagnostics/logs/recording.md#logsinksyslog
[sysmgr-config-search]: https://cs.opensource.google/search?q=fuchsia-pkg:%2F%2Ffuchsia.com%2F.*%23meta%2Fmy_component.cmx%20-f:.*.cmx$%20%5C%22services%5C%22&ss=fuchsia
[sysmgr-config]: /docs/concepts/components/v1/sysmgr.md
[sysmgr-critical-components]: /docs/concepts/components/v1/sysmgr.md#critical_components
[system-services]: /docs/concepts/testing/v1_test_component.md#services
[troubleshooting-components]: /docs/development/components/v2/troubleshooting.md
[unit-tests-with-generated-manifests]: /docs/development/components/build.md#unit-tests
[ffx-inspect]: /docs/reference/tools/sdk/ffx.md#inspect
[vulkan]: /docs/concepts/graphics/magma/vulkan.md#components_v2
[realm-builder]:/docs/development/components/v2/realm_builder.md
[protocol-connector]: /src/lib/fuchsia-component/src/client.rs
[service-directory-cpp]: /sdk/lib/sys/cpp/service_directory.h