blob: 30a3f6355afa9bbb51489945f2c558efc6dd3979 [file] [log] [blame]
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@available(added=7)
library fuchsia.component.runner;
using fuchsia.component;
using fuchsia.component.sandbox;
using fuchsia.data;
using fuchsia.diagnostics.types;
using fuchsia.io;
using fuchsia.mem;
using fuchsia.process;
using fuchsia.url;
using zx;
const MAX_NAMESPACE_COUNT uint32 = 32;
const MAX_HANDLE_COUNT uint32 = 128;
/// A protocol used for running components.
///
/// This protocol is implemented by components which provide a runtime
/// environment for other components.
///
/// Note: The component manager is the only intended direct client of this
/// interface.
@discoverable
closed protocol ComponentRunner {
/// Start running a component instance described by `start_info`.
///
/// Component manager binds and uses `controller` to control the
/// lifetime of the newly started component instance.
///
/// Errors are delivered as epitaphs over the `ComponentController`
/// protocol. In the event of an error, the runner must ensure that
/// resources are cleaned up.
///
/// Errors:
///
strict Start(resource struct {
start_info ComponentStartInfo;
controller server_end:ComponentController;
});
};
/// A single component namespace entry, which describes a namespace mount point
/// (`path`) and the directory backing it (`directory`). This type is usually
/// composed inside a vector. See `ComponentStartInfo.ns` for more details.
type ComponentNamespaceEntry = resource table {
/// The mount point for the directory, including a
/// leading slash. For example: "/pkg", "/svc", or "/config/data".
1: path string:fuchsia.component.MAX_PATH_LENGTH;
/// The directory mounted at the above `path`.
2: directory client_end:fuchsia.io.Directory;
};
/// Parameters for starting a new component instance.
type ComponentStartInfo = resource table {
/// The resolved URL of the component.
///
/// This is the canonical URL obtained by the component resolver after
/// following redirects and resolving relative paths.
1: resolved_url fuchsia.url.Url;
/// The component's program declaration.
/// This information originates from `ComponentDecl.program`.
2: program fuchsia.data.Dictionary;
/// The namespace to provide to the component instance.
///
/// A namespace specifies the set of directories that a component instance
/// receives at start-up. Through the namespace directories, a component
/// may access capabilities available to it. The contents of the namespace
/// are mainly determined by the component's `use` declarations but may
/// also contain additional capabilities automatically provided by the
/// framework.
///
/// By convention, a component's namespace typically contains some or all
/// of the following directories:
///
/// - "/svc": A directory containing services that the component requested
/// to use via its "import" declarations.
/// - "/pkg": A directory containing the component's package, including its
/// binaries, libraries, and other assets.
///
/// The mount points specified in each entry must be unique and
/// non-overlapping. For example, [{"/foo", ..}, {"/foo/bar", ..}] is
/// invalid.
3: ns vector<ComponentNamespaceEntry>:MAX_NAMESPACE_COUNT;
/// The directory this component serves.
4: outgoing_dir server_end:fuchsia.io.Directory;
/// The directory served by the runner to present runtime information about
/// the component. The runner must either serve it, or drop it to avoid
/// blocking any consumers indefinitely.
5: runtime_dir server_end:fuchsia.io.Directory;
/// The numbered handles that were passed to the component.
///
/// If the component does not support numbered handles, the runner is expected
/// to close the handles.
6: numbered_handles vector<fuchsia.process.HandleInfo>:MAX_HANDLE_COUNT;
/// Binary representation of the component's configuration.
///
/// # Layout
///
/// The first 2 bytes of the data should be interpreted as an unsigned 16-bit
/// little-endian integer which denotes the number of bytes following it that
/// contain the configuration checksum. After the checksum, all the remaining
/// bytes are a persistent FIDL message of a top-level struct. The struct's
/// fields match the configuration fields of the component's compiled manifest
/// in the same order.
7: encoded_config fuchsia.mem.Data;
/// An eventpair that debuggers can use to defer the launch of the component.
///
/// For example, ELF runners hold off from creating processes in the component
/// until ZX_EVENTPAIR_PEER_CLOSED is signaled on this eventpair. They also
/// ensure that runtime_dir is served before waiting on this eventpair.
/// ELF debuggers can query the runtime_dir to decide whether to attach before
/// they drop the other side of the eventpair, which is sent in the payload of
/// the DebugStarted event in fuchsia.component.events.
8: break_on_start zx.Handle:EVENTPAIR;
/// An opaque token that represents the component instance.
///
/// The `fuchsia.component/Introspector` protocol may be used to get the
/// string moniker of the instance from this token.
///
/// Runners may publish this token as part of diagnostics information, to
/// identify the running component without knowing its moniker.
///
/// The token is invalidated when the component instance is destroyed.
@available(added=HEAD)
9: component_instance zx.Handle:EVENT;
/// A dictionary containing data and handles that the component has escrowed
/// during its previous execution via [`ComponentController.OnEscrow`].
@available(added=HEAD)
10: escrowed_dictionary client_end:fuchsia.component.sandbox.Dictionary;
};
/// A protocol for binding and controlling the lifetime of a component instance
/// started using `ComponentRunner.Start()`. The component manager is the
/// intended direct client of this protocol.
///
/// When the controlled component instance terminates or becomes inaccessible
/// for any reason, the server closes the connection with an epitaph.
///
/// LIFECYCLE
///
/// A component may exist in one of two states: `Started`, or `Stopped`. The
/// component is `Started` from the time `ComponentRunner.Start()` is called
/// until the ComponentRunner closes the ComponentController handle. The
/// component then transitions to `Stopped`.
///
/// Component manager uses ComponentController to terminate a component in two
/// steps:
/// 1) Component manager calls `Stop()` to indicate that the ComponentRunner
/// should stop a component's execution and close this connection with an
/// epitaph.
/// 2) If after some time the ComponentController is not closed, component
/// manager calls `Kill()` to indicate that the ComponentRunner must halt a
/// component's execution immediately, and then close this connection with
/// an epitaph. The component manager may wait some period of time after
/// calling `Kill()` before closing the ComponentController channel, but
/// makes no guarantees it will wait or for how long.
///
/// Component manager first waits for the ComponentController to close, and
/// then tears down the namespace it hosts for the stopped component. Component
/// manager may call `Kill()` without first having called `Stop()`.
///
/// Before stopping, a component can optionally use `OnEscrow` to store some
/// state in the framework, to receive those state again the next time it is
/// started.
///
/// EPITAPH
///
/// This protocol sends a FIDL epitaph to indicate that the component instance
/// has been terminated. The component runner is expected to clean up all
/// resources attributed to the component before closing the connection.
///
/// The following epitaphs may be sent by the server on error:
/// - `ZX_OK`: The component exited successfully, typically because the
/// component was asked to stop or it decided independently to exit.
/// - `INVALID_ARGUMENTS`:
/// * `start_info.resolved_url` is not supported by this
/// runner;
/// * `start_info` contains missing or invalid arguments.
/// - `INSTANCE_CANNOT_START`: The runner could not start the component.
/// For example, a critical part of the program could not be found or
/// loaded, or the referenced binary was invalid for this runner.
/// - `RESOURCE_UNAVAILABLE`: The component could not be launched due to
/// lack of resources.
/// - `INTERNAL`: An unexpected internal runner error was encountered.
/// - `INSTANCE_DIED`: The component instance was started but
/// subsequently terminated with an error.
/// - Other status codes (e.g. `ZX_ERR_PEER_CLOSED`) may indicate a failure
/// of the component runner itself. The component manager may respond to such
/// failures by terminating the component runner's job to ensure system
/// stability.
closed protocol ComponentController {
/// Request to stop the component instance.
///
/// After stopping the component instance, the server should close this
/// connection with an epitaph. After the connection
/// closes, component manager considers this component instance to be
/// Stopped and the component's namespace will be torn down.
strict Stop();
/// Stop this component instance immediately.
///
/// The ComponentRunner must immediately kill the component instance, and
/// then close this connection with an epitaph. After the connection
/// closes, component manager considers this component instance to be
/// Stopped and the component's namespace will be torn down.
///
/// In some cases Kill() may be issued before Stop(), but that is not
/// guaranteed.
strict Kill();
/// Event for runners to publish diagnostics to the platform.
///
/// This event signals to the platform that the runner for this
/// component is publishing diagnostics about the runtime of the
/// component. The component manager may optionally expose this data
/// to clients.
strict -> OnPublishDiagnostics(resource struct {
payload fuchsia.diagnostics.types.ComponentDiagnostics;
});
/// Store some of the component's state in the framework, to be redelivered
/// to the component the next time it's started (a practice called
/// "escrowing").
///
/// When the framework receives this event, it will wait until the current
/// execution of the component has finished, then start the component again
/// when the `ZX_CHANNEL_READABLE` signal is observed on `outgoing_dir`.
///
/// Repeated calls will replace the old escrowed value. This is discouraged.
///
/// Handles escrowed via `OnEscrow` are always delivered to the next
/// execution of the component.
@available(added=HEAD)
strict -> OnEscrow(resource table {
/// Escrow the outgoing directory server endpoint. Whenever the
/// component is started, the framework will return this channel via
/// [`ComponentStartInfo.outgoing_dir`].
1: outgoing_dir server_end:fuchsia.io.Directory;
/// Escrow some user defined state. Whenever the component is started,
/// the framework will return these handles via
/// [`ComponentStartInfo.escrowed_dictionary`].
///
/// The framework will not wait for any signals on these objects.
///
/// ## Example
///
/// Let's say a component needs to escrow an event pair that represents
/// the result of some expensive calculation. It can create a
/// dictionary, put the event pair inside with an appropriate key
/// (e.g. `"my_event_pair"`), then check for that entry on startup.
2: escrowed_dictionary client_end:fuchsia.component.sandbox.Dictionary;
});
};