blob: 82e53f7bf263a27e22b66ac844e1e5737c4a395e [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACING_SERVICE_H_
#define INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACING_SERVICE_H_
#include <stdint.h>
#include <functional>
#include <memory>
#include <vector>
#include "perfetto/base/export.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/sys_types.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/ext/tracing/core/shared_memory.h"
#include "perfetto/tracing/buffer_exhausted_policy.h"
#include "perfetto/tracing/core/forward_decls.h"
namespace perfetto {
namespace base {
class TaskRunner;
} // namespace base
class Consumer;
class Producer;
class SharedMemoryArbiter;
class TraceWriter;
// TODO: for the moment this assumes that all the calls happen on the same
// thread/sequence. Not sure this will be the case long term in Chrome.
// The API for the Producer port of the Service.
// Subclassed by:
// 1. The tracing_service_impl.cc business logic when returning it in response
// to the ConnectProducer() method.
// 2. The transport layer (e.g., src/ipc) when the producer and
// the service don't talk locally but via some IPC mechanism.
class PERFETTO_EXPORT_COMPONENT ProducerEndpoint {
public:
virtual ~ProducerEndpoint();
// Disconnects the endpoint from the service, while keeping the shared memory
// valid. After calling this, the endpoint will no longer call any methods
// on the Producer.
virtual void Disconnect() = 0;
// Called by the Producer to (un)register data sources. Data sources are
// identified by their name (i.e. DataSourceDescriptor.name)
virtual void RegisterDataSource(const DataSourceDescriptor&) = 0;
virtual void UpdateDataSource(const DataSourceDescriptor&) = 0;
virtual void UnregisterDataSource(const std::string& name) = 0;
// Associate the trace writer with the given |writer_id| with
// |target_buffer|. The service may use this information to retrieve and
// copy uncommitted chunks written by the trace writer into its associated
// buffer, e.g. when a producer process crashes or when a flush is
// necessary.
virtual void RegisterTraceWriter(uint32_t writer_id,
uint32_t target_buffer) = 0;
// Remove the association of the trace writer previously created via
// RegisterTraceWriter.
virtual void UnregisterTraceWriter(uint32_t writer_id) = 0;
// Called by the Producer to signal that some pages in the shared memory
// buffer (shared between Service and Producer) have changed.
// When the Producer and the Service are hosted in the same process and
// hence potentially live on the same task runner, This method must call
// TracingServiceImpl's CommitData synchronously, without any PostTask()s,
// if on the same thread. This is to avoid a deadlock where the Producer
// exhausts its SMB and stalls waiting for the service to catch up with
// reads, but the Service never gets to that because it lives on the same
// thread.
using CommitDataCallback = std::function<void()>;
virtual void CommitData(const CommitDataRequest&,
CommitDataCallback callback = {}) = 0;
virtual SharedMemory* shared_memory() const = 0;
// Size of shared memory buffer pages. It's always a multiple of 4K.
// See shared_memory_abi.h
virtual size_t shared_buffer_page_size_kb() const = 0;
// Creates a trace writer, which allows to create events, handling the
// underying shared memory buffer and signalling to the Service. This method
// is thread-safe but the returned object is not. A TraceWriter should be
// used only from a single thread, or the caller has to handle sequencing
// via a mutex or equivalent. This method can only be called if
// TracingService::ConnectProducer was called with |in_process=true|.
// Args:
// |target_buffer| is the target buffer ID where the data produced by the
// writer should be stored by the tracing service. This value is passed
// upon creation of the data source (StartDataSource()) in the
// DataSourceConfig.target_buffer().
virtual std::unique_ptr<TraceWriter> CreateTraceWriter(
BufferID target_buffer,
BufferExhaustedPolicy buffer_exhausted_policy =
BufferExhaustedPolicy::kDefault) = 0;
// TODO(eseckler): Also expose CreateStartupTraceWriter() ?
// In some cases you can access the producer's SharedMemoryArbiter (for
// example if TracingService::ConnectProducer is called with
// |in_process=true|). The SharedMemoryArbiter can be used to create
// TraceWriters which is able to directly commit chunks. For the
// |in_process=true| case this can be done without going through an IPC layer.
virtual SharedMemoryArbiter* MaybeSharedMemoryArbiter() = 0;
// Whether the service accepted a shared memory buffer provided by the
// producer.
virtual bool IsShmemProvidedByProducer() const = 0;
// Called in response to a Producer::Flush(request_id) call after all data
// for the flush request has been committed.
virtual void NotifyFlushComplete(FlushRequestID) = 0;
// Called in response to one or more Producer::StartDataSource(),
// if the data source registered setting the flag
// DataSourceDescriptor.will_notify_on_start.
virtual void NotifyDataSourceStarted(DataSourceInstanceID) = 0;
// Called in response to one or more Producer::StopDataSource(),
// if the data source registered setting the flag
// DataSourceDescriptor.will_notify_on_stop.
virtual void NotifyDataSourceStopped(DataSourceInstanceID) = 0;
// This informs the service to activate any of these triggers if any tracing
// session was waiting for them.
virtual void ActivateTriggers(const std::vector<std::string>&) = 0;
// Emits a synchronization barrier to linearize with the service. When
// |callback| is invoked, the caller has the guarantee that the service has
// seen and processed all the requests sent by this producer prior to the
// Sync() call. Used mainly in tests.
virtual void Sync(std::function<void()> callback) = 0;
}; // class ProducerEndpoint.
// The API for the Consumer port of the Service.
// Subclassed by:
// 1. The tracing_service_impl.cc business logic when returning it in response
// to
// the ConnectConsumer() method.
// 2. The transport layer (e.g., src/ipc) when the consumer and
// the service don't talk locally but via some IPC mechanism.
class PERFETTO_EXPORT_COMPONENT ConsumerEndpoint {
public:
virtual ~ConsumerEndpoint();
// Enables tracing with the given TraceConfig. The ScopedFile argument is
// used only when TraceConfig.write_into_file == true.
// If TraceConfig.deferred_start == true data sources are configured via
// SetupDataSource() but are not started until StartTracing() is called.
// This is to support pre-initialization and fast triggering of traces.
// The ScopedFile argument is used only when TraceConfig.write_into_file
// == true.
virtual void EnableTracing(const TraceConfig&,
base::ScopedFile = base::ScopedFile()) = 0;
// Update the trace config of an existing tracing session; only a subset
// of options can be changed mid-session. Currently the only
// supported functionality is expanding the list of producer_name_filters()
// (or removing the filter entirely) for existing data sources.
virtual void ChangeTraceConfig(const TraceConfig&) = 0;
// Starts all data sources configured in the trace config. This is used only
// after calling EnableTracing() with TraceConfig.deferred_start=true.
// It's a no-op if called after a regular EnableTracing(), without setting
// deferred_start.
virtual void StartTracing() = 0;
virtual void DisableTracing() = 0;
// Clones an existing tracing session and attaches to it. The session is
// cloned in read-only mode and can only be used to read a snapshot of an
// existing tracing session. Will invoke Consumer::OnSessionCloned().
// If TracingSessionID == kBugreportSessionId (0xff...ff) the session with the
// highest bugreport score is cloned (if any exists).
// TODO(primiano): make pure virtual after various 3way patches.
virtual void CloneSession(TracingSessionID);
// Requests all data sources to flush their data immediately and invokes the
// passed callback once all of them have acked the flush (in which case
// the callback argument |success| will be true) or |timeout_ms| are elapsed
// (in which case |success| will be false).
// If |timeout_ms| is 0 the TraceConfig's flush_timeout_ms is used, or,
// if that one is not set (or is set to 0), kDefaultFlushTimeoutMs (5s) is
// used.
using FlushCallback = std::function<void(bool /*success*/)>;
virtual void Flush(uint32_t timeout_ms, FlushCallback) = 0;
// Tracing data will be delivered invoking Consumer::OnTraceData().
virtual void ReadBuffers() = 0;
virtual void FreeBuffers() = 0;
// Will call OnDetach().
virtual void Detach(const std::string& key) = 0;
// Will call OnAttach().
virtual void Attach(const std::string& key) = 0;
// Will call OnTraceStats().
virtual void GetTraceStats() = 0;
// Start or stop observing events of selected types. |events_mask| specifies
// the types of events to observe in a bitmask of ObservableEvents::Type.
// To disable observing, pass 0.
// Will call OnObservableEvents() repeatedly whenever an event of an enabled
// ObservableEventType occurs.
// TODO(eseckler): Extend this to support producers & data sources.
virtual void ObserveEvents(uint32_t events_mask) = 0;
// Used to obtain the list of connected data sources and other info about
// the tracing service.
using QueryServiceStateCallback =
std::function<void(bool success, const TracingServiceState&)>;
virtual void QueryServiceState(QueryServiceStateCallback) = 0;
// Used for feature detection. Makes sense only when the consumer and the
// service talk over IPC and can be from different versions.
using QueryCapabilitiesCallback =
std::function<void(const TracingServiceCapabilities&)>;
virtual void QueryCapabilities(QueryCapabilitiesCallback) = 0;
// If any tracing session with TraceConfig.bugreport_score > 0 is running,
// this will pick the highest-score one, stop it and save it into a fixed
// path (See kBugreportTracePath).
// The callback is invoked when the file has been saved, in case of success,
// or whenever an error occurs.
// Args:
// - success: if true, an eligible trace was found and saved into file.
// If false, either there was no eligible trace running or
// something else failed (See |msg|).
// - msg: human readable diagnostic messages to debug failures.
using SaveTraceForBugreportCallback =
std::function<void(bool /*success*/, const std::string& /*msg*/)>;
virtual void SaveTraceForBugreport(SaveTraceForBugreportCallback) = 0;
}; // class ConsumerEndpoint.
// The public API of the tracing Service business logic.
//
// Exposed to:
// 1. The transport layer (e.g., src/unix_rpc/unix_service_host.cc),
// which forwards commands received from a remote producer or consumer to
// the actual service implementation.
// 2. Tests.
//
// Subclassed by:
// The service business logic in src/core/tracing_service_impl.cc.
class PERFETTO_EXPORT_COMPONENT TracingService {
public:
using ProducerEndpoint = perfetto::ProducerEndpoint;
using ConsumerEndpoint = perfetto::ConsumerEndpoint;
// Default sizes used by the service implementation and client library.
static constexpr size_t kDefaultShmPageSize = 4096ul;
static constexpr size_t kDefaultShmSize = 256 * 1024ul;
enum class ProducerSMBScrapingMode {
// Use service's default setting for SMB scraping. Currently, the default
// mode is to disable SMB scraping, but this may change in the future.
kDefault,
// Enable scraping of uncommitted chunks in producers' shared memory
// buffers.
kEnabled,
// Disable scraping of uncommitted chunks in producers' shared memory
// buffers.
kDisabled
};
// Implemented in src/core/tracing_service_impl.cc .
static std::unique_ptr<TracingService> CreateInstance(
std::unique_ptr<SharedMemory::Factory>,
base::TaskRunner*);
virtual ~TracingService();
// Connects a Producer instance and obtains a ProducerEndpoint, which is
// essentially a 1:1 channel between one Producer and the Service.
//
// The caller has to guarantee that the passed Producer will be alive as long
// as the returned ProducerEndpoint is alive. Both the passed Producer and the
// returned ProducerEndpoint must live on the same task runner of the service,
// specifically:
// 1) The Service will call Producer::* methods on the Service's task runner.
// 2) The Producer should call ProducerEndpoint::* methods only on the
// service's task runner, except for ProducerEndpoint::CreateTraceWriter(),
// which can be called on any thread. To disconnect just destroy the
// returned ProducerEndpoint object. It is safe to destroy the Producer
// once the Producer::OnDisconnect() has been invoked.
//
// |uid| is the trusted user id of the producer process, used by the consumers
// for validating the origin of trace data. |shared_memory_size_hint_bytes|
// and |shared_memory_page_size_hint_bytes| are optional hints on the size of
// the shared memory buffer and its pages. The service can ignore the hints
// (e.g., if the hints are unreasonably large or other sizes were configured
// in a tracing session's config). |in_process| enables the ProducerEndpoint
// to manage its own shared memory and enables use of
// |ProducerEndpoint::CreateTraceWriter|.
//
// The producer can optionally provide a non-null |shm|, which the service
// will adopt for the connection to the producer, provided it is correctly
// sized. In this case, |shared_memory_page_size_hint_bytes| indicates the
// page size used in this SMB. The producer can use this mechanism to record
// tracing data to an SMB even before the tracing session is started by the
// service. This is used in Chrome to implement startup tracing. If the buffer
// is incorrectly sized, the service will discard the SMB and allocate a new
// one, provided to the producer via ProducerEndpoint::shared_memory() after
// OnTracingSetup(). To verify that the service accepted the SMB, the producer
// may check via ProducerEndpoint::IsShmemProvidedByProducer(). If the service
// accepted the SMB, the producer can then commit any data that is already in
// the SMB after the tracing session was started by the service via
// Producer::StartDataSource(). The |shm| will also be rejected when
// connecting to a service that is too old (pre Android-11).
//
// Can return null in the unlikely event that service has too many producers
// connected.
virtual std::unique_ptr<ProducerEndpoint> ConnectProducer(
Producer*,
uid_t uid,
pid_t pid,
const std::string& name,
size_t shared_memory_size_hint_bytes = 0,
bool in_process = false,
ProducerSMBScrapingMode smb_scraping_mode =
ProducerSMBScrapingMode::kDefault,
size_t shared_memory_page_size_hint_bytes = 0,
std::unique_ptr<SharedMemory> shm = nullptr,
const std::string& sdk_version = {}) = 0;
// Connects a Consumer instance and obtains a ConsumerEndpoint, which is
// essentially a 1:1 channel between one Consumer and the Service.
// The caller has to guarantee that the passed Consumer will be alive as long
// as the returned ConsumerEndpoint is alive.
// To disconnect just destroy the returned ConsumerEndpoint object. It is safe
// to destroy the Consumer once the Consumer::OnDisconnect() has been invoked.
virtual std::unique_ptr<ConsumerEndpoint> ConnectConsumer(Consumer*,
uid_t) = 0;
// Enable/disable scraping of chunks in the shared memory buffer. If enabled,
// the service will copy uncommitted but non-empty chunks from the SMB when
// flushing (e.g. to handle unresponsive producers or producers unable to
// flush their active chunks), on producer disconnect (e.g. to recover data
// from crashed producers), and after disabling a tracing session (e.g. to
// gather data from producers that didn't stop their data sources in time).
//
// This feature is currently used by Chrome.
virtual void SetSMBScrapingEnabled(bool enabled) = 0;
};
} // namespace perfetto
#endif // INCLUDE_PERFETTO_EXT_TRACING_CORE_TRACING_SERVICE_H_