Fix various typos, error handling for GN auto-roller.
[chromium-blink-merge.git] / content / browser / tracing / background_tracing_manager_impl.cc
blobb007581a93d4f8e8619175e66dea03b160bb855a
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.
5 #include "content/browser/tracing/background_tracing_manager_impl.h"
7 #include "base/json/json_writer.h"
8 #include "base/macros.h"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/metrics/statistics_recorder.h"
11 #include "base/time/time.h"
12 #include "components/tracing/tracing_messages.h"
13 #include "content/browser/tracing/trace_message_filter.h"
14 #include "content/public/browser/background_tracing_preemptive_config.h"
15 #include "content/public/browser/background_tracing_reactive_config.h"
16 #include "content/public/browser/browser_thread.h"
17 #include "content/public/browser/content_browser_client.h"
18 #include "content/public/browser/tracing_delegate.h"
19 #include "content/public/common/content_client.h"
21 namespace content {
23 namespace {
25 base::LazyInstance<BackgroundTracingManagerImpl>::Leaky g_controller =
26 LAZY_INSTANCE_INITIALIZER;
28 const char kMetaDataConfigKey[] = "config";
29 const char kMetaDataVersionKey[] = "product_version";
31 // These values are used for a histogram. Do not reorder.
32 enum BackgroundTracingMetrics {
33 SCENARIO_ACTIVATION_REQUESTED = 0,
34 SCENARIO_ACTIVATED_SUCCESSFULLY = 1,
35 RECORDING_ENABLED = 2,
36 PREEMPTIVE_TRIGGERED = 3,
37 REACTIVE_TRIGGERED = 4,
38 FINALIZATION_ALLOWED = 5,
39 FINALIZATION_DISALLOWED = 6,
40 FINALIZATION_STARTED = 7,
41 FINALIZATION_COMPLETE = 8,
42 NUMBER_OF_BACKGROUND_TRACING_METRICS,
45 void RecordBackgroundTracingMetric(BackgroundTracingMetrics metric) {
46 UMA_HISTOGRAM_ENUMERATION("Tracing.Background.ScenarioState", metric,
47 NUMBER_OF_BACKGROUND_TRACING_METRICS);
50 } // namespace
52 BackgroundTracingManagerImpl::TracingTimer::TracingTimer(
53 StartedFinalizingCallback callback) : callback_(callback) {
56 BackgroundTracingManagerImpl::TracingTimer::~TracingTimer() {
59 void BackgroundTracingManagerImpl::TracingTimer::StartTimer() {
60 const int kTimeoutSecs = 10;
61 tracing_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kTimeoutSecs),
62 this, &BackgroundTracingManagerImpl::TracingTimer::TracingTimerFired);
65 void BackgroundTracingManagerImpl::TracingTimer::CancelTimer() {
66 tracing_timer_.Stop();
69 void BackgroundTracingManagerImpl::TracingTimer::TracingTimerFired() {
70 BackgroundTracingManagerImpl::GetInstance()->BeginFinalizing(callback_);
73 void BackgroundTracingManagerImpl::TracingTimer::FireTimerForTesting() {
74 CancelTimer();
75 TracingTimerFired();
78 BackgroundTracingManager* BackgroundTracingManager::GetInstance() {
79 return BackgroundTracingManagerImpl::GetInstance();
82 BackgroundTracingManagerImpl* BackgroundTracingManagerImpl::GetInstance() {
83 return g_controller.Pointer();
86 BackgroundTracingManagerImpl::BackgroundTracingManagerImpl()
87 : delegate_(GetContentClient()->browser()->GetTracingDelegate()),
88 is_gathering_(false),
89 is_tracing_(false),
90 requires_anonymized_data_(true),
91 trigger_handle_ids_(0) {
92 // BackgroundTracingManagerImpl is leaky, so there's no danger of this being
93 // called after being destroyed and we can use base::Unretained().
94 TracingControllerImpl::GetInstance()->SetTraceMessageFilterAddedCallback(
95 base::Bind(&BackgroundTracingManagerImpl::OnTraceMessageFilterAdded,
96 base::Unretained(this)));
99 BackgroundTracingManagerImpl::~BackgroundTracingManagerImpl() {
100 NOTREACHED();
103 void BackgroundTracingManagerImpl::WhenIdle(
104 base::Callback<void()> idle_callback) {
105 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
106 idle_callback_ = idle_callback;
109 bool BackgroundTracingManagerImpl::IsSupportedConfig(
110 BackgroundTracingConfig* config) {
111 // No config is just fine, we just don't do anything.
112 if (!config)
113 return true;
115 if (config->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
116 BackgroundTracingPreemptiveConfig* preemptive_config =
117 static_cast<BackgroundTracingPreemptiveConfig*>(config);
118 const std::vector<BackgroundTracingPreemptiveConfig::MonitoringRule>&
119 configs = preemptive_config->configs;
120 for (size_t i = 0; i < configs.size(); ++i) {
121 if (configs[i].type == BackgroundTracingPreemptiveConfig::
122 MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED ||
123 configs[i].type ==
124 BackgroundTracingPreemptiveConfig::
125 MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE) {
126 continue;
128 return false;
132 if (config->mode == BackgroundTracingConfig::REACTIVE_TRACING_MODE) {
133 BackgroundTracingReactiveConfig* reactive_config =
134 static_cast<BackgroundTracingReactiveConfig*>(config);
135 const std::vector<BackgroundTracingReactiveConfig::TracingRule>&
136 configs = reactive_config->configs;
137 for (size_t i = 0; i < configs.size(); ++i) {
138 if (configs[i].type !=
139 BackgroundTracingReactiveConfig::TRACE_FOR_10S_OR_TRIGGER_OR_FULL)
140 return false;
144 return true;
147 void BackgroundTracingManagerImpl::SetupUMACallbacks(
148 BackgroundTracingManagerImpl::SetupUMACallMode mode) {
149 if (!config_ ||
150 config_->mode != BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE)
151 return;
153 BackgroundTracingPreemptiveConfig* preemptive_config =
154 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get());
155 const std::vector<BackgroundTracingPreemptiveConfig::MonitoringRule>&
156 configs = preemptive_config->configs;
157 for (size_t i = 0; i < configs.size(); ++i) {
158 if (configs[i].type !=
159 BackgroundTracingPreemptiveConfig::
160 MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE) {
161 continue;
164 if (mode == CLEAR_CALLBACKS) {
165 base::StatisticsRecorder::ClearCallback(
166 configs[i].histogram_trigger_info.histogram_name);
167 } else {
168 base::StatisticsRecorder::SetCallback(
169 configs[i].histogram_trigger_info.histogram_name,
170 base::Bind(&BackgroundTracingManagerImpl::OnHistogramChangedCallback,
171 base::Unretained(this),
172 configs[i].histogram_trigger_info.histogram_name,
173 configs[i].histogram_trigger_info.histogram_value));
177 SetupFiltersFromConfig(mode);
180 void BackgroundTracingManagerImpl::OnHistogramTrigger(
181 const std::string& histogram_name) {
182 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
183 content::BrowserThread::PostTask(
184 content::BrowserThread::UI, FROM_HERE,
185 base::Bind(&BackgroundTracingManagerImpl::OnHistogramTrigger,
186 base::Unretained(this), histogram_name));
187 return;
190 CHECK(config_ &&
191 config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE);
193 if (!is_tracing_ || is_gathering_)
194 return;
196 BackgroundTracingPreemptiveConfig* preemptive_config =
197 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get());
198 for (const auto& config : preemptive_config->configs) {
199 if (config.type != BackgroundTracingPreemptiveConfig::
200 MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE) {
201 continue;
204 if (config.histogram_trigger_info.histogram_name == histogram_name) {
205 RecordBackgroundTracingMetric(PREEMPTIVE_TRIGGERED);
206 BeginFinalizing(StartedFinalizingCallback());
211 void BackgroundTracingManagerImpl::OnHistogramChangedCallback(
212 const std::string& histogram_name,
213 base::Histogram::Sample reference_value,
214 base::Histogram::Sample actual_value) {
215 if (reference_value > actual_value)
216 return;
218 OnHistogramTrigger(histogram_name);
221 bool BackgroundTracingManagerImpl::SetActiveScenario(
222 scoped_ptr<BackgroundTracingConfig> config,
223 const BackgroundTracingManager::ReceiveCallback& receive_callback,
224 DataFiltering data_filtering) {
225 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
226 RecordBackgroundTracingMetric(SCENARIO_ACTIVATION_REQUESTED);
228 if (is_tracing_)
229 return false;
231 bool requires_anonymized_data = (data_filtering == ANONYMIZE_DATA);
233 // If the I/O thread isn't running, this is a startup scenario and
234 // we have to wait until initialization is finished to validate that the
235 // scenario can run.
236 if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
237 // TODO(oysteine): Retry when time_until_allowed has elapsed.
238 if (config && delegate_ &&
239 !delegate_->IsAllowedToBeginBackgroundScenario(
240 *config.get(), requires_anonymized_data)) {
241 return false;
243 } else {
244 base::MessageLoop::current()->PostTask(
245 FROM_HERE,
246 base::Bind(&BackgroundTracingManagerImpl::ValidateStartupScenario,
247 base::Unretained(this)));
250 if (!IsSupportedConfig(config.get()))
251 return false;
253 // No point in tracing if there's nowhere to send it.
254 if (config && receive_callback.is_null())
255 return false;
257 SetupUMACallbacks(CLEAR_CALLBACKS);
259 config_ = config.Pass();
260 receive_callback_ = receive_callback;
261 requires_anonymized_data_ = requires_anonymized_data;
263 EnableRecordingIfConfigNeedsIt();
265 RecordBackgroundTracingMetric(SCENARIO_ACTIVATED_SUCCESSFULLY);
266 return true;
269 bool BackgroundTracingManagerImpl::HasActiveScenarioForTesting() {
270 return config_;
273 void BackgroundTracingManagerImpl::OnTraceMessageFilterAdded(
274 TraceMessageFilter* filter) {
275 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
276 SetupFilterFromConfig(filter, BIND_CALLBACKS);
279 void BackgroundTracingManagerImpl::SetupFiltersFromConfig(
280 BackgroundTracingManagerImpl::SetupUMACallMode mode) {
281 TracingControllerImpl::TraceMessageFilterSet filters;
282 TracingControllerImpl::GetInstance()->GetTraceMessageFilters(&filters);
284 for (auto& filter : filters)
285 SetupFilterFromConfig(filter, mode);
288 void BackgroundTracingManagerImpl::SetupFilterFromConfig(
289 scoped_refptr<TraceMessageFilter> filter,
290 BackgroundTracingManagerImpl::SetupUMACallMode mode) {
291 if (!config_ ||
292 config_->mode != BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE)
293 return;
295 BackgroundTracingPreemptiveConfig* preemptive_config =
296 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get());
298 for (const auto& config : preemptive_config->configs) {
299 if (config.type != BackgroundTracingPreemptiveConfig::
300 MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE) {
301 continue;
304 if (mode == CLEAR_CALLBACKS) {
305 filter->Send(new TracingMsg_ClearUMACallback(
306 config.histogram_trigger_info.histogram_name));
307 } else {
308 filter->Send(new TracingMsg_SetUMACallback(
309 config.histogram_trigger_info.histogram_name,
310 config.histogram_trigger_info.histogram_value));
315 void BackgroundTracingManagerImpl::ValidateStartupScenario() {
316 if (!config_ || !delegate_)
317 return;
319 if (!delegate_->IsAllowedToBeginBackgroundScenario(
320 *config_.get(), requires_anonymized_data_)) {
321 AbortScenario();
325 void BackgroundTracingManagerImpl::EnableRecordingIfConfigNeedsIt() {
326 if (!config_)
327 return;
329 SetupUMACallbacks(BIND_CALLBACKS);
331 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
332 EnableRecording(GetCategoryFilterStringForCategoryPreset(
333 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get())
334 ->category_preset),
335 base::trace_event::RECORD_CONTINUOUSLY);
337 // There is nothing to do in case of reactive tracing.
340 bool BackgroundTracingManagerImpl::IsAbleToTriggerTracing(
341 TriggerHandle handle) const {
342 if (!config_)
343 return false;
345 // If the last trace is still uploading, we don't allow a new one to trigger.
346 if (is_gathering_)
347 return false;
349 if (!IsTriggerHandleValid(handle)) {
350 return false;
353 std::string trigger_name = GetTriggerNameFromHandle(handle);
355 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
356 BackgroundTracingPreemptiveConfig* preemptive_config =
357 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get());
359 const std::vector<BackgroundTracingPreemptiveConfig::MonitoringRule>&
360 configs = preemptive_config->configs;
362 for (size_t i = 0; i < configs.size(); ++i) {
363 if (configs[i].type == BackgroundTracingPreemptiveConfig::
364 MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED &&
365 configs[i].named_trigger_info.trigger_name == trigger_name) {
366 return true;
369 } else {
370 BackgroundTracingReactiveConfig* reactive_config =
371 static_cast<BackgroundTracingReactiveConfig*>(config_.get());
373 const std::vector<BackgroundTracingReactiveConfig::TracingRule>&
374 configs = reactive_config->configs;
376 for (size_t i = 0; i < configs.size(); ++i) {
377 if (configs[i].type !=
378 BackgroundTracingReactiveConfig::
379 TRACE_FOR_10S_OR_TRIGGER_OR_FULL)
380 continue;
381 if (trigger_name == configs[i].trigger_name) {
382 return true;
386 return false;
389 void BackgroundTracingManagerImpl::TriggerNamedEvent(
390 BackgroundTracingManagerImpl::TriggerHandle handle,
391 StartedFinalizingCallback callback) {
392 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
393 content::BrowserThread::PostTask(
394 content::BrowserThread::UI, FROM_HERE,
395 base::Bind(&BackgroundTracingManagerImpl::TriggerNamedEvent,
396 base::Unretained(this), handle, callback));
397 return;
400 if (!IsAbleToTriggerTracing(handle)) {
401 if (!callback.is_null())
402 callback.Run(false);
403 return;
406 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
407 RecordBackgroundTracingMetric(PREEMPTIVE_TRIGGERED);
408 BeginFinalizing(callback);
409 } else {
410 RecordBackgroundTracingMetric(REACTIVE_TRIGGERED);
411 if (is_tracing_) {
412 tracing_timer_->CancelTimer();
413 BeginFinalizing(callback);
414 return;
417 // It was not already tracing, start a new trace.
418 BackgroundTracingReactiveConfig* reactive_config =
419 static_cast<BackgroundTracingReactiveConfig*>(config_.get());
420 const std::vector<BackgroundTracingReactiveConfig::TracingRule>&
421 configs = reactive_config->configs;
422 std::string trigger_name = GetTriggerNameFromHandle(handle);
423 for (size_t i = 0; i < configs.size(); ++i) {
424 if (configs[i].trigger_name == trigger_name) {
425 EnableRecording(
426 GetCategoryFilterStringForCategoryPreset(
427 configs[i].category_preset),
428 base::trace_event::RECORD_UNTIL_FULL);
429 tracing_timer_.reset(new TracingTimer(callback));
430 tracing_timer_->StartTimer();
431 break;
437 BackgroundTracingManagerImpl::TriggerHandle
438 BackgroundTracingManagerImpl::RegisterTriggerType(const char* trigger_name) {
439 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
441 trigger_handle_ids_ += 1;
443 trigger_handles_.insert(
444 std::pair<TriggerHandle, std::string>(trigger_handle_ids_, trigger_name));
446 return static_cast<TriggerHandle>(trigger_handle_ids_);
449 bool BackgroundTracingManagerImpl::IsTriggerHandleValid(
450 BackgroundTracingManager::TriggerHandle handle) const {
451 return trigger_handles_.find(handle) != trigger_handles_.end();
454 std::string BackgroundTracingManagerImpl::GetTriggerNameFromHandle(
455 BackgroundTracingManager::TriggerHandle handle) const {
456 CHECK(IsTriggerHandleValid(handle));
457 return trigger_handles_.find(handle)->second;
460 void BackgroundTracingManagerImpl::GetTriggerNameList(
461 std::vector<std::string>* trigger_names) {
462 for (std::map<TriggerHandle, std::string>::iterator it =
463 trigger_handles_.begin();
464 it != trigger_handles_.end(); ++it)
465 trigger_names->push_back(it->second);
468 void BackgroundTracingManagerImpl::InvalidateTriggerHandlesForTesting() {
469 trigger_handles_.clear();
472 void BackgroundTracingManagerImpl::SetTracingEnabledCallbackForTesting(
473 const base::Closure& callback) {
474 tracing_enabled_callback_for_testing_ = callback;
477 void BackgroundTracingManagerImpl::FireTimerForTesting() {
478 tracing_timer_->FireTimerForTesting();
481 void BackgroundTracingManagerImpl::EnableRecording(
482 std::string category_filter_str,
483 base::trace_event::TraceRecordMode record_mode) {
484 base::trace_event::TraceConfig trace_config(category_filter_str, record_mode);
485 if (requires_anonymized_data_)
486 trace_config.EnableArgumentFilter();
488 is_tracing_ = TracingController::GetInstance()->EnableRecording(
489 trace_config, tracing_enabled_callback_for_testing_);
490 RecordBackgroundTracingMetric(RECORDING_ENABLED);
493 void BackgroundTracingManagerImpl::OnFinalizeStarted(
494 base::RefCountedString* file_contents) {
495 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
497 RecordBackgroundTracingMetric(FINALIZATION_STARTED);
498 UMA_HISTOGRAM_MEMORY_KB("Tracing.Background.FinalizingTraceSizeInKB",
499 file_contents->size() / 1024);
501 if (!receive_callback_.is_null()) {
502 receive_callback_.Run(
503 file_contents, GenerateMetadataDict(),
504 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete,
505 base::Unretained(this)));
509 void BackgroundTracingManagerImpl::OnFinalizeComplete() {
510 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
511 BrowserThread::PostTask(
512 BrowserThread::UI, FROM_HERE,
513 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete,
514 base::Unretained(this)));
515 return;
518 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
520 is_gathering_ = false;
522 if (!idle_callback_.is_null())
523 idle_callback_.Run();
525 // Now that a trace has completed, we may need to enable recording again.
526 // TODO(oysteine): Retry later if IsAllowedToBeginBackgroundScenario fails.
527 if (!delegate_ ||
528 delegate_->IsAllowedToBeginBackgroundScenario(
529 *config_.get(), requires_anonymized_data_)) {
530 EnableRecordingIfConfigNeedsIt();
531 } else {
532 // Clear all the callbacks so we don't keep hearing about histogram changes,
533 // etc. anymore, both in this process and in any child processes.
534 SetupUMACallbacks(CLEAR_CALLBACKS);
537 RecordBackgroundTracingMetric(FINALIZATION_COMPLETE);
540 scoped_ptr<base::DictionaryValue>
541 BackgroundTracingManagerImpl::GenerateMetadataDict() const {
542 // Grab the product version.
543 std::string product_version = GetContentClient()->GetProduct();
545 // Serialize the config into json.
546 scoped_ptr<base::DictionaryValue> config_dict(new base::DictionaryValue());
548 BackgroundTracingConfig::IntoDict(config_.get(), config_dict.get());
550 scoped_ptr<base::DictionaryValue> metadata_dict(new base::DictionaryValue());
551 metadata_dict->Set(kMetaDataConfigKey, config_dict.Pass());
552 metadata_dict->SetString(kMetaDataVersionKey, product_version);
554 return metadata_dict.Pass();
557 void BackgroundTracingManagerImpl::BeginFinalizing(
558 StartedFinalizingCallback callback) {
559 is_gathering_ = true;
560 is_tracing_ = false;
562 bool is_allowed_finalization =
563 !delegate_ || (config_ &&
564 delegate_->IsAllowedToEndBackgroundScenario(
565 *config_.get(), requires_anonymized_data_));
567 scoped_refptr<TracingControllerImpl::TraceDataSink> trace_data_sink;
568 if (is_allowed_finalization) {
569 trace_data_sink = content::TracingController::CreateCompressedStringSink(
570 content::TracingController::CreateCallbackEndpoint(
571 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeStarted,
572 base::Unretained(this))));
573 RecordBackgroundTracingMetric(FINALIZATION_ALLOWED);
575 if (auto metadata_dict = GenerateMetadataDict()) {
576 std::string results;
577 if (base::JSONWriter::Write(*metadata_dict.get(), &results))
578 trace_data_sink->SetMetadata(results);
580 } else {
581 RecordBackgroundTracingMetric(FINALIZATION_DISALLOWED);
584 content::TracingController::GetInstance()->DisableRecording(trace_data_sink);
586 if (!callback.is_null())
587 callback.Run(is_allowed_finalization);
590 void BackgroundTracingManagerImpl::AbortScenario() {
591 SetupUMACallbacks(CLEAR_CALLBACKS);
593 is_tracing_ = false;
594 config_.reset();
596 content::TracingController::GetInstance()->DisableRecording(nullptr);
599 std::string
600 BackgroundTracingManagerImpl::GetCategoryFilterStringForCategoryPreset(
601 BackgroundTracingConfig::CategoryPreset preset) const {
602 switch (preset) {
603 case BackgroundTracingConfig::CategoryPreset::BENCHMARK:
604 return "benchmark,toplevel";
605 case BackgroundTracingConfig::CategoryPreset::BENCHMARK_DEEP:
606 return "*,disabled-by-default-benchmark.detailed";
608 NOTREACHED();
609 return "";
612 } // namspace content