summaryrefslogtreecommitdiff
path: root/chromium/components/tracing
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/components/tracing')
-rw-r--r--chromium/components/tracing/BUILD.gn30
-rw-r--r--chromium/components/tracing/DEPS1
-rw-r--r--chromium/components/tracing/OWNERS1
-rw-r--r--chromium/components/tracing/child_memory_dump_manager_delegate_impl.cc64
-rw-r--r--chromium/components/tracing/child_memory_dump_manager_delegate_impl.h24
-rw-r--r--chromium/components/tracing/child_trace_message_filter.cc85
-rw-r--r--chromium/components/tracing/child_trace_message_filter.h16
-rw-r--r--chromium/components/tracing/startup_tracing.cc66
-rw-r--r--chromium/components/tracing/startup_tracing.h18
-rw-r--r--chromium/components/tracing/trace_config_file.cc140
-rw-r--r--chromium/components/tracing/trace_config_file.h96
-rw-r--r--chromium/components/tracing/trace_config_file_unittest.cc220
-rw-r--r--chromium/components/tracing/tracing_export.h29
-rw-r--r--chromium/components/tracing/tracing_messages.h23
-rw-r--r--chromium/components/tracing/tracing_switches.cc52
-rw-r--r--chromium/components/tracing/tracing_switches.h22
16 files changed, 774 insertions, 113 deletions
diff --git a/chromium/components/tracing/BUILD.gn b/chromium/components/tracing/BUILD.gn
index 336f5cb5ea4..bd5b2711492 100644
--- a/chromium/components/tracing/BUILD.gn
+++ b/chromium/components/tracing/BUILD.gn
@@ -2,29 +2,51 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("tracing") {
+component("tracing") {
sources = [
"child_memory_dump_manager_delegate_impl.cc",
"child_memory_dump_manager_delegate_impl.h",
"child_trace_message_filter.cc",
"child_trace_message_filter.h",
+ "tracing_export.h",
"tracing_messages.cc",
"tracing_messages.h",
]
+ defines = [ "TRACING_IMPLEMENTATION" ]
+
deps = [
"//base",
"//ipc",
]
}
-source_set("startup_tracing") {
+component("startup_tracing") {
sources = [
- "startup_tracing.cc",
- "startup_tracing.h",
+ "trace_config_file.cc",
+ "trace_config_file.h",
+ "tracing_export.h",
+ "tracing_switches.cc",
+ "tracing_switches.h",
]
+ defines = [ "TRACING_IMPLEMENTATION" ]
+
deps = [
"//base",
]
}
+
+source_set("unit_tests") {
+ testonly = true
+
+ sources = [
+ "trace_config_file_unittest.cc",
+ ]
+
+ deps = [
+ ":startup_tracing",
+ "//base/test:test_support",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/tracing/DEPS b/chromium/components/tracing/DEPS
index 9634ba4f06a..1c40d981eb6 100644
--- a/chromium/components/tracing/DEPS
+++ b/chromium/components/tracing/DEPS
@@ -1,4 +1,3 @@
include_rules = [
- "+base",
"+ipc",
]
diff --git a/chromium/components/tracing/OWNERS b/chromium/components/tracing/OWNERS
index 2226238acb8..1a389403d36 100644
--- a/chromium/components/tracing/OWNERS
+++ b/chromium/components/tracing/OWNERS
@@ -1,6 +1,7 @@
jbauman@chromium.org
nduca@chromium.org
dsinclair@chromium.org
+simonhatch@chromium.org
# Changes to IPC messages require a security review to avoid introducing
# new sandbox escapes.
diff --git a/chromium/components/tracing/child_memory_dump_manager_delegate_impl.cc b/chromium/components/tracing/child_memory_dump_manager_delegate_impl.cc
index 4e2cc9f318d..fe5c952f6a9 100644
--- a/chromium/components/tracing/child_memory_dump_manager_delegate_impl.cc
+++ b/chromium/components/tracing/child_memory_dump_manager_delegate_impl.cc
@@ -9,67 +9,89 @@
namespace tracing {
+namespace {
+void AbortDumpRequest(const base::trace_event::MemoryDumpRequestArgs& args,
+ const base::trace_event::MemoryDumpCallback& callback) {
+ if (!callback.is_null())
+ callback.Run(args.dump_guid, false /* success */);
+}
+} // namespace
+
// static
ChildMemoryDumpManagerDelegateImpl*
ChildMemoryDumpManagerDelegateImpl::GetInstance() {
- return Singleton<
+ return base::Singleton<
ChildMemoryDumpManagerDelegateImpl,
- LeakySingletonTraits<ChildMemoryDumpManagerDelegateImpl>>::get();
+ base::LeakySingletonTraits<ChildMemoryDumpManagerDelegateImpl>>::get();
}
ChildMemoryDumpManagerDelegateImpl::ChildMemoryDumpManagerDelegateImpl()
- : ctmf_(nullptr) {
- base::trace_event::MemoryDumpManager::GetInstance()->SetDelegate(this);
+ : ctmf_(nullptr),
+ tracing_process_id_(
+ base::trace_event::MemoryDumpManager::kInvalidTracingProcessId) {
}
-ChildMemoryDumpManagerDelegateImpl::~ChildMemoryDumpManagerDelegateImpl() {
-}
+ChildMemoryDumpManagerDelegateImpl::~ChildMemoryDumpManagerDelegateImpl() {}
void ChildMemoryDumpManagerDelegateImpl::SetChildTraceMessageFilter(
ChildTraceMessageFilter* ctmf) {
+ const auto& task_runner = ctmf ? (ctmf->ipc_task_runner()) : nullptr;
// Check that we are either registering the CTMF or tearing it down, but not
// replacing a valid instance with another one (should never happen).
DCHECK(ctmf_ == nullptr || (ctmf == nullptr && ctmf_task_runner_ != nullptr));
ctmf_ = ctmf;
- ctmf_task_runner_ = ctmf ? (ctmf->ipc_task_runner()) : nullptr;
+
+ {
+ base::AutoLock lock(lock_);
+ ctmf_task_runner_ = task_runner;
+ }
+
+ if (ctmf) {
+ base::trace_event::MemoryDumpManager::GetInstance()->Initialize(
+ this /* delegate */, false /* is_coordinator */);
+ }
}
// Invoked in child processes by the MemoryDumpManager.
void ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
const base::trace_event::MemoryDumpCallback& callback) {
+ // RequestGlobalMemoryDump can be called on any thread, cannot access
+ // ctmf_task_runner_ as it could be racy.
+ scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner;
+ {
+ base::AutoLock lock(lock_);
+ ctmf_task_runner = ctmf_task_runner_;
+ }
+
// Bail out if we receive a dump request from the manager before the
// ChildTraceMessageFilter has been initialized.
- if (!ctmf_task_runner_) {
- if (!callback.is_null())
- callback.Run(args.dump_guid, false /* success */);
- return;
- }
+ if (!ctmf_task_runner)
+ return AbortDumpRequest(args, callback);
// Make sure we access |ctmf_| only on the thread where it lives to avoid
// races on shutdown.
- if (!ctmf_task_runner_->BelongsToCurrentThread()) {
- ctmf_task_runner_->PostTask(
+ if (!ctmf_task_runner->BelongsToCurrentThread()) {
+ const bool did_post_task = ctmf_task_runner->PostTask(
FROM_HERE,
base::Bind(&ChildMemoryDumpManagerDelegateImpl::RequestGlobalMemoryDump,
base::Unretained(this), args, callback));
+ if (!did_post_task)
+ return AbortDumpRequest(args, callback);
return;
}
// The ChildTraceMessageFilter could have been destroyed while hopping on the
// right thread. If this is the case, bail out.
- if (!ctmf_) {
- if (!callback.is_null())
- callback.Run(args.dump_guid, false /* success */);
- return;
- }
+ if (!ctmf_)
+ return AbortDumpRequest(args, callback);
// Send the request up to the browser process' MessageDumpmanager.
ctmf_->SendGlobalMemoryDumpRequest(args, callback);
}
-bool ChildMemoryDumpManagerDelegateImpl::IsCoordinatorProcess() const {
- return false;
+uint64 ChildMemoryDumpManagerDelegateImpl::GetTracingProcessId() const {
+ return tracing_process_id_;
}
} // namespace tracing
diff --git a/chromium/components/tracing/child_memory_dump_manager_delegate_impl.h b/chromium/components/tracing/child_memory_dump_manager_delegate_impl.h
index 912815dd018..ca5de293ed7 100644
--- a/chromium/components/tracing/child_memory_dump_manager_delegate_impl.h
+++ b/chromium/components/tracing/child_memory_dump_manager_delegate_impl.h
@@ -9,6 +9,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
namespace base {
class SingleThreadTaskRunner;
@@ -33,16 +34,27 @@ class ChildMemoryDumpManagerDelegateImpl
void RequestGlobalMemoryDump(
const base::trace_event::MemoryDumpRequestArgs& args,
const base::trace_event::MemoryDumpCallback& callback) override;
- bool IsCoordinatorProcess() const override;
+ uint64 GetTracingProcessId() const override;
void SetChildTraceMessageFilter(ChildTraceMessageFilter* ctmf);
+ // Pass kInvalidTracingProcessId to invalidate the id.
+ void set_tracing_process_id(uint64 id) {
+ DCHECK_IMPLIES(
+ tracing_process_id_ !=
+ base::trace_event::MemoryDumpManager::kInvalidTracingProcessId,
+ id == base::trace_event::MemoryDumpManager::kInvalidTracingProcessId ||
+ id == tracing_process_id_);
+ tracing_process_id_ = id;
+ }
+
protected:
// Make CreateProcessDump() visible to ChildTraceMessageFilter.
friend class ChildTraceMessageFilter;
private:
- friend struct DefaultSingletonTraits<ChildMemoryDumpManagerDelegateImpl>;
+ friend struct base::DefaultSingletonTraits<
+ ChildMemoryDumpManagerDelegateImpl>;
ChildMemoryDumpManagerDelegateImpl();
~ChildMemoryDumpManagerDelegateImpl() override;
@@ -53,6 +65,14 @@ class ChildMemoryDumpManagerDelegateImpl
// It is NULL iff |cmtf_| is NULL.
scoped_refptr<base::SingleThreadTaskRunner> ctmf_task_runner_;
+ // Protects from concurrent access to |ctmf_task_runner_| to allow
+ // RequestGlobalMemoryDump to be called from arbitrary threads.
+ base::Lock lock_;
+
+ // The unique id of the child process, created for tracing and is expected to
+ // be valid only when tracing is enabled.
+ uint64 tracing_process_id_;
+
DISALLOW_COPY_AND_ASSIGN(ChildMemoryDumpManagerDelegateImpl);
};
diff --git a/chromium/components/tracing/child_trace_message_filter.cc b/chromium/components/tracing/child_trace_message_filter.cc
index 19fef02e106..62e13aec2c0 100644
--- a/chromium/components/tracing/child_trace_message_filter.cc
+++ b/chromium/components/tracing/child_trace_message_filter.cc
@@ -4,6 +4,7 @@
#include "components/tracing/child_trace_message_filter.h"
+#include "base/metrics/statistics_recorder.h"
#include "base/trace_event/trace_event.h"
#include "components/tracing/child_memory_dump_manager_delegate_impl.h"
#include "components/tracing/tracing_messages.h"
@@ -13,6 +14,12 @@ using base::trace_event::TraceLog;
namespace tracing {
+namespace {
+
+const int kMinTimeBetweenHistogramChangesInSeconds = 10;
+
+} // namespace
+
ChildTraceMessageFilter::ChildTraceMessageFilter(
base::SingleThreadTaskRunner* ipc_task_runner)
: sender_(NULL),
@@ -50,6 +57,8 @@ bool ChildTraceMessageFilter::OnMessageReceived(const IPC::Message& message) {
OnProcessMemoryDumpRequest)
IPC_MESSAGE_HANDLER(TracingMsg_GlobalMemoryDumpResponse,
OnGlobalMemoryDumpResponse)
+ IPC_MESSAGE_HANDLER(TracingMsg_SetUMACallback, OnSetUMACallback)
+ IPC_MESSAGE_HANDLER(TracingMsg_ClearUMACallback, OnClearUMACallback)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
@@ -226,4 +235,80 @@ void ChildTraceMessageFilter::OnGlobalMemoryDumpResponse(uint64 dump_guid,
pending_memory_dump_callback_.Run(dump_guid, success);
}
+void ChildTraceMessageFilter::OnHistogramChanged(
+ const std::string& histogram_name,
+ base::Histogram::Sample reference_lower_value,
+ base::Histogram::Sample reference_upper_value,
+ base::Histogram::Sample actual_value) {
+ if (actual_value < reference_lower_value ||
+ actual_value > reference_upper_value)
+ return;
+
+ ipc_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&ChildTraceMessageFilter::SendTriggerMessage, this,
+ histogram_name));
+}
+
+void ChildTraceMessageFilter::SendTriggerMessage(
+ const std::string& histogram_name) {
+ if (!histogram_last_changed_.is_null()) {
+ base::Time computed_next_allowed_time =
+ histogram_last_changed_ +
+ base::TimeDelta::FromSeconds(kMinTimeBetweenHistogramChangesInSeconds);
+ if (computed_next_allowed_time > base::Time::Now())
+ return;
+ }
+ histogram_last_changed_ = base::Time::Now();
+
+ if (sender_)
+ sender_->Send(new TracingHostMsg_TriggerBackgroundTrace(histogram_name));
+}
+
+void ChildTraceMessageFilter::OnSetUMACallback(
+ const std::string& histogram_name,
+ int histogram_lower_value,
+ int histogram_upper_value) {
+ histogram_last_changed_ = base::Time();
+ base::StatisticsRecorder::SetCallback(
+ histogram_name,
+ base::Bind(&ChildTraceMessageFilter::OnHistogramChanged, this,
+ histogram_name, histogram_lower_value, histogram_upper_value));
+
+ base::HistogramBase* existing_histogram =
+ base::StatisticsRecorder::FindHistogram(histogram_name);
+ if (!existing_histogram)
+ return;
+
+ scoped_ptr<base::HistogramSamples> samples =
+ existing_histogram->SnapshotSamples();
+ if (!samples)
+ return;
+
+ scoped_ptr<base::SampleCountIterator> sample_iterator = samples->Iterator();
+ if (!sample_iterator)
+ return;
+
+ while (!sample_iterator->Done()) {
+ base::HistogramBase::Sample min;
+ base::HistogramBase::Sample max;
+ base::HistogramBase::Count count;
+ sample_iterator->Get(&min, &max, &count);
+ if (min >= histogram_lower_value && max <= histogram_upper_value &&
+ count > 0) {
+ ipc_task_runner_->PostTask(
+ FROM_HERE, base::Bind(&ChildTraceMessageFilter::SendTriggerMessage,
+ this, histogram_name));
+ break;
+ }
+
+ sample_iterator->Next();
+ }
+}
+
+void ChildTraceMessageFilter::OnClearUMACallback(
+ const std::string& histogram_name) {
+ histogram_last_changed_ = base::Time();
+ base::StatisticsRecorder::ClearCallback(histogram_name);
+}
+
} // namespace tracing
diff --git a/chromium/components/tracing/child_trace_message_filter.h b/chromium/components/tracing/child_trace_message_filter.h
index f61e29429e2..124f5625f3b 100644
--- a/chromium/components/tracing/child_trace_message_filter.h
+++ b/chromium/components/tracing/child_trace_message_filter.h
@@ -7,7 +7,10 @@
#include "base/bind.h"
#include "base/memory/ref_counted_memory.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
#include "base/trace_event/memory_dump_request_args.h"
+#include "components/tracing/tracing_export.h"
#include "ipc/message_filter.h"
namespace base {
@@ -17,7 +20,7 @@ class SingleThreadTaskRunner;
namespace tracing {
// This class sends and receives trace messages on child processes.
-class ChildTraceMessageFilter : public IPC::MessageFilter {
+class TRACING_EXPORT ChildTraceMessageFilter : public IPC::MessageFilter {
public:
explicit ChildTraceMessageFilter(
base::SingleThreadTaskRunner* ipc_task_runner);
@@ -57,6 +60,15 @@ class ChildTraceMessageFilter : public IPC::MessageFilter {
void OnProcessMemoryDumpRequest(
const base::trace_event::MemoryDumpRequestArgs& args);
void OnGlobalMemoryDumpResponse(uint64 dump_guid, bool success);
+ void OnSetUMACallback(const std::string& histogram_name,
+ int histogram_lower_value,
+ int histogram_upper_value);
+ void OnClearUMACallback(const std::string& histogram_name);
+ void OnHistogramChanged(const std::string& histogram_name,
+ base::Histogram::Sample reference_lower_value,
+ base::Histogram::Sample reference_upper_value,
+ base::Histogram::Sample actual_value);
+ void SendTriggerMessage(const std::string& histogram_name);
// Callback from trace subsystem.
void OnTraceDataCollected(
@@ -79,6 +91,8 @@ class ChildTraceMessageFilter : public IPC::MessageFilter {
// callback of the outstanding memory dump request, if any.
base::trace_event::MemoryDumpCallback pending_memory_dump_callback_;
+ base::Time histogram_last_changed_;
+
DISALLOW_COPY_AND_ASSIGN(ChildTraceMessageFilter);
};
diff --git a/chromium/components/tracing/startup_tracing.cc b/chromium/components/tracing/startup_tracing.cc
deleted file mode 100644
index 321b95092a4..00000000000
--- a/chromium/components/tracing/startup_tracing.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright (c) 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 "components/tracing/startup_tracing.h"
-
-#include "base/files/file_path.h"
-#include "base/files/file_util.h"
-#include "base/path_service.h"
-#include "base/trace_event/trace_event.h"
-
-namespace tracing {
-
-namespace {
-
-// Maximum trace config file size that will be loaded, in bytes.
-const size_t kTraceConfigFileSizeLimit = 64 * 1024;
-
-// Trace config file path:
-// - Android: /data/local/.config/chrome-trace-config.json
-// - POSIX other than Android: $HOME/.config/chrome-trace-config.json
-// - Win: %USERPROFILE%/.config/chrome-trace-config.json
-#if defined(OS_ANDROID)
-const base::FilePath::CharType kAndroidTraceConfigDir[] =
- FILE_PATH_LITERAL("/data/local");
-#endif
-
-const base::FilePath::CharType kChromeConfigDir[] =
- FILE_PATH_LITERAL(".config");
-const base::FilePath::CharType kTraceConfigFileName[] =
- FILE_PATH_LITERAL("chrome-trace-config.json");
-
-base::FilePath GetTraceConfigFilePath() {
-#if defined(OS_ANDROID)
- base::FilePath path(kAndroidTraceConfigDir);
-#elif defined(OS_POSIX) || defined(OS_WIN)
- base::FilePath path;
- PathService::Get(base::DIR_HOME, &path);
-#else
- base::FilePath path;
-#endif
- path = path.Append(kChromeConfigDir);
- path = path.Append(kTraceConfigFileName);
- return path;
-}
-
-} // namespace
-
-void EnableStartupTracingIfConfigFileExists() {
- base::FilePath trace_config_file_path = GetTraceConfigFilePath();
- if (!base::PathExists(trace_config_file_path))
- return;
-
- std::string trace_config_str;
- if (!base::ReadFileToString(trace_config_file_path,
- &trace_config_str,
- kTraceConfigFileSizeLimit)) {
- return;
- }
-
- base::trace_event::TraceConfig trace_config(trace_config_str);
- base::trace_event::TraceLog::GetInstance()->SetEnabled(
- trace_config, base::trace_event::TraceLog::RECORDING_MODE);
-}
-
-} // namespace tracing
diff --git a/chromium/components/tracing/startup_tracing.h b/chromium/components/tracing/startup_tracing.h
deleted file mode 100644
index ae68f6fa654..00000000000
--- a/chromium/components/tracing/startup_tracing.h
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) 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.
-
-#ifndef COMPONENTS_TRACING_STARTUP_TRACING_H_
-#define COMPONENTS_TRACING_STARTUP_TRACING_H_
-
-namespace tracing {
-
-// Enable startup tracing according to the trace config file. If the trace
-// config file does not exist, it will do nothing. This is designed to be used
-// by Telemetry. Telemetry will stop tracing via DevTools later. To avoid
-// conflict, this should not be used when --trace-startup is enabled.
-void EnableStartupTracingIfConfigFileExists();
-
-} // namespace tracing
-
-#endif // COMPONENTS_TRACING_STARTUP_TRACING_H_
diff --git a/chromium/components/tracing/trace_config_file.cc b/chromium/components/tracing/trace_config_file.cc
new file mode 100644
index 00000000000..769d527ca8b
--- /dev/null
+++ b/chromium/components/tracing/trace_config_file.cc
@@ -0,0 +1,140 @@
+// Copyright (c) 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 "components/tracing/trace_config_file.h"
+
+#include <string>
+
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/json/json_reader.h"
+#include "base/json/json_writer.h"
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "base/values.h"
+#include "components/tracing/tracing_switches.h"
+
+namespace tracing {
+
+namespace {
+
+// Maximum trace config file size that will be loaded, in bytes.
+const size_t kTraceConfigFileSizeLimit = 64 * 1024;
+
+// Trace config file path:
+// - Android: /data/local/chrome-trace-config.json
+// - Others: specified by --trace-config-file flag.
+#if defined(OS_ANDROID)
+const base::FilePath::CharType kAndroidTraceConfigFile[] =
+ FILE_PATH_LITERAL("/data/local/chrome-trace-config.json");
+#endif
+
+const base::FilePath::CharType kDefaultResultFile[] =
+ FILE_PATH_LITERAL("chrometrace.log");
+
+// String parameters that can be used to parse the trace config file content.
+const char kTraceConfigParam[] = "trace_config";
+const char kStartupDurationParam[] = "startup_duration";
+const char kResultFileParam[] = "result_file";
+
+} // namespace
+
+TraceConfigFile* TraceConfigFile::GetInstance() {
+ return base::Singleton<TraceConfigFile,
+ base::DefaultSingletonTraits<TraceConfigFile>>::get();
+}
+
+TraceConfigFile::TraceConfigFile()
+ : is_enabled_(false),
+ trace_config_(base::trace_event::TraceConfig()),
+ startup_duration_(0),
+ result_file_(kDefaultResultFile) {
+#if defined(OS_ANDROID)
+ base::FilePath trace_config_file(kAndroidTraceConfigFile);
+#else
+ const base::CommandLine& command_line =
+ *base::CommandLine::ForCurrentProcess();
+ if (!command_line.HasSwitch(switches::kTraceConfigFile) ||
+ command_line.HasSwitch(switches::kTraceStartup) ||
+ command_line.HasSwitch(switches::kTraceShutdown)) {
+ return;
+ }
+ base::FilePath trace_config_file =
+ command_line.GetSwitchValuePath(switches::kTraceConfigFile);
+#endif
+
+ if (trace_config_file.empty()) {
+ // If the trace config file path is not specified, trace Chrome with the
+ // default configuration for 5 sec.
+ startup_duration_ = 5;
+ is_enabled_ = true;
+ return;
+ }
+
+ if (!base::PathExists(trace_config_file))
+ return;
+
+ std::string trace_config_file_content;
+ if (!base::ReadFileToString(trace_config_file,
+ &trace_config_file_content,
+ kTraceConfigFileSizeLimit)) {
+ return;
+ }
+ is_enabled_ = ParseTraceConfigFileContent(trace_config_file_content);
+}
+
+TraceConfigFile::~TraceConfigFile() {
+}
+
+bool TraceConfigFile::ParseTraceConfigFileContent(const std::string& content) {
+ scoped_ptr<base::Value> value(base::JSONReader::Read(content));
+ if (!value || !value->IsType(base::Value::TYPE_DICTIONARY))
+ return false;
+
+ scoped_ptr<base::DictionaryValue> dict(
+ static_cast<base::DictionaryValue*>(value.release()));
+
+ base::DictionaryValue* trace_config_dict = NULL;
+ if (!dict->GetDictionary(kTraceConfigParam, &trace_config_dict))
+ return false;
+
+ std::string trace_config_str;
+ base::JSONWriter::Write(*trace_config_dict, &trace_config_str);
+ trace_config_ = base::trace_event::TraceConfig(trace_config_str);
+
+ if (!dict->GetInteger(kStartupDurationParam, &startup_duration_))
+ startup_duration_ = 0;
+
+ if (startup_duration_ < 0)
+ startup_duration_ = 0;
+
+ std::string result_file_str;
+ if (dict->GetString(kResultFileParam, &result_file_str))
+ result_file_ = base::FilePath().AppendASCII(result_file_str);
+
+ return true;
+}
+
+bool TraceConfigFile::IsEnabled() const {
+ return is_enabled_;
+}
+
+base::trace_event::TraceConfig TraceConfigFile::GetTraceConfig() const {
+ DCHECK(IsEnabled());
+ return trace_config_;
+}
+
+int TraceConfigFile::GetStartupDuration() const {
+ DCHECK(IsEnabled());
+ return startup_duration_;
+}
+
+#if !defined(OS_ANDROID)
+base::FilePath TraceConfigFile::GetResultFile() const {
+ DCHECK(IsEnabled());
+ return result_file_;
+}
+#endif
+
+} // namespace tracing
diff --git a/chromium/components/tracing/trace_config_file.h b/chromium/components/tracing/trace_config_file.h
new file mode 100644
index 00000000000..863fee49b5b
--- /dev/null
+++ b/chromium/components/tracing/trace_config_file.h
@@ -0,0 +1,96 @@
+// Copyright (c) 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.
+
+#ifndef COMPONENTS_TRACING_TRACE_CONFIG_FILE_H_
+#define COMPONENTS_TRACING_TRACE_CONFIG_FILE_H_
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/trace_event/trace_config.h"
+#include "components/tracing/tracing_export.h"
+
+namespace base {
+template <typename Type> struct DefaultSingletonTraits;
+} // namespace base
+
+namespace tracing {
+
+// TraceConfigFile is a singleton that contains the configurations of tracing.
+// One can create a trace config file and use it to configure startup and/or
+// shutdown tracing.
+//
+// The trace config file should be JSON formated. One example is:
+// {
+// "trace_config": {
+// "record_mode": "record-until-full",
+// "included_categories": ["cc", "skia"]
+// },
+// "startup_duration": 5,
+// "result_file": "chrometrace.log"
+// }
+//
+// trace_config: The configuration of tracing. Please see the details in
+// base/trace_event/trace_config.h.
+//
+// startup_duration: The duration for startup tracing in terms of seconds.
+// Tracing will stop automatically after the duration. If this
+// value is not specified, the duration is 0 and one needs
+// to stop tracing by other ways, e.g., by DevTools, or get
+// the result file after shutting the browser down.
+//
+// result_file: The file that contains the trace log. The default result
+// file path is chrometrace.log. Chrome will dump the trace
+// log to this file
+// 1) after startup_duration if it is specified;
+// 2) or after browser shutdown if startup duration is 0.
+// One can also stop tracing and get the result by other ways,
+// e.g., by DevTools. In that case, the trace log will not be
+// saved to this file.
+// Notice: This is not supported on Android. The result file
+// path will be generated by tracing controller.
+//
+// The trace config file can be specified by the --trace-config-file flag on
+// most platforms except on Android, e.g., --trace-config-file=path/to/file/.
+// This flag should not be used with --trace-startup or --trace-shutdown. If
+// those two flags are used, --trace-config-file flag will be ignored. If the
+// --trace-config-file flag is used without the file path, Chrome will do
+// startup tracing with 5 seconds' startup duration.
+//
+// On Android, Chrome does not read the --trace-config-file flag, because not
+// all Chrome based browsers read customized flag, e.g., Android WebView. Chrome
+// on Android reads from a fixed file location:
+// /data/local/chrome-trace-config.json
+// If this file exists, Chrome will start tracing according to the configuration
+// specified in the file, otherwise, Chrome will not start tracing.
+class TRACING_EXPORT TraceConfigFile {
+ public:
+ static TraceConfigFile* GetInstance();
+
+ bool IsEnabled() const;
+ base::trace_event::TraceConfig GetTraceConfig() const;
+ int GetStartupDuration() const;
+#if !defined(OS_ANDROID)
+ base::FilePath GetResultFile() const;
+#endif
+
+ private:
+ // This allows constructor and destructor to be private and usable only
+ // by the Singleton class.
+ friend struct base::DefaultSingletonTraits<TraceConfigFile>;
+ TraceConfigFile();
+ ~TraceConfigFile();
+
+ bool ParseTraceConfigFileContent(const std::string& content);
+
+ bool is_enabled_;
+ base::trace_event::TraceConfig trace_config_;
+ int startup_duration_;
+ base::FilePath result_file_;
+
+ DISALLOW_COPY_AND_ASSIGN(TraceConfigFile);
+};
+
+} // namespace tracing
+
+#endif // COMPONENTS_TRACING_TRACE_CONFIG_FILE_H_
diff --git a/chromium/components/tracing/trace_config_file_unittest.cc b/chromium/components/tracing/trace_config_file_unittest.cc
new file mode 100644
index 00000000000..d62c4d44217
--- /dev/null
+++ b/chromium/components/tracing/trace_config_file_unittest.cc
@@ -0,0 +1,220 @@
+// Copyright (c) 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 "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "components/tracing/trace_config_file.h"
+#include "components/tracing/tracing_switches.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace tracing {
+
+namespace {
+
+const char kTraceConfig[] =
+ "{"
+ "\"enable_argument_filter\":true,"
+ "\"enable_sampling\":true,"
+ "\"enable_systrace\":true,"
+ "\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
+ "\"included_categories\":[\"included\","
+ "\"inc_pattern*\","
+ "\"disabled-by-default-cc\"],"
+ "\"record_mode\":\"record-continuously\","
+ "\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
+ "}";
+
+std::string GetTraceConfigFileContent(std::string trace_config,
+ std::string startup_duration,
+ std::string result_file) {
+ std::string content = "{";
+ if (!trace_config.empty())
+ content += "\"trace_config\":" + trace_config;
+
+ if (!startup_duration.empty()) {
+ if (content != "{")
+ content += ",";
+ content += "\"startup_duration\":" + startup_duration;
+ }
+
+ if (!result_file.empty()) {
+ if (content != "{")
+ content += ",";
+ content += "\"result_file\":\"" + result_file + "\"";
+ }
+
+ content += "}";
+ return content;
+}
+
+} // namespace
+
+TEST(TraceConfigFileTest, TraceStartupEnabled) {
+ base::ShadowingAtExitManager sem;
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kTraceStartup);
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kTraceConfigFile);
+
+ EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+}
+
+TEST(TraceConfigFileTest, TraceShutdownEnabled) {
+ base::ShadowingAtExitManager sem;
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kTraceShutdown);
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kTraceConfigFile);
+
+ EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+}
+
+TEST(TraceConfigFileTest, TraceConfigFileNotEnabled) {
+ base::ShadowingAtExitManager sem;
+ EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+}
+
+TEST(TraceConfigFileTest, TraceConfigFileEnabledWithoutPath) {
+ base::ShadowingAtExitManager sem;
+ base::CommandLine::ForCurrentProcess()->AppendSwitch(
+ switches::kTraceConfigFile);
+
+ ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_EQ(base::trace_event::TraceConfig().ToString(),
+ TraceConfigFile::GetInstance()->GetTraceConfig().ToString());
+ EXPECT_EQ(5, TraceConfigFile::GetInstance()->GetStartupDuration());
+ EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")),
+ TraceConfigFile::GetInstance()->GetResultFile());
+}
+
+TEST(TraceConfigFileTest, TraceConfigFileEnabledWithInvalidPath) {
+ base::ShadowingAtExitManager sem;
+ base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+ switches::kTraceConfigFile,
+ base::FilePath(FILE_PATH_LITERAL("invalid-trace-config-file-path")));
+
+ EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+}
+
+TEST(TraceConfigFileTest, ValidContent) {
+ base::ShadowingAtExitManager sem;
+ std::string content = GetTraceConfigFileContent(
+ kTraceConfig, "10", "trace_result_file.log");
+
+ base::FilePath trace_config_file;
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ ASSERT_NE(-1, base::WriteFile(
+ trace_config_file, content.c_str(), (int)content.length()));
+ base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+ switches::kTraceConfigFile, trace_config_file);
+
+ ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_STREQ(
+ kTraceConfig,
+ TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str());
+ EXPECT_EQ(10, TraceConfigFile::GetInstance()->GetStartupDuration());
+ EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("trace_result_file.log")),
+ TraceConfigFile::GetInstance()->GetResultFile());
+}
+
+TEST(TraceConfigFileTest, ValidContentWithOnlyTraceConfig) {
+ base::ShadowingAtExitManager sem;
+ std::string content = GetTraceConfigFileContent(kTraceConfig, "", "");
+
+ base::FilePath trace_config_file;
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ ASSERT_NE(-1, base::WriteFile(
+ trace_config_file, content.c_str(), (int)content.length()));
+ base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+ switches::kTraceConfigFile, trace_config_file);
+
+ ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_STREQ(
+ kTraceConfig,
+ TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str());
+ EXPECT_EQ(0, TraceConfigFile::GetInstance()->GetStartupDuration());
+ EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")),
+ TraceConfigFile::GetInstance()->GetResultFile());
+}
+
+TEST(TraceConfigFileTest, ContentWithNegtiveDuration) {
+ base::ShadowingAtExitManager sem;
+ std::string content = GetTraceConfigFileContent(kTraceConfig, "-1", "");
+
+ base::FilePath trace_config_file;
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ ASSERT_NE(-1, base::WriteFile(
+ trace_config_file, content.c_str(), (int)content.length()));
+ base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+ switches::kTraceConfigFile, trace_config_file);
+
+ ASSERT_TRUE(TraceConfigFile::GetInstance()->IsEnabled());
+ EXPECT_STREQ(
+ kTraceConfig,
+ TraceConfigFile::GetInstance()->GetTraceConfig().ToString().c_str());
+ EXPECT_EQ(0, TraceConfigFile::GetInstance()->GetStartupDuration());
+ EXPECT_EQ(base::FilePath(FILE_PATH_LITERAL("chrometrace.log")),
+ TraceConfigFile::GetInstance()->GetResultFile());
+}
+
+TEST(TraceConfigFileTest, ContentWithoutTraceConfig) {
+ base::ShadowingAtExitManager sem;
+ std::string content = GetTraceConfigFileContent(
+ "", "10", "trace_result_file.log");
+
+ base::FilePath trace_config_file;
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ ASSERT_NE(-1, base::WriteFile(
+ trace_config_file, content.c_str(), (int)content.length()));
+ base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+ switches::kTraceConfigFile, trace_config_file);
+
+ EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+}
+
+TEST(TraceConfigFileTest, InvalidContent) {
+ base::ShadowingAtExitManager sem;
+ std::string content = "invalid trace config file content";
+
+ base::FilePath trace_config_file;
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ ASSERT_NE(-1, base::WriteFile(
+ trace_config_file, content.c_str(), (int)content.length()));
+ base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+ switches::kTraceConfigFile, trace_config_file);
+
+ EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+}
+
+TEST(TraceConfigFileTest, EmptyContent) {
+ base::ShadowingAtExitManager sem;
+ base::FilePath trace_config_file;
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ ASSERT_TRUE(
+ base::CreateTemporaryFileInDir(temp_dir.path(), &trace_config_file));
+ base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
+ switches::kTraceConfigFile, trace_config_file);
+
+ EXPECT_FALSE(TraceConfigFile::GetInstance()->IsEnabled());
+}
+
+} // namespace tracing
diff --git a/chromium/components/tracing/tracing_export.h b/chromium/components/tracing/tracing_export.h
new file mode 100644
index 00000000000..ac24e303bcd
--- /dev/null
+++ b/chromium/components/tracing/tracing_export.h
@@ -0,0 +1,29 @@
+// 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.
+
+#ifndef COMPONENTS_TRACING_TRACING_EXPORT_H_
+#define COMPONENTS_TRACING_TRACING_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(TRACING_IMPLEMENTATION)
+#define TRACING_EXPORT __declspec(dllexport)
+#else
+#define TRACING_EXPORT __declspec(dllimport)
+#endif // defined(TRACING_IMPLEMENTATION)
+
+#else // defined(WIN32)
+#if defined(TRACING_IMPLEMENTATION)
+#define TRACING_EXPORT __attribute__((visibility("default")))
+#else
+#define TRACING_EXPORT
+#endif // defined(TRACING_IMPLEMENTATION)
+#endif
+
+#else // defined(COMPONENT_BUILD)
+#define TRACING_EXPORT
+#endif
+
+#endif // COMPONENTS_TRACING_TRACING_EXPORT_H_
diff --git a/chromium/components/tracing/tracing_messages.h b/chromium/components/tracing/tracing_messages.h
index 88c7834064b..cd5a2020dda 100644
--- a/chromium/components/tracing/tracing_messages.h
+++ b/chromium/components/tracing/tracing_messages.h
@@ -7,14 +7,18 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/metrics/histogram.h"
#include "base/sync_socket.h"
#include "base/trace_event/memory_dump_request_args.h"
#include "base/trace_event/trace_event_impl.h"
+#include "components/tracing/tracing_export.h"
#include "ipc/ipc_channel_handle.h"
#include "ipc/ipc_message_macros.h"
#include "ipc/ipc_message_utils.h"
#include "ipc/ipc_platform_file.h"
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT TRACING_EXPORT
#define IPC_MESSAGE_START TracingMsgStart
IPC_STRUCT_TRAITS_BEGIN(base::trace_event::TraceLogStatus)
@@ -25,8 +29,16 @@ IPC_STRUCT_TRAITS_END()
IPC_STRUCT_TRAITS_BEGIN(base::trace_event::MemoryDumpRequestArgs)
IPC_STRUCT_TRAITS_MEMBER(dump_guid)
IPC_STRUCT_TRAITS_MEMBER(dump_type)
+IPC_STRUCT_TRAITS_MEMBER(level_of_detail)
IPC_STRUCT_TRAITS_END()
+IPC_STRUCT_TRAITS_BEGIN(base::trace_event::MemoryDumpArgs)
+ IPC_STRUCT_TRAITS_MEMBER(level_of_detail)
+IPC_STRUCT_TRAITS_END()
+
+IPC_ENUM_TRAITS_MAX_VALUE(base::trace_event::MemoryDumpLevelOfDetail,
+ base::trace_event::MemoryDumpLevelOfDetail::LAST)
+
IPC_ENUM_TRAITS_MAX_VALUE(
base::trace_event::MemoryDumpType,
static_cast<int>(base::trace_event::MemoryDumpType::LAST))
@@ -75,6 +87,14 @@ IPC_MESSAGE_CONTROL2(TracingMsg_GlobalMemoryDumpResponse,
uint64 /* dump_guid */,
bool /* success */)
+IPC_MESSAGE_CONTROL3(TracingMsg_SetUMACallback,
+ std::string /* histogram_name */,
+ base::HistogramBase::Sample /* histogram_lower_value */,
+ base::HistogramBase::Sample /* histogram_uppwer_value */)
+
+IPC_MESSAGE_CONTROL1(TracingMsg_ClearUMACallback,
+ std::string /* histogram_name */)
+
// Sent everytime when a watch event is matched.
IPC_MESSAGE_CONTROL0(TracingHostMsg_WatchEventMatched)
@@ -110,3 +130,6 @@ IPC_MESSAGE_CONTROL1(TracingHostMsg_GlobalMemoryDumpRequest,
IPC_MESSAGE_CONTROL2(TracingHostMsg_ProcessMemoryDumpResponse,
uint64 /* dump_guid */,
bool /* success */)
+
+IPC_MESSAGE_CONTROL1(TracingHostMsg_TriggerBackgroundTrace,
+ std::string /* name */)
diff --git a/chromium/components/tracing/tracing_switches.cc b/chromium/components/tracing/tracing_switches.cc
new file mode 100644
index 00000000000..ba3c1b158fb
--- /dev/null
+++ b/chromium/components/tracing/tracing_switches.cc
@@ -0,0 +1,52 @@
+// 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 "components/tracing/tracing_switches.h"
+
+namespace switches {
+
+// Causes TRACE_EVENT flags to be recorded from startup.
+// This flag will be ignored if --trace-startup or --trace-shutdown is provided.
+const char kTraceConfigFile[] = "trace-config-file";
+
+// Causes TRACE_EVENT flags to be recorded beginning with shutdown. Optionally,
+// can specify the specific trace categories to include (e.g.
+// --trace-shutdown=base,net) otherwise, all events are recorded.
+// --trace-shutdown-file can be used to control where the trace log gets stored
+// to since there is otherwise no way to access the result.
+const char kTraceShutdown[] = "trace-shutdown";
+
+// If supplied, sets the file which shutdown tracing will be stored into, if
+// omitted the default will be used "chrometrace.log" in the current directory.
+// Has no effect unless --trace-shutdown is also supplied.
+// Example: --trace-shutdown --trace-shutdown-file=/tmp/trace_event.log
+const char kTraceShutdownFile[] = "trace-shutdown-file";
+
+// Causes TRACE_EVENT flags to be recorded from startup. Optionally, can
+// specify the specific trace categories to include (e.g.
+// --trace-startup=base,net) otherwise, all events are recorded. Setting this
+// flag results in the first call to BeginTracing() to receive all trace events
+// since startup. In Chrome, you may find --trace-startup-file and
+// --trace-startup-duration to control the auto-saving of the trace (not
+// supported in the base-only TraceLog component).
+const char kTraceStartup[] = "trace-startup";
+
+// Sets the time in seconds until startup tracing ends. If omitted a default of
+// 5 seconds is used. Has no effect without --trace-startup, or if
+// --startup-trace-file=none was supplied.
+const char kTraceStartupDuration[] = "trace-startup-duration";
+
+// If supplied, sets the file which startup tracing will be stored into, if
+// omitted the default will be used "chrometrace.log" in the current directory.
+// Has no effect unless --trace-startup is also supplied.
+// Example: --trace-startup --trace-startup-file=/tmp/trace_event.log
+// As a special case, can be set to 'none' - this disables automatically saving
+// the result to a file and the first manually recorded trace will then receive
+// all events since startup.
+const char kTraceStartupFile[] = "trace-startup-file";
+
+// Sets the target URL for uploading tracing data.
+const char kTraceUploadURL[] = "trace-upload-url";
+
+} // namespace switches
diff --git a/chromium/components/tracing/tracing_switches.h b/chromium/components/tracing/tracing_switches.h
new file mode 100644
index 00000000000..263a49bcf5c
--- /dev/null
+++ b/chromium/components/tracing/tracing_switches.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifndef COMPONENTS_TRACING_TRACING_SWITCHES_H_
+#define COMPONENTS_TRACING_TRACING_SWITCHES_H_
+
+#include "components/tracing/tracing_export.h"
+
+namespace switches {
+
+TRACING_EXPORT extern const char kTraceConfigFile[];
+TRACING_EXPORT extern const char kTraceShutdown[];
+TRACING_EXPORT extern const char kTraceShutdownFile[];
+TRACING_EXPORT extern const char kTraceStartup[];
+TRACING_EXPORT extern const char kTraceStartupDuration[];
+TRACING_EXPORT extern const char kTraceStartupFile[];
+TRACING_EXPORT extern const char kTraceUploadURL[];
+
+} // namespace switches
+
+#endif // COMPONENTS_TRACING_TRACING_SWITCHES_H_