[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / tracing / background_tracing_manager_impl.cc
blob83049236118583b9e30f11a36cead081faf621e6
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/cpu.h"
8 #include "base/json/json_writer.h"
9 #include "base/macros.h"
10 #include "base/metrics/histogram_macros.h"
11 #include "base/sys_info.h"
12 #include "base/time/time.h"
13 #include "content/browser/tracing/background_tracing_rule.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "content/public/browser/content_browser_client.h"
16 #include "content/public/browser/gpu_data_manager.h"
17 #include "content/public/browser/tracing_delegate.h"
18 #include "content/public/common/content_client.h"
19 #include "gpu/config/gpu_info.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 // These values are used for a histogram. Do not reorder.
30 enum BackgroundTracingMetrics {
31 SCENARIO_ACTIVATION_REQUESTED = 0,
32 SCENARIO_ACTIVATED_SUCCESSFULLY = 1,
33 RECORDING_ENABLED = 2,
34 PREEMPTIVE_TRIGGERED = 3,
35 REACTIVE_TRIGGERED = 4,
36 FINALIZATION_ALLOWED = 5,
37 FINALIZATION_DISALLOWED = 6,
38 FINALIZATION_STARTED = 7,
39 FINALIZATION_COMPLETE = 8,
40 NUMBER_OF_BACKGROUND_TRACING_METRICS,
43 void RecordBackgroundTracingMetric(BackgroundTracingMetrics metric) {
44 UMA_HISTOGRAM_ENUMERATION("Tracing.Background.ScenarioState", metric,
45 NUMBER_OF_BACKGROUND_TRACING_METRICS);
48 std::string GetNetworkTypeString() {
49 switch (net::NetworkChangeNotifier::GetConnectionType()) {
50 case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
51 return "Ethernet";
52 case net::NetworkChangeNotifier::CONNECTION_WIFI:
53 return "WiFi";
54 case net::NetworkChangeNotifier::CONNECTION_2G:
55 return "2G";
56 case net::NetworkChangeNotifier::CONNECTION_3G:
57 return "3G";
58 case net::NetworkChangeNotifier::CONNECTION_4G:
59 return "4G";
60 case net::NetworkChangeNotifier::CONNECTION_NONE:
61 return "None";
62 case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
63 return "Bluetooth";
64 case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
65 default:
66 break;
68 return "Unknown";
71 } // namespace
73 BackgroundTracingManagerImpl::TracingTimer::TracingTimer(
74 StartedFinalizingCallback callback) : callback_(callback) {
77 BackgroundTracingManagerImpl::TracingTimer::~TracingTimer() {
80 void BackgroundTracingManagerImpl::TracingTimer::StartTimer(int seconds) {
81 tracing_timer_.Start(
82 FROM_HERE, base::TimeDelta::FromSeconds(seconds), this,
83 &BackgroundTracingManagerImpl::TracingTimer::TracingTimerFired);
86 void BackgroundTracingManagerImpl::TracingTimer::CancelTimer() {
87 tracing_timer_.Stop();
90 void BackgroundTracingManagerImpl::TracingTimer::TracingTimerFired() {
91 BackgroundTracingManagerImpl::GetInstance()->BeginFinalizing(callback_);
94 void BackgroundTracingManagerImpl::TracingTimer::FireTimerForTesting() {
95 CancelTimer();
96 TracingTimerFired();
99 BackgroundTracingManager* BackgroundTracingManager::GetInstance() {
100 return BackgroundTracingManagerImpl::GetInstance();
103 BackgroundTracingManagerImpl* BackgroundTracingManagerImpl::GetInstance() {
104 return g_controller.Pointer();
107 BackgroundTracingManagerImpl::BackgroundTracingManagerImpl()
108 : delegate_(GetContentClient()->browser()->GetTracingDelegate()),
109 is_gathering_(false),
110 is_tracing_(false),
111 requires_anonymized_data_(true),
112 trigger_handle_ids_(0),
113 reactive_triggered_handle_(-1) {}
115 BackgroundTracingManagerImpl::~BackgroundTracingManagerImpl() {
116 NOTREACHED();
119 void BackgroundTracingManagerImpl::WhenIdle(
120 base::Callback<void()> idle_callback) {
121 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
122 idle_callback_ = idle_callback;
125 void BackgroundTracingManagerImpl::TriggerPreemptiveFinalization() {
126 CHECK(config_ &&
127 config_->tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE);
129 if (!is_tracing_ || is_gathering_)
130 return;
132 RecordBackgroundTracingMetric(PREEMPTIVE_TRIGGERED);
133 BeginFinalizing(StartedFinalizingCallback());
136 void BackgroundTracingManagerImpl::OnHistogramTrigger(
137 const std::string& histogram_name) {
138 for (auto& rule : config_->rules()) {
139 static_cast<BackgroundTracingRule*>(rule)
140 ->OnHistogramTrigger(histogram_name);
144 bool BackgroundTracingManagerImpl::SetActiveScenario(
145 scoped_ptr<BackgroundTracingConfig> config,
146 const BackgroundTracingManager::ReceiveCallback& receive_callback,
147 DataFiltering data_filtering) {
148 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
149 RecordBackgroundTracingMetric(SCENARIO_ACTIVATION_REQUESTED);
151 if (is_tracing_)
152 return false;
154 bool requires_anonymized_data = (data_filtering == ANONYMIZE_DATA);
156 // If the I/O thread isn't running, this is a startup scenario and
157 // we have to wait until initialization is finished to validate that the
158 // scenario can run.
159 if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) {
160 // TODO(oysteine): Retry when time_until_allowed has elapsed.
161 if (config && delegate_ &&
162 !delegate_->IsAllowedToBeginBackgroundScenario(
163 *config.get(), requires_anonymized_data)) {
164 return false;
166 } else {
167 base::MessageLoop::current()->PostTask(
168 FROM_HERE,
169 base::Bind(&BackgroundTracingManagerImpl::ValidateStartupScenario,
170 base::Unretained(this)));
173 // No point in tracing if there's nowhere to send it.
174 if (config && receive_callback.is_null())
175 return false;
177 config_.reset(static_cast<BackgroundTracingConfigImpl*>(config.release()));
178 receive_callback_ = receive_callback;
179 requires_anonymized_data_ = requires_anonymized_data;
181 if (config_) {
182 DCHECK(!config_.get()->rules().empty());
183 for (auto& rule : config_.get()->rules())
184 static_cast<BackgroundTracingRule*>(rule)->Install();
187 EnableRecordingIfConfigNeedsIt();
189 RecordBackgroundTracingMetric(SCENARIO_ACTIVATED_SUCCESSFULLY);
190 return true;
193 bool BackgroundTracingManagerImpl::HasActiveScenarioForTesting() {
194 return config_;
197 void BackgroundTracingManagerImpl::ValidateStartupScenario() {
198 if (!config_ || !delegate_)
199 return;
201 if (!delegate_->IsAllowedToBeginBackgroundScenario(
202 *config_.get(), requires_anonymized_data_)) {
203 AbortScenario();
207 void BackgroundTracingManagerImpl::EnableRecordingIfConfigNeedsIt() {
208 if (!config_)
209 return;
211 if (config_->tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE) {
212 EnableRecording(
213 GetCategoryFilterStringForCategoryPreset(config_->category_preset()),
214 base::trace_event::RECORD_CONTINUOUSLY);
216 // There is nothing to do in case of reactive tracing.
219 BackgroundTracingRule*
220 BackgroundTracingManagerImpl::GetRuleAbleToTriggerTracing(
221 TriggerHandle handle) const {
222 if (!config_)
223 return nullptr;
225 // If the last trace is still uploading, we don't allow a new one to trigger.
226 if (is_gathering_)
227 return nullptr;
229 if (!IsTriggerHandleValid(handle)) {
230 return nullptr;
233 std::string trigger_name = GetTriggerNameFromHandle(handle);
234 for (const auto& rule : config_.get()->rules()) {
235 if (static_cast<BackgroundTracingRule*>(rule)
236 ->ShouldTriggerNamedEvent(trigger_name))
237 return static_cast<BackgroundTracingRule*>(rule);
240 return nullptr;
243 void BackgroundTracingManagerImpl::TriggerNamedEvent(
244 BackgroundTracingManagerImpl::TriggerHandle handle,
245 StartedFinalizingCallback callback) {
246 if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
247 content::BrowserThread::PostTask(
248 content::BrowserThread::UI, FROM_HERE,
249 base::Bind(&BackgroundTracingManagerImpl::TriggerNamedEvent,
250 base::Unretained(this), handle, callback));
251 return;
254 BackgroundTracingRule* triggered_rule = GetRuleAbleToTriggerTracing(handle);
255 if (!triggered_rule) {
256 if (!callback.is_null())
257 callback.Run(false);
258 return;
261 if (config_->tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE) {
262 RecordBackgroundTracingMetric(PREEMPTIVE_TRIGGERED);
263 BeginFinalizing(callback);
264 } else {
265 // A different reactive config tried to trigger.
266 if (is_tracing_ && handle != reactive_triggered_handle_) {
267 if (!callback.is_null())
268 callback.Run(false);
269 return;
272 RecordBackgroundTracingMetric(REACTIVE_TRIGGERED);
273 if (is_tracing_) {
274 tracing_timer_->CancelTimer();
275 BeginFinalizing(callback);
276 return;
279 // It was not already tracing, start a new trace.
280 EnableRecording(GetCategoryFilterStringForCategoryPreset(
281 triggered_rule->GetCategoryPreset()),
282 base::trace_event::RECORD_UNTIL_FULL);
283 tracing_timer_.reset(new TracingTimer(callback));
284 tracing_timer_->StartTimer(triggered_rule->GetReactiveTimeout());
285 reactive_triggered_handle_ = handle;
289 BackgroundTracingManagerImpl::TriggerHandle
290 BackgroundTracingManagerImpl::RegisterTriggerType(const char* trigger_name) {
291 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
293 trigger_handle_ids_ += 1;
295 trigger_handles_.insert(
296 std::pair<TriggerHandle, std::string>(trigger_handle_ids_, trigger_name));
298 return static_cast<TriggerHandle>(trigger_handle_ids_);
301 bool BackgroundTracingManagerImpl::IsTriggerHandleValid(
302 BackgroundTracingManager::TriggerHandle handle) const {
303 return trigger_handles_.find(handle) != trigger_handles_.end();
306 std::string BackgroundTracingManagerImpl::GetTriggerNameFromHandle(
307 BackgroundTracingManager::TriggerHandle handle) const {
308 CHECK(IsTriggerHandleValid(handle));
309 return trigger_handles_.find(handle)->second;
312 void BackgroundTracingManagerImpl::InvalidateTriggerHandlesForTesting() {
313 trigger_handles_.clear();
316 void BackgroundTracingManagerImpl::SetTracingEnabledCallbackForTesting(
317 const base::Closure& callback) {
318 tracing_enabled_callback_for_testing_ = callback;
321 void BackgroundTracingManagerImpl::FireTimerForTesting() {
322 tracing_timer_->FireTimerForTesting();
325 void BackgroundTracingManagerImpl::EnableRecording(
326 std::string category_filter_str,
327 base::trace_event::TraceRecordMode record_mode) {
328 base::trace_event::TraceConfig trace_config(category_filter_str, record_mode);
329 if (requires_anonymized_data_)
330 trace_config.EnableArgumentFilter();
332 is_tracing_ = TracingController::GetInstance()->EnableRecording(
333 trace_config, tracing_enabled_callback_for_testing_);
334 RecordBackgroundTracingMetric(RECORDING_ENABLED);
337 void BackgroundTracingManagerImpl::OnFinalizeStarted(
338 base::RefCountedString* file_contents) {
339 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
341 RecordBackgroundTracingMetric(FINALIZATION_STARTED);
342 UMA_HISTOGRAM_MEMORY_KB("Tracing.Background.FinalizingTraceSizeInKB",
343 file_contents->size() / 1024);
345 if (!receive_callback_.is_null()) {
346 receive_callback_.Run(
347 file_contents, GenerateMetadataDict(),
348 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete,
349 base::Unretained(this)));
353 void BackgroundTracingManagerImpl::OnFinalizeComplete() {
354 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
355 BrowserThread::PostTask(
356 BrowserThread::UI, FROM_HERE,
357 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeComplete,
358 base::Unretained(this)));
359 return;
362 CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
364 is_gathering_ = false;
366 if (!idle_callback_.is_null())
367 idle_callback_.Run();
369 // Now that a trace has completed, we may need to enable recording again.
370 // TODO(oysteine): Retry later if IsAllowedToBeginBackgroundScenario fails.
371 if (!delegate_ ||
372 delegate_->IsAllowedToBeginBackgroundScenario(
373 *config_.get(), requires_anonymized_data_)) {
374 EnableRecordingIfConfigNeedsIt();
375 } else {
376 AbortScenario();
379 RecordBackgroundTracingMetric(FINALIZATION_COMPLETE);
382 scoped_ptr<base::DictionaryValue>
383 BackgroundTracingManagerImpl::GenerateMetadataDict() const {
384 // Grab the network type.
385 std::string network_type = GetNetworkTypeString();
387 // Grab the product version.
388 std::string product_version = GetContentClient()->GetProduct();
390 // Serialize the config into json.
391 scoped_ptr<base::DictionaryValue> config_dict(new base::DictionaryValue());
393 config_->IntoDict(config_dict.get());
395 scoped_ptr<base::DictionaryValue> metadata_dict(new base::DictionaryValue());
396 metadata_dict->Set("config", config_dict.Pass());
397 metadata_dict->SetString("network-type", network_type);
398 metadata_dict->SetString("product-version", product_version);
400 // OS
401 metadata_dict->SetString("os-name", base::SysInfo::OperatingSystemName());
402 metadata_dict->SetString("os-version",
403 base::SysInfo::OperatingSystemVersion());
404 metadata_dict->SetString("os-arch",
405 base::SysInfo::OperatingSystemArchitecture());
407 // CPU
408 base::CPU cpu;
409 metadata_dict->SetInteger("cpu-family", cpu.family());
410 metadata_dict->SetInteger("cpu-model", cpu.model());
411 metadata_dict->SetInteger("cpu-stepping", cpu.stepping());
412 metadata_dict->SetInteger("num-cpus", base::SysInfo::NumberOfProcessors());
413 metadata_dict->SetInteger("physical-memory",
414 base::SysInfo::AmountOfPhysicalMemoryMB());
416 std::string cpu_brand = cpu.cpu_brand();
417 // Workaround for crbug.com/249713.
418 // TODO(oysteine): Remove workaround when bug is fixed.
419 size_t null_pos = cpu_brand.find('\0');
420 if (null_pos != std::string::npos)
421 cpu_brand.erase(null_pos);
422 metadata_dict->SetString("cpu-brand", cpu_brand);
424 // GPU
425 gpu::GPUInfo gpu_info = content::GpuDataManager::GetInstance()->GetGPUInfo();
427 #if !defined(OS_ANDROID)
428 metadata_dict->SetInteger("gpu-venid", gpu_info.gpu.vendor_id);
429 metadata_dict->SetInteger("gpu-devid", gpu_info.gpu.device_id);
430 #endif
432 metadata_dict->SetString("gpu-driver", gpu_info.driver_version);
433 metadata_dict->SetString("gpu-psver", gpu_info.pixel_shader_version);
434 metadata_dict->SetString("gpu-vsver", gpu_info.vertex_shader_version);
436 #if defined(OS_MACOSX)
437 metadata_dict->SetString("gpu-glver", gpu_info.gl_version);
438 #elif defined(OS_POSIX)
439 metadata_dict->SetString("gpu-gl-vendor", gpu_info.gl_vendor);
440 metadata_dict->SetString("gpu-gl-renderer", gpu_info.gl_renderer);
441 #endif
443 return metadata_dict.Pass();
446 void BackgroundTracingManagerImpl::BeginFinalizing(
447 StartedFinalizingCallback callback) {
448 is_gathering_ = true;
449 is_tracing_ = false;
450 reactive_triggered_handle_ = -1;
452 bool is_allowed_finalization =
453 !delegate_ || (config_ &&
454 delegate_->IsAllowedToEndBackgroundScenario(
455 *config_.get(), requires_anonymized_data_));
457 scoped_refptr<TracingControllerImpl::TraceDataSink> trace_data_sink;
458 if (is_allowed_finalization) {
459 trace_data_sink = content::TracingController::CreateCompressedStringSink(
460 content::TracingController::CreateCallbackEndpoint(
461 base::Bind(&BackgroundTracingManagerImpl::OnFinalizeStarted,
462 base::Unretained(this))));
463 RecordBackgroundTracingMetric(FINALIZATION_ALLOWED);
465 if (auto metadata_dict = GenerateMetadataDict()) {
466 std::string results;
467 if (base::JSONWriter::Write(*metadata_dict.get(), &results))
468 trace_data_sink->SetMetadata(results);
470 } else {
471 RecordBackgroundTracingMetric(FINALIZATION_DISALLOWED);
474 content::TracingController::GetInstance()->DisableRecording(trace_data_sink);
476 if (!callback.is_null())
477 callback.Run(is_allowed_finalization);
480 void BackgroundTracingManagerImpl::AbortScenario() {
481 is_tracing_ = false;
482 reactive_triggered_handle_ = -1;
483 config_.reset();
485 content::TracingController::GetInstance()->DisableRecording(nullptr);
488 std::string
489 BackgroundTracingManagerImpl::GetCategoryFilterStringForCategoryPreset(
490 BackgroundTracingConfigImpl::CategoryPreset preset) const {
491 switch (preset) {
492 case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK:
493 return "benchmark,toplevel";
494 case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_DEEP:
495 return "*,disabled-by-default-benchmark.detailed";
496 case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_GPU:
497 return "benchmark,toplevel,gpu";
498 case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_IPC:
499 return "benchmark,toplevel,ipc";
500 case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP:
501 return "benchmark,toplevel,startup,disabled-by-default-file";
503 NOTREACHED();
504 return "";
507 } // namspace content