Google celebrates Pride Month. See how.

Other common 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 full-resolver resolver to it. Resolvers are routed to components using environments, and core.cml has a shared environment named core-env for components outside of base.

Use the list-packages command to report the package sets where your component package is included.

fx list-packages --verbose my-package

If the package is not listed with the base tag, follow the remaining instructions in this section.

When adding your component, assign the shared core-env as your component's environment.

// core.cml / component.core_shard.cml
{
  children: [
    ...
    {
      name: "my_component",
      url: "fuchsia-pkg://fuchsia.com/my-pkg#meta/my_component.cm",
      environment: "#core-env",
    },
  ],
}

Start on boot

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.

// 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, otherwise you need to use core realm variability 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 and component manifests.

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:

    // Remove this entry.
    lifecycle_allowlist.insert(component::Moniker{
        .url = "fuchsia-pkg://fuchsia.com/my_package#meta/my_component.cmx", .realm_path = {"app", "sys"}});
    
  2. When migrating your component manifest, add the lifecycle stop event:

    // my_component.cml
    {
        include: [
            "syslog/client.shard.cml",
        ],
        program: {
            runner: "elf",
            binary: "bin/my_binary",
            lifecycle: { stop_event: "notify" },
        },
        ...
    }
    
  3. Get the fuchsia.process.lifecycle.Lifecycle channel provided by the ELF 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: fuchsia_zircon::Channel = lifecycle_handle.into();
                let async_x = AsyncChannel::from(
                    fuchsia_async::Channel::from_channel(x).expect("Async channel conversion failed."),
                );
                let mut req_stream = LifecycleRequestStream::from_channel(async_x);
                info!("Awaiting request to close...");
                while 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_;
    };
    

More information about the Lifecycle protocol is available in the ELF runner documentation.

Developer tools plugins

Many ffx plugins depend on FIDL protocols provided by components. This dependency is expressed by declaring a component selector in the plugin's ffx_plugin macro, such as core/appmgr:out:fuchsia.update.channelcontrol.ChannelControl.

Selectors are dependent on the component's [moniker][moniker], which describes its place in the component instance tree . If there are ffx plugins that depend on capabilities provided by your component, you need to migrate those selectors using Remote Control Service (RCS) proxy selector maps.

To migrate the ffx plugin selectors for your component, do the following:

Add an entry to //src/developer/remote-control/data/selector-maps.json mapping the v1 component's moniker under appmgr to the new v2 component's moniker:

{
  ...
  "core/appmgr:out:fuchsia.fonts.Provider": "core/font_provider:expose:fuchsia.fonts.Provider"
}

This mapping overrides the code written in the ffx_plugin macro declarations, and it should only remain in place long enough to verify that the component migration has successfully landed. Otherwise, it may cause confusion for future contributors.

Once the migration is complete and the v1 component is no longer present in any release branches, consider removing the mapping from RCS, and updating the ffx plugin selectors to reference the v2 component directly.

What's next

Explore the following sections for additional migration guidance on specific features your components may support: