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