1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
|
// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_TRACING_TRACING_SCENARIO_H_
#define CONTENT_BROWSER_TRACING_TRACING_SCENARIO_H_
#include "base/cancelable_callback.h"
#include "base/memory/weak_ptr.h"
#include "base/sequence_checker.h"
#include "base/task/sequenced_task_runner.h"
#include "base/token.h"
#include "base/trace_event/trace_config.h"
#include "base/unguessable_token.h"
#include "content/browser/tracing/background_tracing_rule.h"
#include "content/common/content_export.h"
#include "services/tracing/public/cpp/perfetto/perfetto_config.h"
#include "third_party/perfetto/include/perfetto/tracing/tracing.h"
#include "third_party/perfetto/protos/perfetto/config/chrome/scenario_config.gen.h"
namespace content {
class CONTENT_EXPORT TracingScenarioBase {
public:
virtual ~TracingScenarioBase();
// Disables a scenario.
virtual void Disable();
// Enables a disabled scenario.
virtual void Enable();
const std::string& scenario_name() const { return scenario_name_; }
protected:
explicit TracingScenarioBase(std::string scenario_name);
virtual bool OnStartTrigger(const BackgroundTracingRule* rule) = 0;
virtual bool OnStopTrigger(const BackgroundTracingRule* rule) = 0;
virtual bool OnUploadTrigger(const BackgroundTracingRule* rule) = 0;
uint32_t TriggerNameHash(const BackgroundTracingRule* triggered_rule) const;
std::vector<std::unique_ptr<BackgroundTracingRule>> start_rules_;
std::vector<std::unique_ptr<BackgroundTracingRule>> stop_rules_;
std::vector<std::unique_ptr<BackgroundTracingRule>> upload_rules_;
std::string scenario_name_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
SEQUENCE_CHECKER(sequence_checker_);
};
// NestedTracingScenario manages triggers for a single nested tracing
// scenario. Unlike TracingScenario below, it doesn't manage a tracing
// session, but inherits from the parent's session instead.
class CONTENT_EXPORT NestedTracingScenario : public TracingScenarioBase {
public:
enum class State {
// The scenario is disabled and no rule is installed.
kDisabled,
// The scenario is enabled, start rules are installed and
// OnNestedScenarioStart() is called.
kEnabled,
// The tracing session is active and stop/upload rules are installed.
kActive,
// A stop rule was triggered and only upload rules are installed.
// After stopping, the nested scenario becomes kDisabled and
// OnNestedScenarioStop() is called.
kStopping,
};
// The delegate gets notified of state transitions and receives traces.
class Delegate {
public:
// Called when a start rule is triggered and |scenario| becomes kActive.
virtual void OnNestedScenarioStart(
NestedTracingScenario* active_scenario) = 0;
// Called when a stop rule is triggered and |scenario| becomes kStopping.
// Disable() is expected to be called shortly after.
virtual void OnNestedScenarioStop(NestedTracingScenario* idle_scenario) = 0;
// Called when an upload rule is triggered and |scenario| becomes kDisabled.
virtual void OnNestedScenarioUpload(
NestedTracingScenario* scenario,
const BackgroundTracingRule* triggered_rule) = 0;
protected:
~Delegate() = default;
};
static std::unique_ptr<NestedTracingScenario> Create(
const perfetto::protos::gen::NestedScenarioConfig& config,
Delegate* scenario_delegate);
~NestedTracingScenario() override;
// Disables a scenario.
void Disable() override;
// Enables a disabled scenario. Cannot be called after the scenario is
// enabled.
void Enable() override;
// Request to stop an active scenario. Upload rules are still active until
// Disable() is called.
void Stop();
State current_state() const { return current_state_; }
protected:
NestedTracingScenario(
const perfetto::protos::gen::NestedScenarioConfig& config,
Delegate* scenario_delegate);
bool Initialize(const perfetto::protos::gen::NestedScenarioConfig& config);
private:
bool OnStartTrigger(const BackgroundTracingRule* rule) override;
bool OnStopTrigger(const BackgroundTracingRule* rule) override;
bool OnUploadTrigger(const BackgroundTracingRule* rule) override;
void SetState(State new_state);
State current_state_ = State::kDisabled;
raw_ptr<Delegate> scenario_delegate_;
};
// TracingScenario manages triggers and tracing session for a single field
// tracing scenario. TracingScenario allows for multiple scenarios to be enabled
// and watch for rules at once, and is meant to replace
// BackgroundTracingActiveScenario.
// TODO(crbug.com/40257548): Update the comment above once
// BackgroundTracingActiveScenario is deleted.
class CONTENT_EXPORT TracingScenario : public TracingScenarioBase,
public NestedTracingScenario::Delegate {
public:
enum class State {
// The scenario is disabled and no rule is installed.
kDisabled,
// The scenario is enabled and setup/start rules are installed.
kEnabled,
// The tracing session was setup and the scenario is ready to start.
kSetup,
// The tracing session is starting.
kStarting,
// The tracing session is recording.
kRecording,
// A stop rule was triggered and the tracing session is stopping.
kStopping,
// An upload rule was triggered and the tracing session is finalizing.
kFinalizing,
// A nested upload rule was triggered and the tracing session is being
// cloned.
kCloning
};
// The delegate gets notified of state transitions and receives traces.
class Delegate {
public:
// Called when |scenario| becomes active, i.e. kSetup or kRecoding. Returns
// true if tracing is allowed to begin.
virtual bool OnScenarioActive(TracingScenario* scenario) = 0;
// Called when |scenario| becomes idle again. Returns true if tracing is
// allowed to save.
virtual bool OnScenarioIdle(TracingScenario* scenario) = 0;
// Called when a trace from |scenario| is cloned, returns true if tracing
// is allowed to save.
virtual bool OnScenarioCloned(TracingScenario* scenario) = 0;
// Called when |scenario| starts recording a trace.
virtual void OnScenarioRecording(TracingScenario* scenario) = 0;
// Called when |scenario| has an error.
virtual void OnScenarioError(TracingScenario* scenario,
perfetto::TracingError error) = 0;
// Called when a trace was collected.
virtual void SaveTrace(TracingScenario* scenario,
base::Token trace_uuid,
const BackgroundTracingRule* triggered_rule,
std::string&& serialized_trace) = 0;
protected:
~Delegate() = default;
};
static std::unique_ptr<TracingScenario> Create(
const perfetto::protos::gen::ScenarioConfig& config,
bool enable_privacy_filter,
bool is_local_scenario,
bool enable_package_name_filter,
bool request_startup_tracing,
Delegate* scenario_delegate);
~TracingScenario() override;
// Disables an enabled but non-active scenario. Cannot be called after the
// scenario activates.
void Disable() override;
// Enables a disabled scenario. Cannot be called after the scenario is
// enabled.
void Enable() override;
// Aborts an active scenario.
void Abort();
void GenerateMetadataProto(
perfetto::protos::pbzero::ChromeMetadataPacket* metadata);
State current_state() const { return current_state_; }
bool privacy_filter_enabled() const { return privacy_filtering_enabled_; }
bool is_local_scenario() const { return is_local_scenario_; }
base::Token GetSessionID() const { return session_id_; }
protected:
TracingScenario(const perfetto::protos::gen::ScenarioConfig& config,
Delegate* scenario_delegate,
bool enable_privacy_filter,
bool is_local_scenario,
bool request_startup_tracing);
bool Initialize(const perfetto::protos::gen::ScenarioConfig& config,
bool enable_package_name_filter);
virtual std::unique_ptr<perfetto::TracingSession> CreateTracingSession();
private:
// Helper deleter to automatically clear on-error callback from
// perfetto::TracingSession. Without clearing the callback, it is
// invoked whenever a session is deleted.
struct TracingSessionDeleter {
TracingSessionDeleter() = default;
// NOLINTNEXTLINE(google-explicit-constructor)
TracingSessionDeleter(std::default_delete<perfetto::TracingSession>) {}
void operator()(perfetto::TracingSession* ptr) const;
};
using TracingSession =
std::unique_ptr<perfetto::TracingSession, TracingSessionDeleter>;
class TraceReader;
void SetupTracingSession();
void OnTracingError(perfetto::TracingError error);
void OnTracingStop();
void OnTracingStart();
void OnTracingCloned();
void OnFinalizingDone(base::Token trace_uuid,
std::string&& serialized_trace,
TracingSession tracing_session,
const BackgroundTracingRule* triggered_rule);
void DisableNestedScenarios();
// NestedTracingScenario::Delegate:
// When called, the base scenario stop rules are uninstalled and other
// nested scenarios are disabled.
void OnNestedScenarioStart(NestedTracingScenario* scenario) override;
// When called, the base scenario remains active and becomes the leaf; stop
// rules are installed again and all nested scenarios are enabled.
void OnNestedScenarioStop(NestedTracingScenario* scenario) override;
// When called, all rules are uinstalled and the tracing session is
// stopped and finalized.
void OnNestedScenarioUpload(
NestedTracingScenario* scenario,
const BackgroundTracingRule* triggered_rule) override;
bool OnSetupTrigger(const BackgroundTracingRule* rule);
bool OnStartTrigger(const BackgroundTracingRule* rule) override;
bool OnStopTrigger(const BackgroundTracingRule* rule) override;
bool OnUploadTrigger(const BackgroundTracingRule* rule) override;
base::WeakPtr<TracingScenario> GetWeakPtr();
void SetState(State new_state);
const bool privacy_filtering_enabled_;
const bool is_local_scenario_;
const bool request_startup_tracing_;
const bool use_system_backend_ = false;
State current_state_ = State::kDisabled;
std::vector<std::unique_ptr<BackgroundTracingRule>> setup_rules_;
std::vector<std::unique_ptr<NestedTracingScenario>> nested_scenarios_;
raw_ptr<NestedTracingScenario> active_scenario_{nullptr};
base::CancelableOnceClosure on_nested_stopped_;
perfetto::TraceConfig trace_config_;
raw_ptr<Delegate> scenario_delegate_;
TracingSession tracing_session_;
base::Token session_id_;
base::UnguessableToken session_unguessable_name_;
raw_ptr<const BackgroundTracingRule> triggered_rule_;
// NOTE: Weak pointers must be invalidated before all other member variables.
base::WeakPtrFactory<TracingScenario> weak_ptr_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_TRACING_TRACING_SCENARIO_H_
|