blob: 96230c970b8025f49a63d4654c9e0f36efc32859 [file] [edit]
/*
* Copyright (C) 2025 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 SRC_TRACING_SERVICE_TRACING_SERVICE_SESSION_H_
#define SRC_TRACING_SERVICE_TRACING_SERVICE_SESSION_H_
#include <algorithm>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <tuple>
#include <vector>
#include "perfetto/base/logging.h"
#include "perfetto/ext/base/circular_queue.h"
#include "perfetto/ext/base/clock_snapshots.h"
#include "perfetto/ext/base/periodic_task.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/base/scoped_sched_boost.h"
#include "perfetto/ext/base/uuid.h"
#include "perfetto/ext/tracing/core/basic_types.h"
#include "perfetto/tracing/core/data_source_config.h"
#include "perfetto/tracing/core/trace_config.h"
#include "src/tracing/service/tracing_service_structs.h"
namespace protozero {
class MessageFilter;
}
namespace perfetto {
namespace protos {
namespace gen {
enum TraceStats_FinalFlushOutcome : int;
}
} // namespace protos
namespace base {
class TaskRunner;
}
namespace tracing_service {
class ConsumerEndpointImpl;
// Holds the state of a tracing session. A tracing session is uniquely bound
// a specific Consumer. Each Consumer can own one or more sessions.
struct TracingSession {
enum State {
DISABLED = 0,
CONFIGURED,
STARTED,
DISABLING_WAITING_STOP_ACKS,
CLONED_READ_ONLY,
};
TracingSession(TracingSessionID,
ConsumerEndpointImpl*,
const TraceConfig&,
base::TaskRunner*);
TracingSession(TracingSession&&) = delete;
TracingSession& operator=(TracingSession&&) = delete;
size_t num_buffers() const { return buffers_index.size(); }
uint32_t flush_timeout_ms() {
uint32_t timeout_ms = config.flush_timeout_ms();
return timeout_ms ? timeout_ms : kDefaultFlushTimeoutMs;
}
uint32_t data_source_stop_timeout_ms() {
uint32_t timeout_ms = config.data_source_stop_timeout_ms();
return timeout_ms ? timeout_ms : kDataSourceStopTimeoutMs;
}
PacketSequenceID GetPacketSequenceID(MachineID, ProducerID, WriterID);
DataSourceInstance* GetDataSourceInstance(ProducerID, DataSourceInstanceID);
bool AllDataSourceInstancesStarted();
bool AllDataSourceInstancesStopped();
// Checks whether |clone_uid| is allowed to clone the current tracing
// session.
bool IsCloneAllowed(uid_t clone_uid) const;
const TracingSessionID id;
// The consumer that started the session.
// Can be nullptr if the consumer detached from the session.
ConsumerEndpointImpl* consumer_maybe_null;
// Unix uid of the consumer. This is valid even after the consumer detaches
// and does not change for the entire duration of the session. It is used to
// prevent that a consumer re-attaches to a session from a different uid.
uid_t const consumer_uid;
// The list of triggers this session received while alive and the time they
// were received at. This is used to insert 'fake' packets back to the
// consumer so they can tell when some event happened. The order matches the
// order they were received.
std::vector<TriggerInfo> received_triggers;
// The trace config provided by the Consumer when calling
// EnableTracing(), plus any updates performed by ChangeTraceConfig.
TraceConfig config;
// List of data source instances that have been enabled on the various
// producers for this tracing session.
std::multimap<ProducerID, DataSourceInstance> data_source_instances;
// For each Flush(N) request, keeps track of the set of producers for which
// we are still awaiting a NotifyFlushComplete(N) ack.
std::map<FlushRequestID, PendingFlush> pending_flushes;
// For each Clone request, keeps track of the flushes acknowledgement that
// we are still waiting for.
std::map<PendingCloneID, PendingClone> pending_clones;
PendingCloneID last_pending_clone_id_ = 0;
// Maps a per-trace-session buffer index into the corresponding global
// BufferID (shared namespace amongst all consumers). This vector has as
// many entries as |config.buffers_size()|.
std::vector<BufferID> buffers_index;
std::map<std::tuple<MachineID, ProducerID, WriterID>, PacketSequenceID>
packet_sequence_ids;
PacketSequenceID last_packet_sequence_id = kServicePacketSequenceID;
// Whether we should emit the trace stats next time we reach EOF while
// performing ReadBuffers.
bool should_emit_stats = false;
// Whether we should emit the sync marker the next time ReadBuffers() is
// called.
bool should_emit_sync_marker = false;
// Whether we put the initial packets (trace config, system info,
// etc.) into the trace output yet.
bool did_emit_initial_packets = false;
// Whether we emitted clock offsets for relay clients yet.
bool did_emit_remote_clock_sync_ = false;
// Whether we should compress TracePackets after reading them.
bool compress_deflate = false;
// The number of received triggers we've emitted into the trace output.
size_t num_triggers_emitted_into_trace = 0;
// Packets that failed validation of the TrustedPacket.
uint64_t invalid_packets = 0;
// Flush() stats. See comments in trace_stats.proto for more.
uint64_t flushes_requested = 0;
uint64_t flushes_succeeded = 0;
uint64_t flushes_failed = 0;
// Outcome of the final Flush() done by FlushAndDisableTracing().
protos::gen::TraceStats_FinalFlushOutcome final_flush_outcome{};
// Set to true on the first call to MaybeNotifyAllDataSourcesStarted().
bool did_notify_all_data_source_started = false;
// Stores simple lifecycle events of a particular type (i.e. associated with
// a single field id in the TracingServiceEvent proto).
struct LifecycleEvent {
explicit LifecycleEvent(uint32_t f_id, uint32_t m_size = 1)
: field_id(f_id), max_size(m_size), timestamps(m_size) {}
// The field id of the event in the TracingServiceEvent proto.
uint32_t field_id;
// Stores the max size of |timestamps|. Set to 1 by default (in
// the constructor) but can be overridden in TraceSession constructor
// if a larger size is required.
uint32_t max_size;
// Stores the timestamps emitted for each event type (in nanoseconds).
// Emitted into the trace and cleared when the consumer next calls
// ReadBuffers.
base::CircularQueue<int64_t> timestamps;
};
std::vector<LifecycleEvent> lifecycle_events;
// Stores arbitrary lifecycle events that don't fit in lifecycle_events as
// serialized TracePacket protos.
struct ArbitraryLifecycleEvent {
int64_t timestamp;
std::vector<uint8_t> data;
};
std::optional<ArbitraryLifecycleEvent> slow_start_event;
std::vector<ArbitraryLifecycleEvent> last_flush_events;
// If this is a cloned tracing session, the timestamp at which each buffer
// was cloned.
std::vector<int64_t> buffer_cloned_timestamps;
using ClockSnapshotData = base::ClockSnapshotVector;
// Initial clock snapshot, captured at trace start time (when state goes to
// TracingSession::STARTED). Emitted into the trace when the consumer first
// calls ReadBuffers().
ClockSnapshotData initial_clock_snapshot;
// Stores clock snapshots to emit into the trace as a ring buffer. This
// buffer is populated both periodically and when lifecycle events happen
// but only when significant clock drift is detected. Emitted into the trace
// and cleared when the consumer next calls ReadBuffers().
base::CircularQueue<ClockSnapshotData> clock_snapshot_ring_buffer;
State state = DISABLED;
// If the consumer detached the session, this variable defines the key used
// for identifying the session later when reattaching.
std::string detach_key;
// This is set when the Consumer calls sets |write_into_file| == true in the
// TraceConfig. In this case this represents the file we should stream the
// trace packets into, rather than returning it to the consumer via
// OnTraceData().
base::ScopedFile write_into_file;
uint32_t write_period_ms = 0;
// Flush strategy for the tracing session:
// * kDisabled: default, no periodic or on-write flushing is performed.
// * kOnWrite: Buffers are flushed every time data is written to the output
// file.
// * kPeriodic: Buffers are flushed periodically based on the value of
// periodic_flush_ms.
enum class FlushStrategy : uint8_t { kDisabled, kOnWrite, kPeriodic };
FlushStrategy flush_strategy = FlushStrategy::kDisabled;
uint32_t periodic_flush_ms = 0;
bool fflush_post_write = false;
uint64_t max_file_size_bytes = 0;
uint64_t bytes_written_into_file = 0;
// Periodic task for snapshotting service events (e.g. clocks, sync markers
// etc)
base::PeriodicTask snapshot_periodic_task;
// Deferred task that stops the trace when |duration_ms| expires. This is
// to handle the case of |prefer_suspend_clock_for_duration| which cannot
// use PostDelayedTask.
base::PeriodicTask timed_stop_task;
// When non-NULL the packets should be post-processed using the filter.
std::unique_ptr<protozero::MessageFilter> trace_filter;
uint64_t filter_input_packets = 0;
uint64_t filter_input_bytes = 0;
uint64_t filter_output_bytes = 0;
uint64_t filter_errors = 0;
uint64_t filter_time_taken_ns = 0;
std::vector<uint64_t> filter_bytes_discarded_per_buffer;
// A randomly generated trace identifier. Note that this does NOT always
// match the requested TraceConfig.trace_uuid_msb/lsb. Specifically, it does
// until a gap-less snapshot is requested. Each snapshot re-generates the
// uuid to avoid emitting two different traces with the same uuid.
base::Uuid trace_uuid;
// This is set when the clone operation was caused by a clone trigger.
std::optional<TriggerInfo> clone_trigger;
std::optional<base::ScopedSchedBoost> priority_boost;
// NOTE: when adding new fields here consider whether that state should be
// copied over in DoCloneSession() or not. Ask yourself: is this a
// "runtime state" (e.g. active data sources) or a "trace (meta)data state"?
// If the latter, it should be handled by DoCloneSession()).
};
} // namespace tracing_service
} // namespace perfetto
#endif // SRC_TRACING_SERVICE_TRACING_SERVICE_SESSION_H_