chromium/services/tracing/public/mojom/perfetto_service.mojom

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

module tracing.mojom;

import "mojo/public/mojom/base/byte_string.mojom";
import "mojo/public/mojom/base/token.mojom";
import "mojo/public/mojom/base/file.mojom";
import "mojo/public/mojom/base/shared_memory.mojom";

// Producer processes register with the format
// "kPerfettoProducerNamePrefix-PID" when connecting to Chrome's internal
// tracing service. Note that system producers use a different but similar
// naming scheme to disambiguate between different apps on the same system,
// see SystemProducer::ConnectToSystemService() implementations. Of
// particular interest is PosixSystemProducer::ConnectSocket().
const string kPerfettoProducerNamePrefix = "org.chromium-";
const string kTraceEventDataSourceName = "org.chromium.trace_event";
const string kMemoryInstrumentationDataSourceName = "org.chromium.memory_instrumentation";
const string kMetaDataSourceName = "org.chromium.trace_metadata";
const string kSystemTraceDataSourceName = "org.chromium.trace_system";
const string kArcTraceDataSourceName = "org.chromium.trace_arc";
const string kSamplerProfilerSourceName = "org.chromium.sampler_profiler";
const string kJavaHeapProfilerSourceName = "org.chromium.java_heap_profiler";
const string kNativeHeapProfilerSourceName =
    "org.chromium.native_heap_profiler";

// Brief description of the flow: There's a per-process ProducerClient which
// connects to the central PerfettoService and establishes a two-way connection
// with a ProducerHost. The latter will then pass a SharedMemoryBuffer to the
// ProducerClient and tell it to start logging events of a given type into it.
// As chunks of the buffer get filled up, the client will communicate this to
// the ProducerHost, which will tell Perfetto to copy the finished chunks into
// its central storage and pass them on to its consumers.

// For a more complete explanation of a Perfetto tracing session, see
// https://android.googlesource.com/platform/external/perfetto/+/master/docs/life-of-a-tracing-session.md

// See https://android.googlesource.com/platform/external/perfetto/
// for the full documentation of Perfetto concepts and its shared memory ABI.

// Passed by the client process as part of CommitDataRequest() to the central
// Perfetto service. Signals that a chunk (segment/page of the shared memory
// buffer which is owned by a per-thread TraceWriter) is ready for consumption
// (flushed or fully written).
struct ChunksToMove {
  // The page index within the producer:service shared memory buffer.
  uint32 page;
  // The chunk index within the given page.
  uint32 chunk;
  // The target ring-buffer in the service that the chunk should be copied into.
  uint32 target_buffer;
};

// Passed by the client process as part of CommitDataRequest() to the central
// Perfetto service. Used to patch previously written chunks (for example, to
// fill in size fields when protos span multiple chunks).
struct ChunkPatch {
  // Offset relative to the chunk defined in ChunksToPatch.
  uint32 offset;
  mojo_base.mojom.ByteString data;
};

struct ChunksToPatch {
  // The triplet {target_buffer, writer_id, chunk_id} uniquely identifies a
  // chunk that has been copied over into the main, non-shared, trace buffer
  // owned by the service.
  uint32 target_buffer;
  uint32 writer_id;
  uint32 chunk_id;
  array<ChunkPatch> patches;
  // If false the chunk should be considered finalized and available to be read.
  bool has_more_patches;
};

struct CommitDataRequest {
  array<ChunksToMove> chunks_to_move;
  array<ChunksToPatch> chunks_to_patch;
  uint64 flush_request_id;
};

// Passed as part of DataSourceConfig
struct ChromeConfig {
  // TODO(crbug.com/41439336): Once we've completed removing the old IPC layer
  // we should convert this into a struct that represents a
  // base::trace_event::TraceConfig object rather then the json encoded string
  // used currently.
  string trace_config;

  // When enabled the data source is supposed to only emit fields in the output
  // proto that are guaranteed to not contain any sensitive data.
  bool privacy_filtering_enabled;

  // Whether the final tracing result will be converted to the legacy JSON
  // format.
  bool convert_to_legacy_json;

  // Priority of the tracing session.
  TracingClientPriority client_priority;
};

enum ConsoleOutput {
  kOutputUnspecified,
  kOutputStdOut,
  kOutputStdErr,
};

struct ConsoleConfig {
  ConsoleOutput output;
  bool enable_colors;
};

struct InterceptorConfig {
  string name;
  // `console_config` is optionally present only if `name` == "console".
  // If not present, the default config is used.
  ConsoleConfig? console_config;
};

struct DataSourceConfig {
  string name;
  uint32 target_buffer;
  uint32 trace_duration_ms;
  uint64 tracing_session_id;
  ChromeConfig chrome_config;
  InterceptorConfig? interceptor_config;
  string legacy_config;
  mojo_base.mojom.ByteString track_event_config_raw;
  mojo_base.mojom.ByteString etw_config_raw;
};

struct DataSourceRegistration {
  string name;
  bool will_notify_on_start;
  bool will_notify_on_stop;
  bool handles_incremental_state_clear;
};

// This is implemented by the tracing service and represents the service-
// side instance for each ProducerClient.
interface ProducerHost {
  // Called by a ProducerClient to ask the service to:
  // 1) Move data from the shared memory buffer into the final tracing buffer
  //    owned by the service (through the |chunks_to_move|).
  // 2) Patch data (i.e. apply diff) that has been previously copied into the
  //    tracing buffer (if it's not been overwritten).
  // The service is robust in terms of tolerating malformed or malicious
  // requests. The callback is run after the service has handled the commit
  // request.
  CommitData(CommitDataRequest data_request) => ();

  // Called by a ProducerClient to let the Host know it can provide a specific
  // datasource.
  RegisterDataSource(DataSourceRegistration registration_info);

  // Called by the ProducerClient to associate a TraceWriter with a target
  // buffer, which is required to support scraping of the SMB by the service.
  RegisterTraceWriter(uint32 writer_id, uint32 target_buffer);
  UnregisterTraceWriter(uint32 writer_id);
};

// Any client wishing to provide tracing data to Perfetto, can implement
// this interface and use the PerfettoService interface within the tracing
// service to register itself.
interface ProducerClient {
  // Called when tracing is first enabled, before any data sources are started.
  OnTracingStart();

  // Called by Perfetto (via ProducerHost) to request a data source to start
  // logging.
  StartDataSource(uint64 id, DataSourceConfig data_source_config) => ();
  // Requesting a data source to stop logging again, with the id previously
  // sent in the StartDataSource call.
  StopDataSource(uint64 id) => ();
  Flush(uint64 flush_request_id, array<uint64> data_source_ids);
  ClearIncrementalState();
};

// This is implemented by the tracing service, and is essentially a singleton
// factory for establishing bi-directional communication with the Perfetto
// tracing system. A client that wishes to provide tracing data when requested,
// should implement ProducerClient for callbacks and pass along, together with
// the shared memory buffer that'll be used to pass the data.
interface PerfettoService {
  // Connect a new ProducerClient to a ProducerHost in the tracing service,
  // providing the shared memory buffer that will be used to send trace data.
  ConnectToProducerHost(pending_remote<ProducerClient> producer_client,
                        pending_receiver<ProducerHost> producer_host_receiver,
                        mojo_base.mojom.UnsafeSharedMemoryRegion shared_memory,
                        uint64 shared_memory_buffer_page_size_bytes);
};

// The policy for filling the trace buffer.
enum BufferFillPolicy {
  kUnspecified,
  // Overwrite old chunks for new ones.
  kRingBuffer,
  // Discard all chunks once the buffer is full.
  kDiscard
};

struct BufferConfig {
  // The size of a buffer that the Consumer can request Perfetto to allocate
  // and then configure specific data sources to be written into.
  uint32 size_kb;
  BufferFillPolicy fill_policy;
};

struct DataSource {
  DataSourceConfig config;
  array<string> producer_name_filter;
};

// Allows to disable the built-in data sources implicitly enabled in the
// tracing service. See comments in
// third_party/perfetto/protos/perfetto/config/trace_config.proto.
struct PerfettoBuiltinDataSource {
  bool disable_clock_snapshotting;
  bool disable_trace_config;
  bool disable_system_info;
  bool disable_service_events;
  int32 primary_trace_clock_id;
};

struct IncrementalStateConfig {
  // If set to a value > 0, this enables periodical ClearIncrementalState
  // messages to be sent to the producers registered for the session.
  uint32 clear_period_ms;
};

// The configuration provided by a Consumer to the Perfetto service which
// primarily configures which named data sources it would like to enable and
// receive tracing data from, and how large the destination buffers should be.
struct TraceConfig {
  array<DataSource> data_sources;
  PerfettoBuiltinDataSource perfetto_builtin_data_source;
  array<BufferConfig> buffers;
  IncrementalStateConfig incremental_state_config;

  uint32 duration_ms;
  bool write_into_file;
  mojo_base.mojom.Token? trace_uuid;
};

// The priority of the incoming EnableTracing request, used to determine
// whether the session should take precedence over another existing session,
// and/or whether a later session should abort the current one. Ordered in
// ascending priority.
enum TracingClientPriority {
  kUnknown,
  kBackground,
  kUserInitiated
};

// The ConsumerHost interface is a privileged interface which is implemented
// within the tracing service, and connected to by privileged clients
// (e.g. the browser process) to receive tracing data.
interface ConsumerHost {
  // Enable Perfetto tracing with the given TracingSessionClient interface for
  // signaling lifespan of the tracing session, and any future callbacks.
  // The given TracingSessionHost is used to control the tracing session and
  // closing it will disable tracing and free the session's trace buffers.
  // Note: Right now only a single concurrent tracing session is supported,
  // as there's no support for multiplexing enabled trace events to multiple
  // consumers. If a new tracing session is attempted while there's an existing
  // one in progress, the relative priorities (configured through
  // TracingClientPriority in the trace config) will be used to figure out
  // which one to be able to (keep) tracing; if the priorities are the same,
  // the new session will take precedence.
  EnableTracing(pending_receiver<TracingSessionHost> tracing_session_host,
                pending_remote<TracingSessionClient> tracing_session_client,
                TraceConfig config,
                mojo_base.mojom.File? output_file);
};

// Represents the host side of an active tracing session. Closing this
// will disable tracing.
interface TracingSessionHost {
  // Update the trace config for the active tracing session. Currently, only
  // (additive) updates to the |producer_name_filter| of a data source are
  // supported.
  ChangeTraceConfig(TraceConfig config);

  // Stop tracing for the active tracing session. Note that tracing may also
  // stop without an explicit call to DisableTracing(), e.g. when a tracing
  // duration is specified in the TraceConfig.
  DisableTracing();

  // Tell Perfetto we're ready to receive data, over the given data pipe.
  // The result callback will be called when there's no more data currently
  // available. If the TracingSessionClient is still active after the callback,
  // another call to ReadBuffers() needs to be made to receive any new
  // tracing data.
  ReadBuffers(handle<data_pipe_producer> stream) => ();

  // Request current trace buffer usage of the active session. Will be returned
  // as percentage value between 0.0f and 1.0f. |data_loss| indicates whether
  // any trace data is known to have been lost, e.g. because the ring buffer
  // wrapped and data were overridden.
  RequestBufferUsage() => (bool success, float percent_full, bool data_loss);

  // Disables tracing and converts the collected trace data converted into the
  // legacy JSON format before returning it via the data pipe. If
  // |agent_label_filter| is not empty, only data pertaining to the specified
  // tracing agent label (e.g. "traceEvents") will be returned.
  //
  // DEPRECATED: Existing usecases only; new use cases of tracing should use the
  // streaming proto format via ReadBuffers.
  DisableTracingAndEmitJson(string agent_label_filter,
                            handle<data_pipe_producer> stream,
                            bool privacy_filtering_enabled) => ();
};

// Any client connecting to ConsumerHost should implement this interface which
// represents the lifetime of an active tracing session, i.e. from the point
// where tracing is enabled, to the point where all tracing data has been
// received by the client.
interface TracingSessionClient {
  // Called when all processes have begun tracing.
  OnTracingEnabled();
  // Called when tracing is disabled; initiated either by a call to
  // TracingSessionHost::DisableTracing or by the service itself if a timeout is
  // specified in the tracing config.
  OnTracingDisabled(bool tracing_succeeded);
};