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