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