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.InspectSink
instead 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.Directory
and most components do not serve theirout
directory 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.Tree
protocol. 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.Tree
for 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/diagnostics
on 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.Directory
implementations.
- 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
InspectSink
in the Archivist. - Identify components using the
inspect/client.shard.cml
and routefuchsia.inspect.InspectSink
to 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.cml
to use this protocol together with exposing the/diagnostics
directory to the framework, thus allowing for a soft transition. - Support connecting to
InspectSink
instead of exposing adiagnostics
directory in the Inspect libraries. - Remove the implementation of
DirectoryReady
in Component manager and remove it from thefuchsia.sys2.Event
definition 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