| RFC-0168: Exposing Inspect through InspectSink | |
|---|---|
| Status | Accepted |
| Areas |
|
| Description | Define the mechanism through which Inspect is exposed by components. |
| Issues | |
| Gerrit change | |
| Authors | |
| Reviewers | |
| Date submitted (year-month-day) | 2022-05-17 |
| Date reviewed (year-month-day) | 2022-06-15 |
Summary
This RFC introduces the fuchsia.diagnostics.InspectSink protocol that allows components
to expose Inspect data. As a result, the current mechanism (the DirectoryReady event) can now
be removed.
Motivation
Inspect today is exposed through a mechanism that is not aligned with regular component framework
capability routing. Today a component exposes a diagnostics directory in its outgoing namespace
to framework.
The DirectoryReady event was marked deprecated in RFC-121 as part of the goal of publishing event
capabilities in the SDK. However, we don’t yet have a good solution to how components will be able
to expose Inspect data if this directory doesn’t exist. Additionally, Flutter on Fuchsia
wants to remove our reliance on these file system abstractions and simplify their implementation.
Rethinking how components expose Inspect will allow them to remove significant
runtime-complexity and provide advantages to developer ergonomics.
Stakeholders
Facilitator: leannogasawara@google.com
Reviewers:
- crjohns@google.com
- geb@google.com
- shayba@google.com
Consulted:
- dworsham@google.com
- surajmalhotra@google.com
- zarvox@google.com
Socialization: this RFC was previously socialized in the form of a Google Docs document among Diagnostics, Component Framework, Flutter and others.
Design
Background
Time ago, the Archivist used to ingest Inspect data through the /hub. Its codebase was structured
as directory watchers on the hub that would begin tracking Inspect data of a component the moment
the out/diagnostics directory appeared (it used to be named different at the time). This
was eventually removed and done through events (in both appmgr and component manager).
Also, at the time, tests that read Inspect data, did so by reading directly from the /hub.
The Archivist currently relies on the DirectoryReady event for two things:
- Ingesting Inspect data from components (components
expose /diagnostics to framework). - Attributing Inspect data to the source component.
The DirectoryReady event tackles both of these points. However, we already have
CapabilityRequested for (2) and the author believes we could tackle (1) with a regular
protocol (similar to fuchsia.logger.LogSink) bringing additional advantages.
Solving attribution is a non-goal of this RFC. That’s left as future work for removing the
CapabilityRequested event which is currently used for LogSink and DebugData.
InspectSink
This RFC introduces the InspectSink protocol that allows the Archivist to ingest Inspect data
from a component. This protocol is defined as follows:
library fuchsia.diagnostics;
using zx;
@discoverable
protocol InspectSink {
/// Publishes a handle to the `fuchsia.inspect.Tree` protocol that the server can use to read
/// Inspect data, including lazy nodes.
Publish(struct {
tree fuchsia.inspect.Tree;
root zx.handle:<VMO, zx.rights.BASIC | zx.rights.READ | zx.rights.MAP, optional>;
});
/// Publishes a read handle to the inspect VMO that the component asynchronously updates.
/// The server can read Inspect using the Inspect reader algorithm [1]. A component using this
/// method to publish Inspect won't be able to expose lazy nodes.
///
/// [1]: /docs/reference/platform-spec/diagnostics/inspect-vmo-format.md#reader_algorithm
PublishVmo(struct {
name string;
root zx.handle:<VMO, zx.rights.BASIC | zx.rights.READ | zx.rights.MAP>;
});
}
The main method is Publish, most components will be using it as fuchsia.inspect.Tree is the
standard way of exposing Inspect. However, we provide a mechanism that allows components to publish
only an Inspect VMO. This is needed for a few reasons:
- A component doesn't need to be a server (no reason to run an async loop, just consuming capabilities, not serving anything) if it doesn't need to be one, but should still be able to expose Inspect.
- Until drivers are migrated to use
fuchsia.inspect.Tree(issue), they will continue exposing VMOs. - Until the Inspect Dart library supports
fuchsia.inspect.Tree, it will need to continue exposing VMOs.
Just like fuchsia.logger.LogSink, this protocol will be served by the Archivist and routed
to components.
This protocol has several advantages over serving an out/diagnostics directory:
Alignment with standard component protocol routing:
- Components just use the protocol
fuchsia.inspect.InspectSinkinstead of doingexpose /diagnostics to framework, similar to how components export logs and traces today. - The Archivist can receive connections to it through
CapabilityRequested, maintaining attribution.
- Components just use the protocol
Inspect data can be made available before starting the component async loop.
A directory is backed by the
fuchsia.io.Directoryand most components do not serve theiroutdirectory until starting their async loop. By using this protocol, snapshots can contain the Inspect data of components that haven’t started their async loop yet but have already written Inspect data.The same applies to the
fuchsia.inspect.Treeprotocol. A component’s Inspect data won’t be available in snapshots until a component starts serving this protocol, which won’t happen in most cases until a component starts its async loop. By using the protocol proposed above we can immediately provide the Archivist with both the root VMO (so at least this one is included in snapshots) and a handle tofuchsia.inspect.Treefor future requests.
No more issues with runners and file system implementations.
- We currently have code in appmgr and component manager that special cases the scenario of a
component not serving
out/diagnosticson time, which is the case for the Flutter runner. That runner serves theout/directory first and then fills it. Ideally we would just use directory watchers, but not all VFS implementations have watchers implemented (notably our VFS implementation in the C++ SDK used by Flutter) and we cannot rely on future runners using completefuchsia.io.Directoryimplementations.
- We currently have code in appmgr and component manager that special cases the scenario of a
component not serving
This change can be done under the hood by changing the inspect/client.shard.cml to use the
new protocol instead of exposing the diagnostics directory to the framework. The file
inspect/client.shard.cml is offered through the SDK, and is used by all components that expose
Inspect anywhere.
This proposal is intended for v2 components. We’ll still be handling out/diagnostics for v1
components for compatibility purposes. With the ongoing migration to v2, the author doesn’t
believe it’s worth spending time changing how v1 is working. The goal is to make this change under
the hood, so components being migrated to v2 don't require code changes on how they expose inspect.
Implementation
The standard LSC process will be followed.
Particular steps are:
- Implement the new protocol
InspectSinkin the Archivist. - Identify components using the
inspect/client.shard.cmland routefuchsia.inspect.InspectSinkto them from the Archivist. Today this introduces the problem of having to fully enumerate all such components in cml definitions, however we have a solution that has already been socialized and will be covered in a follow-up RFC. - Change
inspect/client.shard.cmlto use this protocol together with exposing the/diagnosticsdirectory to the framework, thus allowing for a soft transition. - Support connecting to
InspectSinkinstead of exposing adiagnosticsdirectory in the Inspect libraries. - Remove the implementation of
DirectoryReadyin Component manager and remove it from thefuchsia.sys2.Eventdefinition once all components have been transitioned, and all prebuilts have been refreshed. We'll rely on CTF tests and the support window we have to know when this can be done.
Performance
Performance should have a positive improvement as we no longer have to traverse directories or
create the DirectoryReady event, we just rely on a single protocol.
Security considerations
This change aligns with component framework security properties, in particular the principle of least privilege and the principle of hierarchical isolation.
Privacy considerations
No changes regarding privacy. Inspect data continues to go through the regular privacy pipelines.
Testing
The implementation of this RFC will be tested in the following ways:
- Unit tested in libraries connecting to InspectSink.
- Unit tested and integration tested in the Archivist, which serves InspectSink.
- CTF tests to detect compatibility changes.
Documentation
Inspect discovery and hosting will be updated.
The goal is to make this change under the hood, in the libraries that write inspect. However, If we end up requiring code changes when components migrate to v2, we'll reflect those changes in the diagnostics section of the migration guide.
Drawbacks, alternatives, and unknowns
A single protocol for both logs and Inspect
We could have a DiagnosticsSink which allows components to connect Inspect and logs in a single place.
- Pros: One single protocol to route instead of 2.
- Cons: If for some reason we need to treat logs or Inspect differently in the future, it might be easier to do it if we maintain separate protocols than if we have the same protocol for the two of them.
We believe the con makes this alternative very unattractive as logs and Inspect are different things, so it makes sense to route them separately.
Prior art and references
N/A