Update V8 to version 4.6.55.
[chromium-blink-merge.git] / content / browser / tracing / background_tracing_manager_impl.cc
blob6cdb697426a220638d91906619f2010c323ae107
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"
20 #include "net/base/network_change_notifier.h"
22 namespace content {
24 namespace {
26 base::LazyInstance<BackgroundTracingManagerImpl>::Leaky g_controller =
27 LAZY_INSTANCE_INITIALIZER;
29 const char kMetaDataConfigKey[] = "config";
30 const char kMetaDataNetworkType[] = "network_type";
31 const char kMetaDataVersionKey[] = "product_version";
33 // These values are used for a histogram. Do not reorder.
34 enum BackgroundTracingMetrics {
35 SCENARIO_ACTIVATION_REQUESTED = 0,
36 SCENARIO_ACTIVATED_SUCCESSFULLY = 1,
37 RECORDING_ENABLED = 2,
38 PREEMPTIVE_TRIGGERED = 3,
39 REACTIVE_TRIGGERED = 4,
40 FINALIZATION_ALLOWED = 5,
41 FINALIZATION_DISALLOWED = 6,
42 FINALIZATION_STARTED = 7,
43 FINALIZATION_COMPLETE = 8,
44 NUMBER_OF_BACKGROUND_TRACING_METRICS,
47 void RecordBackgroundTracingMetric(BackgroundTracingMetrics metric) {
48 UMA_HISTOGRAM_ENUMERATION("Tracing.Background.ScenarioState", metric,
49 NUMBER_OF_BACKGROUND_TRACING_METRICS);
52 std::string GetNetworkTypeString() {
53 switch (net::NetworkChangeNotifier::GetConnectionType()) {
54 case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
55 return "Ethernet";
56 case net::NetworkChangeNotifier::CONNECTION_WIFI:
57 return "WiFi";
58 case net::NetworkChangeNotifier::CONNECTION_2G:
59 return "2G";
60 case net::NetworkChangeNotifier::CONNECTION_3G:
61 return "3G";
62 case net::NetworkChangeNotifier::CONNECTION_4G:
63 return "4G";
64 case net::NetworkChangeNotifier::CONNECTION_NONE:
65 return "None";
66 case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
67 return "Bluetooth";
68 case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
69 default:
70 break;
72 return "Unknown";
75 } // namespace
77 BackgroundTracingManagerImpl::TracingTimer::TracingTimer(
78 StartedFinalizingCallback callback) : callback_(callback) {
81 BackgroundTracingManagerImpl::TracingTimer::~TracingTimer() {
84 void BackgroundTracingManagerImpl::TracingTimer::StartTimer() {
85 const int kTimeoutSecs = 10;
86 tracing_timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(kTimeoutSecs),
87 this, &BackgroundTracingManagerImpl::TracingTimer::TracingTimerFired);
90 void BackgroundTracingManagerImpl::TracingTimer::CancelTimer() {
91 tracing_timer_.Stop();
94 void BackgroundTracingManagerImpl::TracingTimer::TracingTimerFired() {
95 BackgroundTracingManagerImpl::GetInstance()->BeginFinalizing(callback_);
98 void BackgroundTracingManagerImpl::TracingTimer::FireTimerForTesting() {
99 CancelTimer();
100 TracingTimerFired();
103 BackgroundTracingManager* BackgroundTracingManager::GetInstance() {
104 return BackgroundTracingManagerImpl::GetInstance();
107 BackgroundTracingManagerImpl* BackgroundTracingManagerImpl::GetInstance() {
108 return g_controller.Pointer();
111 BackgroundTracingManagerImpl::BackgroundTracingManagerImpl()
112 : delegate_(GetContentClient()->browser()->GetTracingDelegate()),
113 is_gathering_(false),
114 is_tracing_(false),
115 requires_anonymized_data_(true),
116 trigger_handle_ids_(0) {
117 // BackgroundTracingManagerImpl is leaky, so there's no danger of this being
118 // called after being destroyed and we can use base::Unretained().
119 TracingControllerImpl::GetInstance()->SetTraceMessageFilterAddedCallback(
120 base::Bind(&BackgroundTracingManagerImpl::OnTraceMessageFilterAdded,
121 base::Unretained(this)));
124 BackgroundTracingManagerImpl::~BackgroundTracingManagerImpl() {
125 NOTREACHED();
128 void BackgroundTracingManagerImpl::WhenIdle(
129 base::Callback<void()> idle_callback) {
130 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
131 idle_callback_ = idle_callback;
134 bool BackgroundTracingManagerImpl::IsSupportedConfig(
135 BackgroundTracingConfig* config) {
136 // No config is just fine, we just don't do anything.
137 if (!config)
138 return true;
140 if (config->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
141 for (const auto& preemptive_config :
142 static_cast<BackgroundTracingPreemptiveConfig*>(config)->configs) {
143 if (preemptive_config.type == BackgroundTracingPreemptiveConfig::
144 MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED ||
145 preemptive_config.type ==
146 BackgroundTracingPreemptiveConfig::
147 MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE) {
148 continue;
150 return false;
154 if (config->mode == BackgroundTracingConfig::REACTIVE_TRACING_MODE) {
155 for (const auto& reactive_config :
156 static_cast<BackgroundTracingReactiveConfig*>(config)->configs) {
157 if (reactive_config.type !=
158 BackgroundTracingReactiveConfig::TRACE_FOR_10S_OR_TRIGGER_OR_FULL)
159 return false;
163 return true;
166 void BackgroundTracingManagerImpl::SetupUMACallbacks(
167 BackgroundTracingManagerImpl::SetupUMACallMode mode) {
168 if (!config_ ||
169 config_->mode != BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE)
170 return;
172 BackgroundTracingPreemptiveConfig* preemptive_config =
173 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get());
174 for (const auto& config : preemptive_config->configs) {
175 if (config.type != BackgroundTracingPreemptiveConfig::
176 MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE) {
177 continue;
180 if (mode == CLEAR_CALLBACKS) {
181 base::StatisticsRecorder::ClearCallback(
182 config.histogram_trigger_info.histogram_name);
183 } else {
184 base::StatisticsRecorder::SetCallback(
185 config.histogram_trigger_info.histogram_name,
186 base::Bind(&BackgroundTracingManagerImpl::OnHistogramChangedCallback,
187 base::Unretained(this),
188 config.histogram_trigger_info.histogram_name,
189 config.histogram_trigger_info.histogram_value));
193 SetupFiltersFromConfig(mode);
196 void BackgroundTracingManagerImpl::OnHistogramTrigger(
197 const std::string& histogram_name) {
198 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
199 content::BrowserThread::PostTask(
200 content::BrowserThread::UI, FROM_HERE,
201 base::Bind(&BackgroundTracingManagerImpl::OnHistogramTrigger,
202 base::Unretained(this), histogram_name));
203 return;
206 CHECK(config_ &&
207 config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE);
209 if (!is_tracing_ || is_gathering_)
210 return;
212 BackgroundTracingPreemptiveConfig* preemptive_config =
213 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get());
214 for (const auto& config : preemptive_config->configs) {
215 if (config.type != BackgroundTracingPreemptiveConfig::
216 MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE) {
217 continue;
220 if (config.histogram_trigger_info.histogram_name == histogram_name) {
221 RecordBackgroundTracingMetric(PREEMPTIVE_TRIGGERED);
222 BeginFinalizing(StartedFinalizingCallback());
227 void BackgroundTracingManagerImpl::OnHistogramChangedCallback(
228 const std::string& histogram_name,
229 base::Histogram::Sample reference_value,
230 base::Histogram::Sample actual_value) {
231 if (reference_value > actual_value)
232 return;
234 OnHistogramTrigger(histogram_name);
237 bool BackgroundTracingManagerImpl::SetActiveScenario(
238 scoped_ptr<BackgroundTracingConfig> config,
239 const BackgroundTracingManager::ReceiveCallback& receive_callback,
240 DataFiltering data_filtering) {
241 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
242 RecordBackgroundTracingMetric(SCENARIO_ACTIVATION_REQUESTED);
244 if (is_tracing_)
245 return false;
247 bool requires_anonymized_data = (data_filtering == ANONYMIZE_DATA);
249 // If the I/O thread isn't running, this is a startup scenario and
250 // we have to wait until initialization is finished to validate that the
251 // scenario can run.
252 if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
253 // TODO(oysteine): Retry when time_until_allowed has elapsed.
254 if (config && delegate_ &&
255 !delegate_->IsAllowedToBeginBackgroundScenario(
256 *config.get(), requires_anonymized_data)) {
257 return false;
259 } else {
260 base::MessageLoop::current()->PostTask(
261 FROM_HERE,
262 base::Bind(&BackgroundTracingManagerImpl::ValidateStartupScenario,
263 base::Unretained(this)));
266 if (!IsSupportedConfig(config.get()))
267 return false;
269 // No point in tracing if there's nowhere to send it.
270 if (config && receive_callback.is_null())
271 return false;
273 SetupUMACallbacks(CLEAR_CALLBACKS);
275 config_ = config.Pass();
276 receive_callback_ = receive_callback;
277 requires_anonymized_data_ = requires_anonymized_data;
279 EnableRecordingIfConfigNeedsIt();
281 RecordBackgroundTracingMetric(SCENARIO_ACTIVATED_SUCCESSFULLY);
282 return true;
285 bool BackgroundTracingManagerImpl::HasActiveScenarioForTesting() {
286 return config_;
289 void BackgroundTracingManagerImpl::OnTraceMessageFilterAdded(
290 TraceMessageFilter* filter) {
291 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
292 SetupFilterFromConfig(filter, BIND_CALLBACKS);
295 void BackgroundTracingManagerImpl::SetupFiltersFromConfig(
296 BackgroundTracingManagerImpl::SetupUMACallMode mode) {
297 TracingControllerImpl::TraceMessageFilterSet filters;
298 TracingControllerImpl::GetInstance()->GetTraceMessageFilters(&filters);
300 for (auto& filter : filters)
301 SetupFilterFromConfig(filter, mode);
304 void BackgroundTracingManagerImpl::SetupFilterFromConfig(
305 scoped_refptr<TraceMessageFilter> filter,
306 BackgroundTracingManagerImpl::SetupUMACallMode mode) {
307 if (!config_ ||
308 config_->mode != BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE)
309 return;
311 BackgroundTracingPreemptiveConfig* preemptive_config =
312 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get());
314 for (const auto& config : preemptive_config->configs) {
315 if (config.type != BackgroundTracingPreemptiveConfig::
316 MONITOR_AND_DUMP_WHEN_SPECIFIC_HISTOGRAM_AND_VALUE) {
317 continue;
320 if (mode == CLEAR_CALLBACKS) {
321 filter->Send(new TracingMsg_ClearUMACallback(
322 config.histogram_trigger_info.histogram_name));
323 } else {
324 filter->Send(new TracingMsg_SetUMACallback(
325 config.histogram_trigger_info.histogram_name,
326 config.histogram_trigger_info.histogram_value));
331 void BackgroundTracingManagerImpl::ValidateStartupScenario() {
332 if (!config_ || !delegate_)
333 return;
335 if (!delegate_->IsAllowedToBeginBackgroundScenario(
336 *config_.get(), requires_anonymized_data_)) {
337 AbortScenario();
341 void BackgroundTracingManagerImpl::EnableRecordingIfConfigNeedsIt() {
342 if (!config_)
343 return;
345 SetupUMACallbacks(BIND_CALLBACKS);
347 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
348 EnableRecording(GetCategoryFilterStringForCategoryPreset(
349 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get())
350 ->category_preset),
351 base::trace_event::RECORD_CONTINUOUSLY);
353 // There is nothing to do in case of reactive tracing.
356 bool BackgroundTracingManagerImpl::IsAbleToTriggerTracing(
357 TriggerHandle handle) const {
358 if (!config_)
359 return false;
361 // If the last trace is still uploading, we don't allow a new one to trigger.
362 if (is_gathering_)
363 return false;
365 if (!IsTriggerHandleValid(handle)) {
366 return false;
369 std::string trigger_name = GetTriggerNameFromHandle(handle);
371 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
372 BackgroundTracingPreemptiveConfig* preemptive_config =
373 static_cast<BackgroundTracingPreemptiveConfig*>(config_.get());
375 for (const auto& config : preemptive_config->configs) {
376 if (config.type == BackgroundTracingPreemptiveConfig::
377 MONITOR_AND_DUMP_WHEN_TRIGGER_NAMED &&
378 config.named_trigger_info.trigger_name == trigger_name) {
379 return true;
382 } else {
383 BackgroundTracingReactiveConfig* reactive_config =
384 static_cast<BackgroundTracingReactiveConfig*>(config_.get());
386 for (const auto& config : reactive_config->configs) {
387 if (config.type !=
388 BackgroundTracingReactiveConfig::TRACE_FOR_10S_OR_TRIGGER_OR_FULL)
389 continue;
390 if (trigger_name == config.trigger_name) {
391 return true;
395 return false;
398 void BackgroundTracingManagerImpl::TriggerNamedEvent(
399 BackgroundTracingManagerImpl::TriggerHandle handle,
400 StartedFinalizingCallback callback) {
401 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
402 content::BrowserThread::PostTask(
403 content::BrowserThread::UI, FROM_HERE,
404 base::Bind(&BackgroundTracingManagerImpl::TriggerNamedEvent,
405 base::Unretained(this), handle, callback));
406 return;
409 if (!IsAbleToTriggerTracing(handle)) {
410 if (!callback.is_null())
411 callback.Run(false);
412 return;
415 if (config_->mode == BackgroundTracingConfig::PREEMPTIVE_TRACING_MODE) {
416 RecordBackgroundTracingMetric(PREEMPTIVE_TRIGGERED);
417 BeginFinalizing(callback);
418 } else {
419 RecordBackgroundTracingMetric(REACTIVE_TRIGGERED);
420 if (is_tracing_) {
421 tracing_timer_->CancelTimer();
422 BeginFinalizing(callback);
423 return;
426 // It was not already tracing, start a new trace.
427 BackgroundTracingReactiveConfig* reactive_config =
428 static_cast<BackgroundTracingReactiveConfig*>(config_.get());
429 std::string trigger_name = GetTriggerNameFromHandle(handle);
430 for (const auto& config : reactive_config->configs) {
431 if (config.trigger_name == trigger_name) {
432 EnableRecording(
433 GetCategoryFilterStringForCategoryPreset(config.category_preset),
434 base::trace_event::RECORD_UNTIL_FULL);
435 tracing_timer_.reset(new TracingTimer(callback));
436 tracing_timer_->StartTimer();
437 break;
443 BackgroundTracingManagerImpl::TriggerHandle
444 BackgroundTracingManagerImpl::RegisterTriggerType(const char* trigger_name) {
445 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
447 trigger_handle_ids_ += 1;
449 trigger_handles_.insert(
450 std::pair<TriggerHandle, std::string>(trigger_handle_ids_, trigger_name));
452 return static_cast<TriggerHandle>(trigger_handle_ids_);
455 bool BackgroundTracingManagerImpl::IsTriggerHandleValid(
456 BackgroundTracingManager::TriggerHandle handle) const {
457 return trigger_handles_.find(handle) != trigger_handles_.end();
460 std::string BackgroundTracingManagerImpl::GetTriggerNameFromHandle(
461 BackgroundTracingManager::TriggerHandle handle) const {
462 CHECK(IsTriggerHandleValid(handle));
463 return trigger_handles_.find(handle)->second;
466 void BackgroundTracingManagerImpl::GetTriggerNameList(
467 std::vector<std::string>* trigger_names) {
468 for (const auto& it : trigger_handles_)
469 trigger_names->push_back(it.second);
472 void BackgroundTracingManagerImpl::InvalidateTriggerHandlesForTesting() {
473 trigger_handles_.clear();
476 void BackgroundTracingManagerImpl::SetTracingEnabledCallbackForTesting(
477 const base::Closure& callback) {
478 tracing_enabled_callback_for_testing_ = callback;
481 void BackgroundTracingManagerImpl::FireTimerForTesting() {
482 tracing_timer_->FireTimerForTesting();
485 void BackgroundTracingManagerImpl::EnableRecording(
486 std::string category_filter_str,
487 base::trace_event::TraceRecordMode record_mode) {
488 base::trace_event::TraceConfig trace_config(category_filter_str, record_mode);
489 if (requires_anonymized_data_)
490 trace_config.EnableArgumentFilter();
492 is_tracing_ = TracingController::GetInstance()->EnableRecording(
493 trace_config, tracing_enabled_callback_for_testing_);
494 RecordBackgroundTracingMetric(RECORDING_ENABLED);
497 void BackgroundTracingManagerImpl::OnFinalizeStarted(
498 base::RefCountedString* file_contents) {
499 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
501 RecordBackgroundTracingMetric(FINALIZATION_STARTED);
502 UMA_HISTOGRAM_MEMORY_KB("Tracing.Background.FinalizingTraceSizeInKB",
503 file_contents->size() / 1024);
505 if (!receive_callback_.is_null()) {
506 receive_callback_.Run(
507 file_contents, GenerateMetadataDict(),
508 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete,
509 base::Unretained(this)));
513 void BackgroundTracingManagerImpl::OnFinalizeComplete() {
514 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
515 BrowserThread::PostTask(
516 BrowserThread::UI, FROM_HERE,
517 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete,
518 base::Unretained(this)));
519 return;
522 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
524 is_gathering_ = false;
526 if (!idle_callback_.is_null())
527 idle_callback_.Run();
529 // Now that a trace has completed, we may need to enable recording again.
530 // TODO(oysteine): Retry later if IsAllowedToBeginBackgroundScenario fails.
531 if (!delegate_ ||
532 delegate_->IsAllowedToBeginBackgroundScenario(
533 *config_.get(), requires_anonymized_data_)) {
534 EnableRecordingIfConfigNeedsIt();
535 } else {
536 // Clear all the callbacks so we don't keep hearing about histogram changes,
537 // etc. anymore, both in this process and in any child processes.
538 SetupUMACallbacks(CLEAR_CALLBACKS);
541 RecordBackgroundTracingMetric(FINALIZATION_COMPLETE);
544 scoped_ptr<base::DictionaryValue>
545 BackgroundTracingManagerImpl::GenerateMetadataDict() const {
546 // Grab the network type.
547 std::string network_type = GetNetworkTypeString();
549 // Grab the product version.
550 std::string product_version = GetContentClient()->GetProduct();
552 // Serialize the config into json.
553 scoped_ptr<base::DictionaryValue> config_dict(new base::DictionaryValue());
555 BackgroundTracingConfig::IntoDict(config_.get(), config_dict.get());
557 scoped_ptr<base::DictionaryValue> metadata_dict(new base::DictionaryValue());
558 metadata_dict->Set(kMetaDataConfigKey, config_dict.Pass());
559 metadata_dict->SetString(kMetaDataNetworkType, network_type);
560 metadata_dict->SetString(kMetaDataVersionKey, product_version);
562 return metadata_dict.Pass();
565 void BackgroundTracingManagerImpl::BeginFinalizing(
566 StartedFinalizingCallback callback) {
567 is_gathering_ = true;
568 is_tracing_ = false;
570 bool is_allowed_finalization =
571 !delegate_ || (config_ &&
572 delegate_->IsAllowedToEndBackgroundScenario(
573 *config_.get(), requires_anonymized_data_));
575 scoped_refptr<TracingControllerImpl::TraceDataSink> trace_data_sink;
576 if (is_allowed_finalization) {
577 trace_data_sink = content::TracingController::CreateCompressedStringSink(
578 content::TracingController::CreateCallbackEndpoint(
579 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeStarted,
580 base::Unretained(this))));
581 RecordBackgroundTracingMetric(FINALIZATION_ALLOWED);
583 if (auto metadata_dict = GenerateMetadataDict()) {
584 std::string results;
585 if (base::JSONWriter::Write(*metadata_dict.get(), &results))
586 trace_data_sink->SetMetadata(results);
588 } else {
589 RecordBackgroundTracingMetric(FINALIZATION_DISALLOWED);
592 content::TracingController::GetInstance()->DisableRecording(trace_data_sink);
594 if (!callback.is_null())
595 callback.Run(is_allowed_finalization);
598 void BackgroundTracingManagerImpl::AbortScenario() {
599 SetupUMACallbacks(CLEAR_CALLBACKS);
601 is_tracing_ = false;
602 config_.reset();
604 content::TracingController::GetInstance()->DisableRecording(nullptr);
607 std::string
608 BackgroundTracingManagerImpl::GetCategoryFilterStringForCategoryPreset(
609 BackgroundTracingConfig::CategoryPreset preset) const {
610 switch (preset) {
611 case BackgroundTracingConfig::CategoryPreset::BENCHMARK:
612 return "benchmark,toplevel";
613 case BackgroundTracingConfig::CategoryPreset::BENCHMARK_DEEP:
614 return "*,disabled-by-default-benchmark.detailed";
616 NOTREACHED();
617 return "";
620 } // namspace content