| // 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(client="platform") |
| closed(removed=24) open(added=24) 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. |
| 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 URL of the component. Called `resolved_url` instead of just `url` |
| /// for historical reasons. |
| 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 fuchsia.component.sandbox.DictionaryRef; |
| }; |
| |
| /// 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 send the `OnStop` event. |
| /// 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 send the `OnStop` event. |
| /// The component manager may wait some period of time after calling `Kill()` |
| /// before sending `OnStop`, 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. |
| /// |
| /// When the component stops, the runner should send an `OnStop` event |
| /// instead of just closing the channel, to report the component's termination status |
| /// (see below) and (optionally) an exit code. Once the runner has sent `OnStop` |
| /// it is free to close [ComponentRunner]; the component framework will close |
| /// its end of the channel when it receives this event. |
| /// |
| /// ## Legacy |
| /// |
| /// Instead of sending `OnStop`, it is also legal for a runner to close the channel |
| /// with with an epitaph equal to the termination status, but this is a legacy method |
| /// for backward compatibility that's no longer recommended. |
| /// |
| /// # Termination status |
| /// |
| /// The termination status indicates the component's final disposition in the eyes of |
| /// the runner. |
| /// |
| /// Note that termination status is _not_ synonymous with a component's exit code. |
| /// A component's exit code, which is optional for a runner to report, is an |
| /// integer that represents the program's own return code. For example, for ELF |
| /// components, it is the value returned by main(). The termination status is |
| /// the _runner_'s status code for the component's termination, which may capture |
| /// failure modes that occur in the context of the runner itself rather than the |
| /// program. |
| /// |
| /// The following termination statuses 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(removed=24) open(added=24) 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(); |
| |
| @available(replaced=27) |
| strict -> OnPublishDiagnostics(resource struct { |
| payload fuchsia.diagnostics.types.ComponentDiagnostics; |
| }); |
| |
| /// 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. |
| @available(added=27) |
| strict -> OnPublishDiagnostics(resource struct { |
| payload 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) |
| flexible -> 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 fuchsia.component.sandbox.DictionaryRef; |
| }); |
| |
| /// Report that the component has stopped, with data about its termination. This will |
| /// cause the component to make a lifecycle transition to `Stopped`. |
| /// |
| /// Once the runner has sent `OnStop` it is free to close this [ComponentRunner]; the |
| /// component framework will close its end of the channel when it receives this event. |
| /// |
| /// Alternatively, a runner may close the controller channel without this event to signal |
| /// component stop, but this method is legacy and no longer recommended. |
| @available(added=HEAD) |
| flexible -> OnStop(@generated_name("ComponentStopInfo") resource table { |
| /// The component's termination status, as documented on [ComponentRunner] above. |
| /// |
| /// The caller should set this field. If it is absent, the framework will assume |
| /// a value of ZX_OK. |
| 1: termination_status zx.Status; |
| |
| /// (Optional) The exit code of the component instance. |
| /// |
| /// Runner implementors may map their runtime specific exit code concept |
| /// (such as libc exit status) to this field. Or they may choose to |
| /// leave this blank. |
| 2: exit_code int64; |
| }); |
| }; |
| |
| // Task associated with a running component. |
| @available(added=27) |
| type Task = flexible resource union { |
| 1: job zx.Handle:JOB; |
| 2: process zx.Handle:PROCESS; |
| 3: thread zx.Handle:THREAD; |
| }; |
| |
| // Contains handles for tasks of the running component. This is emitted by |
| // runners and handled by component manager to obtain information about the |
| // process and record diagnostics. |
| @available(added=27) |
| type ComponentTasks = resource table { |
| // The Zircon task for the running component. |
| // Resource usage for the component is attributed to this task. |
| 1: component_task Task; |
| |
| // The container task running the component. |
| // This field is set to the task that runs `component_task`. For |
| // example, if `component_task` is run a part of a Virtual Machine, |
| // this task is set so that resources attributed to the parent can be |
| // subdivided between their children. |
| // |
| // This field is used only when a portion of the `component_task`'s resource |
| // usage is shared with another component. If `component_task` owns exactly |
| // only those resources used by the component, `parent_task` must be left |
| // unset. |
| 2: parent_task Task; |
| }; |
| |
| // Diagnostics information about a component provided by the runner. |
| @available(added=27) |
| type ComponentDiagnostics = resource table { |
| // Tasks associated with the running component. |
| 1: tasks ComponentTasks; |
| }; |