blob: 0e18cf6fddfe13b17a6ce319af19e55b1ddc5e75 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "content/browser/tracing/background_tracing_manager_impl.h"
#include <utility>
#include "base/command_line.h"
#include "base/json/json_writer.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/metrics/histogram_macros.h"
#include "base/rand_util.h"
#include "base/single_thread_task_runner.h"
#include "base/task/post_task.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/time/time.h"
#include "base/values.h"
#include "components/tracing/common/trace_startup_config.h"
#include "content/browser/tracing/background_memory_tracing_observer.h"
#include "content/browser/tracing/background_startup_tracing_observer.h"
#include "content/browser/tracing/background_tracing_rule.h"
#include "content/browser/tracing/trace_message_filter.h"
#include "content/browser/tracing/tracing_controller_impl.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/tracing_delegate.h"
#include "content/public/common/content_client.h"
#include "content/public/common/content_switches.h"
#include "services/tracing/public/cpp/trace_event_agent.h"
using base::trace_event::TraceConfig;
namespace content {
namespace {
base::LazyInstance<BackgroundTracingManagerImpl>::Leaky
g_background_tracing_manager = LAZY_INSTANCE_INITIALIZER;
// These values are used for a histogram. Do not reorder.
enum BackgroundTracingMetrics {
SCENARIO_ACTIVATION_REQUESTED = 0,
SCENARIO_ACTIVATED_SUCCESSFULLY = 1,
RECORDING_ENABLED = 2,
PREEMPTIVE_TRIGGERED = 3,
REACTIVE_TRIGGERED = 4,
FINALIZATION_ALLOWED = 5,
FINALIZATION_DISALLOWED = 6,
FINALIZATION_STARTED = 7,
OBSOLETE_FINALIZATION_COMPLETE = 8,
SCENARIO_ACTION_FAILED_LOWRES_CLOCK = 9,
UPLOAD_FAILED = 10,
UPLOAD_SUCCEEDED = 11,
STARTUP_SCENARIO_TRIGGERED = 12,
NUMBER_OF_BACKGROUND_TRACING_METRICS,
};
void RecordBackgroundTracingMetric(BackgroundTracingMetrics metric) {
UMA_HISTOGRAM_ENUMERATION("Tracing.Background.ScenarioState", metric,
NUMBER_OF_BACKGROUND_TRACING_METRICS);
}
} // namespace
BackgroundTracingManagerImpl::TracingTimer::TracingTimer(
StartedFinalizingCallback callback) : callback_(callback) {
}
BackgroundTracingManagerImpl::TracingTimer::~TracingTimer() {
}
void BackgroundTracingManagerImpl::TracingTimer::StartTimer(int seconds) {
tracing_timer_.Start(
FROM_HERE, base::TimeDelta::FromSeconds(seconds), this,
&BackgroundTracingManagerImpl::TracingTimer::TracingTimerFired);
}
void BackgroundTracingManagerImpl::TracingTimer::CancelTimer() {
tracing_timer_.Stop();
}
void BackgroundTracingManagerImpl::TracingTimer::TracingTimerFired() {
BackgroundTracingManagerImpl::GetInstance()->BeginFinalizing(callback_);
}
void BackgroundTracingManagerImpl::TracingTimer::FireTimerForTesting() {
CancelTimer();
TracingTimerFired();
}
BackgroundTracingManager* BackgroundTracingManager::GetInstance() {
return BackgroundTracingManagerImpl::GetInstance();
}
BackgroundTracingManagerImpl* BackgroundTracingManagerImpl::GetInstance() {
return g_background_tracing_manager.Pointer();
}
BackgroundTracingManagerImpl::BackgroundTracingManagerImpl()
: delegate_(GetContentClient()->browser()->GetTracingDelegate()),
is_gathering_(false),
is_tracing_(false),
requires_anonymized_data_(true),
trigger_handle_ids_(0),
triggered_named_event_handle_(-1) {
AddEnabledStateObserver(BackgroundMemoryTracingObserver::GetInstance());
AddEnabledStateObserver(BackgroundStartupTracingObserver::GetInstance());
}
BackgroundTracingManagerImpl::~BackgroundTracingManagerImpl() {
NOTREACHED();
}
void BackgroundTracingManagerImpl::AddMetadataGeneratorFunction() {
tracing::TraceEventAgent::GetInstance()->AddMetadataGeneratorFunction(
base::BindRepeating(&BackgroundTracingManagerImpl::GenerateMetadataDict,
base::Unretained(this)));
}
void BackgroundTracingManagerImpl::WhenIdle(
base::Callback<void()> idle_callback) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
idle_callback_ = std::move(idle_callback);
}
bool BackgroundTracingManagerImpl::SetActiveScenario(
std::unique_ptr<BackgroundTracingConfig> config,
BackgroundTracingManager::ReceiveCallback receive_callback,
DataFiltering data_filtering) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (config)
RecordBackgroundTracingMetric(SCENARIO_ACTIVATION_REQUESTED);
if (is_tracing_)
return false;
// If we don't have a high resolution timer available, traces will be
// too inaccurate to be useful.
if (!base::TimeTicks::IsHighResolution()) {
if (config)
RecordBackgroundTracingMetric(SCENARIO_ACTION_FAILED_LOWRES_CLOCK);
return false;
}
std::unique_ptr<content::BackgroundTracingConfigImpl> config_impl(
static_cast<BackgroundTracingConfigImpl*>(config.release()));
config_impl = BackgroundStartupTracingObserver::GetInstance()
->IncludeStartupConfigIfNeeded(std::move(config_impl));
if (BackgroundStartupTracingObserver::GetInstance()
->enabled_in_current_session()) {
// Anonymize data for startup tracing by default. We currently do not
// support storing the config in preferences for next session.
data_filtering = DataFiltering::ANONYMIZE_DATA;
RecordBackgroundTracingMetric(STARTUP_SCENARIO_TRIGGERED);
} else {
// If startup config was not set and tracing was enabled, then do not set
// any scenario.
if (base::trace_event::TraceLog::GetInstance()->IsEnabled())
return false;
}
if (!config_impl)
return false;
bool requires_anonymized_data = (data_filtering == ANONYMIZE_DATA);
// If the profile hasn't loaded or been created yet, this is a startup
// scenario and we have to wait until initialization is finished to validate
// that the scenario can run.
if (!delegate_ || delegate_->IsProfileLoaded()) {
// TODO(oysteine): Retry when time_until_allowed has elapsed.
if (config_impl && delegate_ &&
!delegate_->IsAllowedToBeginBackgroundScenario(
*config_impl.get(), requires_anonymized_data)) {
return false;
}
} else {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&BackgroundTracingManagerImpl::ValidateStartupScenario,
base::Unretained(this)));
}
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (config_impl) {
// No point in tracing if there's nowhere to send it.
if (receive_callback.is_null())
return false;
// If the scenario requires us to toggle Blink features, we want
// to neither override anything else nor to do we want to activate
// the scenario without doing the toggle, so if something else has
// configured these switches we just abort.
if (!config_impl->enable_blink_features().empty() &&
command_line->HasSwitch(switches::kEnableBlinkFeatures)) {
return false;
}
if (!config_impl->disable_blink_features().empty() &&
command_line->HasSwitch(switches::kDisableBlinkFeatures)) {
return false;
}
}
config_ = std::move(config_impl);
receive_callback_ = std::move(receive_callback);
requires_anonymized_data_ = requires_anonymized_data;
DCHECK(!config_->rules().empty());
for (const auto& rule : config_->rules())
rule->Install();
if (!config_->enable_blink_features().empty()) {
command_line->AppendSwitchASCII(switches::kEnableBlinkFeatures,
config_->enable_blink_features());
}
if (!config_->disable_blink_features().empty()) {
command_line->AppendSwitchASCII(switches::kDisableBlinkFeatures,
config_->disable_blink_features());
}
// Notify observers before starting tracing.
for (auto* observer : background_tracing_observers_)
observer->OnScenarioActivated(config_.get());
StartTracingIfConfigNeedsIt();
RecordBackgroundTracingMetric(SCENARIO_ACTIVATED_SUCCESSFULLY);
return true;
}
bool BackgroundTracingManagerImpl::HasActiveScenario() {
return !!config_;
}
void BackgroundTracingManagerImpl::OnStartTracingDone(
BackgroundTracingConfigImpl::CategoryPreset preset) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
for (auto* observer : background_tracing_observers_)
observer->OnTracingEnabled(preset);
}
void BackgroundTracingManagerImpl::AddEnabledStateObserver(
EnabledStateObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
background_tracing_observers_.insert(observer);
}
void BackgroundTracingManagerImpl::RemoveEnabledStateObserver(
EnabledStateObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
background_tracing_observers_.erase(observer);
}
void BackgroundTracingManagerImpl::AddTraceMessageFilter(
TraceMessageFilter* trace_message_filter) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
trace_message_filters_.insert(trace_message_filter);
for (auto* observer : trace_message_filter_observers_)
observer->OnTraceMessageFilterAdded(trace_message_filter);
}
void BackgroundTracingManagerImpl::RemoveTraceMessageFilter(
TraceMessageFilter* trace_message_filter) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
for (auto* observer : trace_message_filter_observers_)
observer->OnTraceMessageFilterRemoved(trace_message_filter);
trace_message_filters_.erase(trace_message_filter);
}
void BackgroundTracingManagerImpl::AddTraceMessageFilterObserver(
TraceMessageFilterObserver* observer) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
trace_message_filter_observers_.insert(observer);
for (auto& filter : trace_message_filters_)
observer->OnTraceMessageFilterAdded(filter.get());
}
void BackgroundTracingManagerImpl::RemoveTraceMessageFilterObserver(
TraceMessageFilterObserver* observer) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
trace_message_filter_observers_.erase(observer);
for (auto& filter : trace_message_filters_)
observer->OnTraceMessageFilterRemoved(filter.get());
}
bool BackgroundTracingManagerImpl::IsTracingForTesting() {
return is_tracing_;
}
void BackgroundTracingManagerImpl::ValidateStartupScenario() {
if (!config_ || !delegate_)
return;
if (!delegate_->IsAllowedToBeginBackgroundScenario(
*config_.get(), requires_anonymized_data_)) {
AbortScenario();
}
}
void BackgroundTracingManagerImpl::StartTracingIfConfigNeedsIt() {
if (!config_)
return;
if (config_->tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE) {
StartTracing(config_->category_preset(),
base::trace_event::RECORD_CONTINUOUSLY);
}
// There is nothing to do in case of reactive tracing.
}
BackgroundTracingRule*
BackgroundTracingManagerImpl::GetRuleAbleToTriggerTracing(
TriggerHandle handle) const {
if (!config_)
return nullptr;
// If the last trace is still uploading, we don't allow a new one to trigger.
if (is_gathering_)
return nullptr;
if (!IsTriggerHandleValid(handle)) {
return nullptr;
}
std::string trigger_name = GetTriggerNameFromHandle(handle);
for (const auto& rule : config_->rules()) {
if (rule->ShouldTriggerNamedEvent(trigger_name))
return rule.get();
}
return nullptr;
}
void BackgroundTracingManagerImpl::OnHistogramTrigger(
const std::string& histogram_name) {
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&BackgroundTracingManagerImpl::OnHistogramTrigger,
base::Unretained(this), histogram_name));
return;
}
if (!config_)
return;
for (const auto& rule : config_->rules()) {
if (rule->ShouldTriggerNamedEvent(histogram_name))
OnRuleTriggered(rule.get(), StartedFinalizingCallback());
}
}
void BackgroundTracingManagerImpl::TriggerNamedEvent(
BackgroundTracingManagerImpl::TriggerHandle handle,
StartedFinalizingCallback callback) {
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&BackgroundTracingManagerImpl::TriggerNamedEvent,
base::Unretained(this), handle, std::move(callback)));
return;
}
bool is_valid_trigger = true;
const BackgroundTracingRule* triggered_rule =
GetRuleAbleToTriggerTracing(handle);
if (!triggered_rule)
is_valid_trigger = false;
// A different reactive config than the running one tried to trigger.
if (!config_ ||
(config_->tracing_mode() == BackgroundTracingConfigImpl::REACTIVE &&
is_tracing_ && triggered_named_event_handle_ != handle)) {
is_valid_trigger = false;
}
if (!is_valid_trigger) {
if (!callback.is_null())
std::move(callback).Run(false);
return;
}
triggered_named_event_handle_ = handle;
OnRuleTriggered(triggered_rule, std::move(callback));
}
void BackgroundTracingManagerImpl::OnRuleTriggered(
const BackgroundTracingRule* triggered_rule,
StartedFinalizingCallback callback) {
// Config can be null here if scenario was aborted when validation and rule
// was triggered just before validation. If validation kicked in after this
// point, we still check before uploading.
if (!config_)
return;
double trigger_chance = triggered_rule->trigger_chance();
if (trigger_chance < 1.0 && base::RandDouble() > trigger_chance) {
if (!callback.is_null())
std::move(callback).Run(false);
return;
}
last_triggered_rule_.reset(new base::DictionaryValue);
triggered_rule->IntoDict(last_triggered_rule_.get());
int trace_delay = triggered_rule->GetTraceDelay();
if (config_->tracing_mode() == BackgroundTracingConfigImpl::REACTIVE) {
// In reactive mode, a trigger starts tracing, or finalizes tracing
// immediately if it's already running.
RecordBackgroundTracingMetric(REACTIVE_TRIGGERED);
if (!is_tracing_) {
// It was not already tracing, start a new trace.
StartTracing(triggered_rule->category_preset(),
base::trace_event::RECORD_UNTIL_FULL);
} else {
// Some reactive configs that trigger again while tracing should just
// end right away (to not capture multiple navigations, for example).
// For others we just want to ignore the repeated trigger.
if (triggered_rule->stop_tracing_on_repeated_reactive()) {
trace_delay = -1;
} else {
if (!callback.is_null())
std::move(callback).Run(false);
return;
}
}
} else {
// In preemptive mode, a trigger starts finalizing a trace if one is
// running and we're not got a finalization timer running,
// otherwise we do nothing.
if (!is_tracing_ || is_gathering_ || tracing_timer_) {
if (!callback.is_null())
std::move(callback).Run(false);
return;
}
RecordBackgroundTracingMetric(PREEMPTIVE_TRIGGERED);
}
if (trace_delay < 0) {
BeginFinalizing(std::move(callback));
} else {
tracing_timer_.reset(new TracingTimer(std::move(callback)));
tracing_timer_->StartTimer(trace_delay);
}
if (!rule_triggered_callback_for_testing_.is_null())
rule_triggered_callback_for_testing_.Run();
}
BackgroundTracingManagerImpl::TriggerHandle
BackgroundTracingManagerImpl::RegisterTriggerType(const char* trigger_name) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
trigger_handle_ids_ += 1;
trigger_handles_.insert(
std::pair<TriggerHandle, std::string>(trigger_handle_ids_, trigger_name));
return static_cast<TriggerHandle>(trigger_handle_ids_);
}
bool BackgroundTracingManagerImpl::IsTriggerHandleValid(
BackgroundTracingManager::TriggerHandle handle) const {
return trigger_handles_.find(handle) != trigger_handles_.end();
}
std::string BackgroundTracingManagerImpl::GetTriggerNameFromHandle(
BackgroundTracingManager::TriggerHandle handle) const {
CHECK(IsTriggerHandleValid(handle));
return trigger_handles_.find(handle)->second;
}
void BackgroundTracingManagerImpl::InvalidateTriggerHandlesForTesting() {
trigger_handles_.clear();
}
void BackgroundTracingManagerImpl::SetRuleTriggeredCallbackForTesting(
const base::Closure& callback) {
rule_triggered_callback_for_testing_ = callback;
}
void BackgroundTracingManagerImpl::FireTimerForTesting() {
DCHECK(tracing_timer_);
tracing_timer_->FireTimerForTesting();
}
void BackgroundTracingManagerImpl::StartTracing(
BackgroundTracingConfigImpl::CategoryPreset preset,
base::trace_event::TraceRecordMode record_mode) {
TraceConfig config = GetConfigForCategoryPreset(preset, record_mode);
if (requires_anonymized_data_)
config.EnableArgumentFilter();
#if defined(OS_ANDROID)
// Set low trace buffer size on Android in order to upload small trace files.
if (config_->tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE)
config.SetTraceBufferSizeInEvents(20000);
#endif
// Activate the categories immediately. StartTracing eventually does this
// itself, but asynchronously via PostTask, and in the meantime events will be
// dropped. This ensures that we start recording events for those categories
// immediately.
if (is_tracing_) {
uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
if (!config.event_filters().empty())
modes |= base::trace_event::TraceLog::FILTERING_MODE;
base::trace_event::TraceLog::GetInstance()->SetEnabled(config, modes);
}
is_tracing_ = TracingControllerImpl::GetInstance()->StartTracing(
config, base::BindOnce(&BackgroundTracingManagerImpl::OnStartTracingDone,
base::Unretained(this), preset));
RecordBackgroundTracingMetric(RECORDING_ENABLED);
}
void BackgroundTracingManagerImpl::OnFinalizeStarted(
base::Closure started_finalizing_closure,
std::unique_ptr<const base::DictionaryValue> metadata,
base::RefCountedString* file_contents) {
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
RecordBackgroundTracingMetric(FINALIZATION_STARTED);
UMA_HISTOGRAM_MEMORY_KB("Tracing.Background.FinalizingTraceSizeInKB",
file_contents->size() / 1024);
if (!receive_callback_.is_null()) {
receive_callback_.Run(
file_contents, std::move(metadata),
base::BindOnce(&BackgroundTracingManagerImpl::OnFinalizeComplete,
base::Unretained(this)));
}
if (!started_finalizing_closure.is_null())
std::move(started_finalizing_closure).Run();
}
void BackgroundTracingManagerImpl::OnFinalizeComplete(bool success) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(&BackgroundTracingManagerImpl::OnFinalizeComplete,
base::Unretained(this), success));
return;
}
CHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
is_gathering_ = false;
if (!idle_callback_.is_null())
idle_callback_.Run();
bool is_allowed_begin =
!delegate_ || (config_ &&
delegate_->IsAllowedToBeginBackgroundScenario(
*config_.get(), requires_anonymized_data_));
// Now that a trace has completed, we may need to enable recording again.
// TODO(oysteine): Retry later if IsAllowedToBeginBackgroundScenario fails.
if (is_allowed_begin) {
StartTracingIfConfigNeedsIt();
} else {
AbortScenario();
}
if (success) {
RecordBackgroundTracingMetric(UPLOAD_SUCCEEDED);
} else {
RecordBackgroundTracingMetric(UPLOAD_FAILED);
}
}
bool BackgroundTracingManagerImpl::IsAllowedFinalization() const {
return !delegate_ ||
(config_ && delegate_->IsAllowedToEndBackgroundScenario(
*config_.get(), requires_anonymized_data_));
}
std::unique_ptr<base::DictionaryValue>
BackgroundTracingManagerImpl::GenerateMetadataDict() {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto metadata_dict = std::make_unique<base::DictionaryValue>();
if (config_) {
auto config_dict = std::make_unique<base::DictionaryValue>();
config_->IntoDict(config_dict.get());
metadata_dict->Set("config", std::move(config_dict));
metadata_dict->SetString("scenario_name", config_->scenario_name());
}
if (last_triggered_rule_)
metadata_dict->Set("last_triggered_rule", std::move(last_triggered_rule_));
return metadata_dict;
}
void BackgroundTracingManagerImpl::BeginFinalizing(
StartedFinalizingCallback callback) {
is_gathering_ = true;
is_tracing_ = false;
triggered_named_event_handle_ = -1;
tracing_timer_.reset();
scoped_refptr<TracingControllerImpl::TraceDataEndpoint> trace_data_endpoint;
bool is_allowed_finalization = IsAllowedFinalization();
base::Closure started_finalizing_closure;
if (!callback.is_null()) {
started_finalizing_closure =
base::BindRepeating(callback, is_allowed_finalization);
}
if (is_allowed_finalization) {
trace_data_endpoint = TracingControllerImpl::CreateCompressedStringEndpoint(
TracingControllerImpl::CreateCallbackEndpoint(base::Bind(
&BackgroundTracingManagerImpl::OnFinalizeStarted,
base::Unretained(this), std::move(started_finalizing_closure))),
true /* compress_with_background_priority */);
RecordBackgroundTracingMetric(FINALIZATION_ALLOWED);
} else {
if (!std::move(callback).is_null()) {
trace_data_endpoint =
TracingControllerImpl::CreateCallbackEndpoint(base::BindRepeating(
[](base::Closure closure,
std::unique_ptr<const base::DictionaryValue> metadata,
base::RefCountedString* file_contents) {
std::move(closure).Run();
},
std::move(started_finalizing_closure)));
}
RecordBackgroundTracingMetric(FINALIZATION_DISALLOWED);
}
content::TracingControllerImpl::GetInstance()->StopTracing(
trace_data_endpoint);
}
void BackgroundTracingManagerImpl::AbortScenario() {
if (is_tracing_) {
scoped_refptr<TracingControllerImpl::TraceDataEndpoint> trace_data_endpoint;
trace_data_endpoint =
TracingControllerImpl::CreateCallbackEndpoint(base::BindRepeating(
&BackgroundTracingManagerImpl::OnAbortScenarioReceived,
base::Unretained(this)));
content::TracingControllerImpl::GetInstance()->StopTracing(
trace_data_endpoint);
} else {
OnAbortScenarioReceived(nullptr, nullptr);
}
}
void BackgroundTracingManagerImpl::OnAbortScenarioReceived(
std::unique_ptr<const base::DictionaryValue> metadata,
base::RefCountedString* trace_str) {
if (base::trace_event::TraceLog::GetInstance()->IsEnabled()) {
// Since the BackgroundTracingManager directly enables tracing
// in TraceLog, in addition to going through Mojo, there's an edge-case
// where tracing is rapidly stopped after starting, too quickly for the
// TraceEventAgent of the browser process to register itself, which means
// that we're left in a state where the Mojo interface doesn't think we're
// tracing but TraceLog is still enabled. If that's the case, we abort
// tracing here.
auto record_mode =
(config_->tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE)
? base::trace_event::RECORD_CONTINUOUSLY
: base::trace_event::RECORD_UNTIL_FULL;
TraceConfig config =
GetConfigForCategoryPreset(config_->category_preset(), record_mode);
uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE;
if (!config.event_filters().empty())
modes |= base::trace_event::TraceLog::FILTERING_MODE;
base::trace_event::TraceLog::GetInstance()->SetDisabled(modes);
}
is_tracing_ = false;
triggered_named_event_handle_ = -1;
config_.reset();
tracing_timer_.reset();
for (auto* observer : background_tracing_observers_)
observer->OnScenarioAborted();
}
TraceConfig BackgroundTracingManagerImpl::GetConfigForCategoryPreset(
BackgroundTracingConfigImpl::CategoryPreset preset,
base::trace_event::TraceRecordMode record_mode) const {
switch (preset) {
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK:
return TraceConfig("benchmark,toplevel", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_DEEP:
return TraceConfig(
"*,disabled-by-default-benchmark.detailed,"
"disabled-by-default-v8.cpu_profile,"
"disabled-by-default-v8.runtime_stats",
record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_GPU:
return TraceConfig(
"benchmark,toplevel,gpu,base,mojom,ipc,"
"disabled-by-default-system_stats,disabled-by-default-cpu_profiler",
record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_IPC:
return TraceConfig("benchmark,toplevel,ipc", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_STARTUP: {
auto config =
tracing::TraceStartupConfig::GetDefaultBrowserStartupConfig();
config.SetTraceRecordMode(record_mode);
return config;
}
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_BLINK_GC:
return TraceConfig("blink_gc,disabled-by-default-blink_gc", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::
BENCHMARK_EXECUTION_METRIC:
return TraceConfig("blink.console,v8", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_NAVIGATION: {
auto config = TraceConfig(
"benchmark,toplevel,ipc,base,browser,navigation,omnibox,ui,shutdown,"
"safe_browsing,Java,EarlyJava,loading,startup,"
"disabled-by-default-system_stats,disabled-by-default-cpu_profiler",
record_mode);
// Filter only browser process events.
base::trace_event::TraceConfig::ProcessFilterConfig process_config(
{base::GetCurrentProcId()});
config.SetProcessFilterConfig(process_config);
return config;
}
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_RENDERERS:
return TraceConfig(
"benchmark,toplevel,ipc,base,ui,v8,renderer,blink,blink_gc,"
"disabled-by-default-v8.gc,"
"disabled-by-default-blink_gc,"
"disabled-by-default-renderer.scheduler,"
"disabled-by-default-system_stats,disabled-by-default-cpu_profiler",
record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_SERVICEWORKER:
return TraceConfig(
"benchmark,toplevel,ipc,base,ServiceWorker,CacheStorage,Blob,"
"loader,loading,navigation,blink.user_timing,"
"disabled-by-default-network",
record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BLINK_STYLE:
return TraceConfig("blink_style", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_MEMORY_HEAVY:
return TraceConfig("-*,disabled-by-default-memory-infra", record_mode);
case BackgroundTracingConfigImpl::CategoryPreset::BENCHMARK_MEMORY_LIGHT: {
// On memory light mode, the periodic memory dumps are disabled.
base::trace_event::TraceConfig::MemoryDumpConfig memory_config;
memory_config.allowed_dump_modes =
std::set<base::trace_event::MemoryDumpLevelOfDetail>(
{base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND});
TraceConfig config("-*,disabled-by-default-memory-infra", record_mode);
config.ResetMemoryDumpConfig(memory_config);
return config;
}
case BackgroundTracingConfigImpl::CategoryPreset::CATEGORY_PRESET_UNSET:
NOTREACHED();
}
NOTREACHED();
return TraceConfig();
}
} // namespace content