1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/tracing/background_tracing_manager_impl.h"
6
7 #include <utility>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/json/json_writer.h"
12 #include "base/location.h"
13 #include "base/macros.h"
14 #include "base/metrics/histogram_macros.h"
15 #include "base/no_destructor.h"
16 #include "base/single_thread_task_runner.h"
17 #include "base/task/post_task.h"
18 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/time.h"
20 #include "base/values.h"
21 #include "components/tracing/common/trace_startup_config.h"
22 #include "content/browser/tracing/background_memory_tracing_observer.h"
23 #include "content/browser/tracing/background_startup_tracing_observer.h"
24 #include "content/browser/tracing/background_tracing_active_scenario.h"
25 #include "content/browser/tracing/background_tracing_agent_client_impl.h"
26 #include "content/browser/tracing/background_tracing_rule.h"
27 #include "content/browser/tracing/tracing_controller_impl.h"
28 #include "content/common/child_process.mojom.h"
29 #include "content/public/browser/browser_child_process_host.h"
30 #include "content/public/browser/browser_task_traits.h"
31 #include "content/public/browser/browser_thread.h"
32 #include "content/public/browser/child_process_data.h"
33 #include "content/public/browser/content_browser_client.h"
34 #include "content/public/browser/render_process_host.h"
35 #include "content/public/browser/tracing_delegate.h"
36 #include "content/public/common/child_process_host.h"
37 #include "content/public/common/content_client.h"
38 #include "content/public/common/content_switches.h"
39 #include "services/tracing/public/cpp/perfetto/trace_event_data_source.h"
40 #include "services/tracing/public/cpp/trace_event_agent.h"
41 #include "services/tracing/public/cpp/tracing_features.h"
42
43 namespace content {
44
45 // static
RecordMetric(Metrics metric)46 void BackgroundTracingManagerImpl::RecordMetric(Metrics metric) {
47 UMA_HISTOGRAM_ENUMERATION("Tracing.Background.ScenarioState", metric,
48 Metrics::NUMBER_OF_BACKGROUND_TRACING_METRICS);
49 }
50
51 // static
GetInstance()52 BackgroundTracingManager* BackgroundTracingManager::GetInstance() {
53 return BackgroundTracingManagerImpl::GetInstance();
54 }
55
56 // static
GetInstance()57 BackgroundTracingManagerImpl* BackgroundTracingManagerImpl::GetInstance() {
58 static base::NoDestructor<BackgroundTracingManagerImpl> manager;
59 return manager.get();
60 }
61
62 // static
ActivateForProcess(int child_process_id,mojom::ChildProcess * child_process)63 void BackgroundTracingManagerImpl::ActivateForProcess(
64 int child_process_id,
65 mojom::ChildProcess* child_process) {
66 // NOTE: Called from any thread.
67
68 mojo::PendingRemote<tracing::mojom::BackgroundTracingAgentProvider>
69 pending_provider;
70 child_process->GetBackgroundTracingAgentProvider(
71 pending_provider.InitWithNewPipeAndPassReceiver());
72
73 base::PostTask(FROM_HERE, {BrowserThread::UI},
74 base::BindOnce(&BackgroundTracingManagerImpl::AddPendingAgent,
75 child_process_id, std::move(pending_provider)));
76 }
77
BackgroundTracingManagerImpl()78 BackgroundTracingManagerImpl::BackgroundTracingManagerImpl()
79 : delegate_(GetContentClient()->browser()->GetTracingDelegate()),
80 trigger_handle_ids_(0) {
81 AddEnabledStateObserver(BackgroundMemoryTracingObserver::GetInstance());
82 AddEnabledStateObserver(BackgroundStartupTracingObserver::GetInstance());
83 }
84
85 BackgroundTracingManagerImpl::~BackgroundTracingManagerImpl() = default;
86
AddMetadataGeneratorFunction()87 void BackgroundTracingManagerImpl::AddMetadataGeneratorFunction() {
88 tracing::TraceEventAgent::GetInstance()->AddMetadataGeneratorFunction(
89 base::BindRepeating(&BackgroundTracingManagerImpl::GenerateMetadataDict,
90 base::Unretained(this)));
91 tracing::TraceEventMetadataSource::GetInstance()->AddGeneratorFunction(
92 base::BindRepeating(&BackgroundTracingManagerImpl::GenerateMetadataProto,
93 base::Unretained(this)));
94 }
95
SetActiveScenario(std::unique_ptr<BackgroundTracingConfig> config,BackgroundTracingManager::ReceiveCallback receive_callback,DataFiltering data_filtering)96 bool BackgroundTracingManagerImpl::SetActiveScenario(
97 std::unique_ptr<BackgroundTracingConfig> config,
98 BackgroundTracingManager::ReceiveCallback receive_callback,
99 DataFiltering data_filtering) {
100 DCHECK_CURRENTLY_ON(BrowserThread::UI);
101 if (config) {
102 RecordMetric(Metrics::SCENARIO_ACTIVATION_REQUESTED);
103 }
104
105 if (active_scenario_ && (active_scenario_->state() !=
106 BackgroundTracingActiveScenario::State::kIdle)) {
107 return false;
108 }
109
110 // If we don't have a high resolution timer available, traces will be
111 // too inaccurate to be useful.
112 if (!base::TimeTicks::IsHighResolution()) {
113 if (config) {
114 RecordMetric(Metrics::SCENARIO_ACTION_FAILED_LOWRES_CLOCK);
115 }
116 return false;
117 }
118
119 std::unique_ptr<BackgroundTracingConfigImpl> config_impl(
120 static_cast<BackgroundTracingConfigImpl*>(config.release()));
121 config_impl = BackgroundStartupTracingObserver::GetInstance()
122 ->IncludeStartupConfigIfNeeded(std::move(config_impl));
123 if (BackgroundStartupTracingObserver::GetInstance()
124 ->enabled_in_current_session()) {
125 // Anonymize data for startup tracing by default. We currently do not
126 // support storing the config in preferences for next session.
127 data_filtering = DataFiltering::ANONYMIZE_DATA;
128 RecordMetric(Metrics::STARTUP_SCENARIO_TRIGGERED);
129 } else {
130 // If startup config was not set and we're not a SYSTEM scenario (system
131 // might already have started a trace in the background) but tracing was
132 // enabled, then do not set any scenario.
133 if (base::trace_event::TraceLog::GetInstance()->IsEnabled() &&
134 config_impl &&
135 config_impl->tracing_mode() != BackgroundTracingConfigImpl::SYSTEM) {
136 return false;
137 }
138 }
139
140 if (!config_impl) {
141 return false;
142 }
143
144 bool requires_anonymized_data = (data_filtering == ANONYMIZE_DATA);
145 config_impl->set_requires_anonymized_data(requires_anonymized_data);
146
147 // If the profile hasn't loaded or been created yet, this is a startup
148 // scenario and we have to wait until initialization is finished to validate
149 // that the scenario can run.
150 if (!delegate_ || delegate_->IsProfileLoaded()) {
151 // TODO(oysteine): Retry when time_until_allowed has elapsed.
152 if (config_impl && delegate_ &&
153 !delegate_->IsAllowedToBeginBackgroundScenario(
154 *config_impl.get(), requires_anonymized_data)) {
155 return false;
156 }
157 } else {
158 base::ThreadTaskRunnerHandle::Get()->PostTask(
159 FROM_HERE,
160 base::BindOnce(&BackgroundTracingManagerImpl::ValidateStartupScenario,
161 base::Unretained(this)));
162 }
163
164 // No point in tracing if there's nowhere to send it.
165 if (config_impl && receive_callback.is_null()) {
166 return false;
167 }
168
169 active_scenario_ = std::make_unique<BackgroundTracingActiveScenario>(
170 std::move(config_impl), std::move(receive_callback),
171 base::BindOnce(&BackgroundTracingManagerImpl::OnScenarioAborted,
172 base::Unretained(this)));
173
174 // Notify observers before starting tracing.
175 for (auto* observer : background_tracing_observers_) {
176 observer->OnScenarioActivated(active_scenario_->GetConfig());
177 }
178
179 active_scenario_->StartTracingIfConfigNeedsIt();
180 RecordMetric(Metrics::SCENARIO_ACTIVATED_SUCCESSFULLY);
181
182 return true;
183 }
184
HasActiveScenario()185 bool BackgroundTracingManagerImpl::HasActiveScenario() {
186 return !!active_scenario_;
187 }
188
HasTraceToUpload()189 bool BackgroundTracingManagerImpl::HasTraceToUpload() {
190 DCHECK_CURRENTLY_ON(BrowserThread::UI);
191 // Send the logs only when the trace size is within limits. If the connection
192 // type changes and we have a bigger than expected trace, then the next time
193 // service asks us when wifi is available, the trace will be sent. If we did
194 // collect a trace that is bigger than expected, then we will end up never
195 // uploading, and drop the trace. This should never happen because the trace
196 // buffer limits are set appropriately.
197 if (trace_to_upload_.empty()) {
198 return false;
199 }
200 if (active_scenario_ &&
201 trace_to_upload_.size() <=
202 active_scenario_->GetTraceUploadLimitKb() * 1024) {
203 return true;
204 }
205 RecordMetric(Metrics::LARGE_UPLOAD_WAITING_TO_RETRY);
206 return false;
207 }
208
GetLatestTraceToUpload()209 std::string BackgroundTracingManagerImpl::GetLatestTraceToUpload() {
210 DCHECK_CURRENTLY_ON(BrowserThread::UI);
211 std::string ret;
212 ret.swap(trace_to_upload_);
213
214 if (active_scenario_) {
215 active_scenario_->OnFinalizeComplete(true);
216 }
217
218 return ret;
219 }
220
AddEnabledStateObserver(EnabledStateObserver * observer)221 void BackgroundTracingManagerImpl::AddEnabledStateObserver(
222 EnabledStateObserver* observer) {
223 DCHECK_CURRENTLY_ON(BrowserThread::UI);
224 background_tracing_observers_.insert(observer);
225 }
226
RemoveEnabledStateObserver(EnabledStateObserver * observer)227 void BackgroundTracingManagerImpl::RemoveEnabledStateObserver(
228 EnabledStateObserver* observer) {
229 DCHECK_CURRENTLY_ON(BrowserThread::UI);
230 background_tracing_observers_.erase(observer);
231 }
232
AddAgent(tracing::mojom::BackgroundTracingAgent * agent)233 void BackgroundTracingManagerImpl::AddAgent(
234 tracing::mojom::BackgroundTracingAgent* agent) {
235 DCHECK_CURRENTLY_ON(BrowserThread::UI);
236 agents_.insert(agent);
237
238 for (auto* observer : agent_observers_) {
239 observer->OnAgentAdded(agent);
240 }
241 }
242
RemoveAgent(tracing::mojom::BackgroundTracingAgent * agent)243 void BackgroundTracingManagerImpl::RemoveAgent(
244 tracing::mojom::BackgroundTracingAgent* agent) {
245 DCHECK_CURRENTLY_ON(BrowserThread::UI);
246 for (auto* observer : agent_observers_) {
247 observer->OnAgentRemoved(agent);
248 }
249
250 agents_.erase(agent);
251 }
252
AddAgentObserver(AgentObserver * observer)253 void BackgroundTracingManagerImpl::AddAgentObserver(AgentObserver* observer) {
254 DCHECK_CURRENTLY_ON(BrowserThread::UI);
255 agent_observers_.insert(observer);
256
257 MaybeConstructPendingAgents();
258
259 for (auto* agent : agents_) {
260 observer->OnAgentAdded(agent);
261 }
262 }
263
RemoveAgentObserver(AgentObserver * observer)264 void BackgroundTracingManagerImpl::RemoveAgentObserver(
265 AgentObserver* observer) {
266 DCHECK_CURRENTLY_ON(BrowserThread::UI);
267 agent_observers_.erase(observer);
268
269 for (auto* agent : agents_) {
270 observer->OnAgentRemoved(agent);
271 }
272 }
273
274 BackgroundTracingActiveScenario*
GetActiveScenarioForTesting()275 BackgroundTracingManagerImpl::GetActiveScenarioForTesting() {
276 DCHECK(active_scenario_);
277 return active_scenario_.get();
278 }
279
IsTracingForTesting()280 bool BackgroundTracingManagerImpl::IsTracingForTesting() {
281 return active_scenario_ && (active_scenario_->state() ==
282 BackgroundTracingActiveScenario::State::kTracing);
283 }
284
SetTraceToUploadForTesting(std::unique_ptr<std::string> trace_data)285 void BackgroundTracingManagerImpl::SetTraceToUploadForTesting(
286 std::unique_ptr<std::string> trace_data) {
287 SetTraceToUpload(std::move(trace_data));
288 }
289
SetTraceToUpload(std::unique_ptr<std::string> trace_data)290 void BackgroundTracingManagerImpl::SetTraceToUpload(
291 std::unique_ptr<std::string> trace_data) {
292 DCHECK_CURRENTLY_ON(BrowserThread::UI);
293 if (trace_data) {
294 trace_to_upload_.swap(*trace_data);
295 } else {
296 trace_to_upload_.clear();
297 }
298 }
299
ValidateStartupScenario()300 void BackgroundTracingManagerImpl::ValidateStartupScenario() {
301 if (!active_scenario_ || !delegate_) {
302 return;
303 }
304
305 if (!delegate_->IsAllowedToBeginBackgroundScenario(
306 *active_scenario_->GetConfig(),
307 active_scenario_->GetConfig()->requires_anonymized_data())) {
308 AbortScenario();
309 }
310 }
311
312
OnHistogramTrigger(const std::string & histogram_name)313 void BackgroundTracingManagerImpl::OnHistogramTrigger(
314 const std::string& histogram_name) {
315 DCHECK_CURRENTLY_ON(BrowserThread::UI);
316 if (active_scenario_) {
317 active_scenario_->OnHistogramTrigger(histogram_name);
318 }
319 }
320
TriggerNamedEvent(BackgroundTracingManagerImpl::TriggerHandle handle,StartedFinalizingCallback callback)321 void BackgroundTracingManagerImpl::TriggerNamedEvent(
322 BackgroundTracingManagerImpl::TriggerHandle handle,
323 StartedFinalizingCallback callback) {
324 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
325 base::PostTask(
326 FROM_HERE, {BrowserThread::UI},
327 base::BindOnce(&BackgroundTracingManagerImpl::TriggerNamedEvent,
328 base::Unretained(this), handle, std::move(callback)));
329 return;
330 }
331
332 if (!active_scenario_ || !IsTriggerHandleValid(handle)) {
333 if (!callback.is_null()) {
334 std::move(callback).Run(false);
335 }
336 return;
337 }
338
339 active_scenario_->TriggerNamedEvent(handle, std::move(callback));
340 }
341
OnRuleTriggered(const BackgroundTracingRule * triggered_rule,StartedFinalizingCallback callback)342 void BackgroundTracingManagerImpl::OnRuleTriggered(
343 const BackgroundTracingRule* triggered_rule,
344 StartedFinalizingCallback callback) {
345 // The active scenario can be null here if scenario was aborted during
346 // validation and the rule was triggered just before validation. If validation
347 // kicked in after this point, we still check before uploading.
348 if (active_scenario_) {
349 active_scenario_->OnRuleTriggered(triggered_rule, std::move(callback));
350 }
351 }
352
353 BackgroundTracingManagerImpl::TriggerHandle
RegisterTriggerType(const char * trigger_name)354 BackgroundTracingManagerImpl::RegisterTriggerType(const char* trigger_name) {
355 DCHECK_CURRENTLY_ON(BrowserThread::UI);
356
357 trigger_handle_ids_ += 1;
358 trigger_handles_.insert(
359 std::pair<TriggerHandle, std::string>(trigger_handle_ids_, trigger_name));
360
361 return static_cast<TriggerHandle>(trigger_handle_ids_);
362 }
363
IsTriggerHandleValid(BackgroundTracingManager::TriggerHandle handle) const364 bool BackgroundTracingManagerImpl::IsTriggerHandleValid(
365 BackgroundTracingManager::TriggerHandle handle) const {
366 return trigger_handles_.find(handle) != trigger_handles_.end();
367 }
368
GetTriggerNameFromHandle(BackgroundTracingManager::TriggerHandle handle) const369 std::string BackgroundTracingManagerImpl::GetTriggerNameFromHandle(
370 BackgroundTracingManager::TriggerHandle handle) const {
371 CHECK(IsTriggerHandleValid(handle));
372 return trigger_handles_.find(handle)->second;
373 }
374
InvalidateTriggerHandlesForTesting()375 void BackgroundTracingManagerImpl::InvalidateTriggerHandlesForTesting() {
376 trigger_handles_.clear();
377 }
378
OnStartTracingDone(BackgroundTracingConfigImpl::CategoryPreset preset)379 void BackgroundTracingManagerImpl::OnStartTracingDone(
380 BackgroundTracingConfigImpl::CategoryPreset preset) {
381 DCHECK_CURRENTLY_ON(BrowserThread::UI);
382 for (auto* observer : background_tracing_observers_) {
383 observer->OnTracingEnabled(preset);
384 }
385 }
386
WhenIdle(base::RepeatingClosure idle_callback)387 void BackgroundTracingManagerImpl::WhenIdle(
388 base::RepeatingClosure idle_callback) {
389 DCHECK_CURRENTLY_ON(BrowserThread::UI);
390 idle_callback_ = std::move(idle_callback);
391
392 if (!active_scenario_) {
393 idle_callback_.Run();
394 }
395 }
396
IsAllowedFinalization() const397 bool BackgroundTracingManagerImpl::IsAllowedFinalization() const {
398 return !delegate_ ||
399 (active_scenario_ &&
400 delegate_->IsAllowedToEndBackgroundScenario(
401 *active_scenario_->GetConfig(),
402 active_scenario_->GetConfig()->requires_anonymized_data()));
403 }
404
405 std::unique_ptr<base::DictionaryValue>
GenerateMetadataDict()406 BackgroundTracingManagerImpl::GenerateMetadataDict() {
407 DCHECK_CURRENTLY_ON(BrowserThread::UI);
408
409 auto metadata_dict = std::make_unique<base::DictionaryValue>();
410 if (active_scenario_) {
411 active_scenario_->GenerateMetadataDict(metadata_dict.get());
412 }
413
414 return metadata_dict;
415 }
416
GenerateMetadataProto(perfetto::protos::pbzero::ChromeMetadataPacket * metadata,bool privacy_filtering_enabled)417 void BackgroundTracingManagerImpl::GenerateMetadataProto(
418 perfetto::protos::pbzero::ChromeMetadataPacket* metadata,
419 bool privacy_filtering_enabled) {
420 DCHECK_CURRENTLY_ON(BrowserThread::UI);
421 if (active_scenario_) {
422 active_scenario_->GenerateMetadataProto(metadata);
423 }
424 }
425
AbortScenarioForTesting()426 void BackgroundTracingManagerImpl::AbortScenarioForTesting() {
427 AbortScenario();
428 }
429
AbortScenario()430 void BackgroundTracingManagerImpl::AbortScenario() {
431 if (active_scenario_) {
432 active_scenario_->AbortScenario();
433 }
434 }
435
OnScenarioAborted()436 void BackgroundTracingManagerImpl::OnScenarioAborted() {
437 DCHECK(active_scenario_);
438
439 // Don't synchronously delete to avoid use-after-free issues in
440 // BackgroundTracingActiveScenario.
441 base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE,
442 std::move(active_scenario_));
443
444 for (auto* observer : background_tracing_observers_) {
445 observer->OnScenarioAborted();
446 }
447
448 if (!idle_callback_.is_null()) {
449 idle_callback_.Run();
450 }
451 }
452
453 // static
AddPendingAgent(int child_process_id,mojo::PendingRemote<tracing::mojom::BackgroundTracingAgentProvider> pending_provider)454 void BackgroundTracingManagerImpl::AddPendingAgent(
455 int child_process_id,
456 mojo::PendingRemote<tracing::mojom::BackgroundTracingAgentProvider>
457 pending_provider) {
458 DCHECK_CURRENTLY_ON(BrowserThread::UI);
459
460 // Delay agent initialization until we have an interested AgentObserver.
461 // We set disconnect handler for cleanup when the tracing target is closed.
462 mojo::Remote<tracing::mojom::BackgroundTracingAgentProvider> provider(
463 std::move(pending_provider));
464
465 provider.set_disconnect_handler(base::BindOnce(
466 &BackgroundTracingManagerImpl::ClearPendingAgent, child_process_id));
467
468 GetInstance()->pending_agents_[child_process_id] = std::move(provider);
469 GetInstance()->MaybeConstructPendingAgents();
470 }
471
472 // static
ClearPendingAgent(int child_process_id)473 void BackgroundTracingManagerImpl::ClearPendingAgent(int child_process_id) {
474 DCHECK_CURRENTLY_ON(BrowserThread::UI);
475 GetInstance()->pending_agents_.erase(child_process_id);
476 }
477
MaybeConstructPendingAgents()478 void BackgroundTracingManagerImpl::MaybeConstructPendingAgents() {
479 DCHECK_CURRENTLY_ON(BrowserThread::UI);
480
481 if (agent_observers_.empty())
482 return;
483
484 for (auto& pending_agent : pending_agents_) {
485 pending_agent.second.set_disconnect_handler(base::OnceClosure());
486 BackgroundTracingAgentClientImpl::Create(pending_agent.first,
487 std::move(pending_agent.second));
488 }
489 pending_agents_.clear();
490 }
491
492 } // namespace content
493