summaryrefslogtreecommitdiff
path: root/chromium/components/metrics
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-04 14:17:57 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2017-01-05 10:05:06 +0000
commit39d357e3248f80abea0159765ff39554affb40db (patch)
treeaba0e6bfb76de0244bba0f5fdbd64b830dd6e621 /chromium/components/metrics
parent87778abf5a1f89266f37d1321b92a21851d8244d (diff)
downloadqtwebengine-chromium-39d357e3248f80abea0159765ff39554affb40db.tar.gz
BASELINE: Update Chromium to 55.0.2883.105
And updates ninja to 1.7.2 Change-Id: I20d43c737f82764d857ada9a55586901b18b9243 Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/components/metrics')
-rw-r--r--chromium/components/metrics/BUILD.gn121
-rw-r--r--chromium/components/metrics/DEPS2
-rw-r--r--chromium/components/metrics/call_stack_profile_collector.cc41
-rw-r--r--chromium/components/metrics/call_stack_profile_collector.h41
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider.cc127
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider.h39
-rw-r--r--chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc60
-rw-r--r--chromium/components/metrics/call_stack_profile_params.cc22
-rw-r--r--chromium/components/metrics/call_stack_profile_params.h87
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector.cc86
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector.h120
-rw-r--r--chromium/components/metrics/child_call_stack_profile_collector_unittest.cc175
-rw-r--r--chromium/components/metrics/file_metrics_provider.cc6
-rw-r--r--chromium/components/metrics/file_metrics_provider_unittest.cc44
-rw-r--r--chromium/components/metrics/leak_detector/BUILD.gn66
-rw-r--r--chromium/components/metrics/leak_detector/OWNERS5
-rw-r--r--chromium/components/metrics/leak_detector/gnu_build_id_reader.cc124
-rw-r--r--chromium/components/metrics/leak_detector/gnu_build_id_reader.h24
-rw-r--r--chromium/components/metrics/leak_detector/leak_detector.mojom40
-rw-r--r--chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.cc67
-rw-r--r--chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.h36
-rw-r--r--chromium/components/metrics/leak_detector/protobuf_to_mojo_converter_unittest.cc139
-rw-r--r--chromium/components/metrics/metrics_log.cc108
-rw-r--r--chromium/components/metrics/metrics_log.h8
-rw-r--r--chromium/components/metrics/metrics_log_manager.cc2
-rw-r--r--chromium/components/metrics/metrics_log_manager_unittest.cc46
-rw-r--r--chromium/components/metrics/metrics_log_unittest.cc27
-rw-r--r--chromium/components/metrics/metrics_pref_names.cc60
-rw-r--r--chromium/components/metrics/metrics_pref_names.h7
-rw-r--r--chromium/components/metrics/metrics_provider.cc3
-rw-r--r--chromium/components/metrics/metrics_provider.h7
-rw-r--r--chromium/components/metrics/metrics_service.cc110
-rw-r--r--chromium/components/metrics/metrics_service.h34
-rw-r--r--chromium/components/metrics/metrics_service_accessor.cc22
-rw-r--r--chromium/components/metrics/metrics_service_accessor.h31
-rw-r--r--chromium/components/metrics/metrics_service_client.h7
-rw-r--r--chromium/components/metrics/metrics_service_unittest.cc47
-rw-r--r--chromium/components/metrics/metrics_state_manager.cc17
-rw-r--r--chromium/components/metrics/net/cellular_logic_helper.cc21
-rw-r--r--chromium/components/metrics/persisted_logs.cc86
-rw-r--r--chromium/components/metrics/persisted_logs.h26
-rw-r--r--chromium/components/metrics/persisted_logs_unittest.cc12
-rw-r--r--chromium/components/metrics/profiler/profiler_metrics_provider.cc3
-rw-r--r--chromium/components/metrics/profiler/tracking_synchronizer.cc2
-rw-r--r--chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc4
-rw-r--r--chromium/components/metrics/proto/BUILD.gn2
-rw-r--r--chromium/components/metrics/proto/cast_logs.proto18
-rw-r--r--chromium/components/metrics/proto/chrome_user_metrics_extension.proto3
-rw-r--r--chromium/components/metrics/proto/execution_context.proto49
-rw-r--r--chromium/components/metrics/proto/memory_leak_report.proto43
-rw-r--r--chromium/components/metrics/proto/omnibox_event.proto11
-rw-r--r--chromium/components/metrics/proto/sampled_profile.proto11
-rw-r--r--chromium/components/metrics/proto/system_profile.proto61
-rw-r--r--chromium/components/metrics/public/cpp/BUILD.gn19
-rw-r--r--chromium/components/metrics/public/cpp/OWNERS4
-rw-r--r--chromium/components/metrics/public/cpp/call_stack_profile.typemap26
-rw-r--r--chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h384
-rw-r--r--chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc402
-rw-r--r--chromium/components/metrics/public/cpp/typemaps.gni5
-rw-r--r--chromium/components/metrics/public/interfaces/BUILD.gn26
-rw-r--r--chromium/components/metrics/public/interfaces/OWNERS4
-rw-r--r--chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom81
-rw-r--r--chromium/components/metrics/public/interfaces/call_stack_profile_collector_test.mojom33
-rw-r--r--chromium/components/metrics/serialization/serialization_utils_unittest.cc6
-rw-r--r--chromium/components/metrics/stability_metrics_helper.cc119
-rw-r--r--chromium/components/metrics/stability_metrics_helper.h5
-rw-r--r--chromium/components/metrics/stability_metrics_helper_unittest.cc48
-rw-r--r--chromium/components/metrics/system_memory_stats_recorder_win.cc2
-rw-r--r--chromium/components/metrics/test_metrics_service_client.cc7
-rw-r--r--chromium/components/metrics/test_metrics_service_client.h2
-rw-r--r--chromium/components/metrics/url_constants.cc2
71 files changed, 3080 insertions, 455 deletions
diff --git a/chromium/components/metrics/BUILD.gn b/chromium/components/metrics/BUILD.gn
index 7fc0934af87..5c10219cdec 100644
--- a/chromium/components/metrics/BUILD.gn
+++ b/chromium/components/metrics/BUILD.gn
@@ -13,8 +13,7 @@ if (metrics_use_blimp) {
defines = [ "OVERRIDE_OS_NAME_TO_BLIMP" ]
}
-# GYP version: components/metrics.gypi:metrics
-source_set("metrics") {
+static_library("metrics") {
sources = [
"call_stack_profile_metrics_provider.cc",
"call_stack_profile_metrics_provider.h",
@@ -83,6 +82,7 @@ source_set("metrics") {
"//components/metrics/proto",
]
deps = [
+ ":call_stack_profile_params",
"//base",
"//base:base_static",
"//components/prefs",
@@ -110,8 +110,7 @@ source_set("metrics") {
}
if (!is_ios) {
- # GYP version: components/metrics.gypi:metrics_gpu
- source_set("gpu") {
+ static_library("gpu") {
sources = [
"gpu/gpu_metrics_provider.cc",
"gpu/gpu_metrics_provider.h",
@@ -128,36 +127,6 @@ if (!is_ios) {
}
}
-if (is_chromeos) {
- # GYP version: components/metrics.gypi:metrics_leak_detector
- source_set("leak_detector") {
- sources = [
- "leak_detector/call_stack_manager.cc",
- "leak_detector/call_stack_manager.h",
- "leak_detector/call_stack_table.cc",
- "leak_detector/call_stack_table.h",
- "leak_detector/custom_allocator.cc",
- "leak_detector/custom_allocator.h",
- "leak_detector/leak_analyzer.cc",
- "leak_detector/leak_analyzer.h",
- "leak_detector/leak_detector.cc",
- "leak_detector/leak_detector.h",
- "leak_detector/leak_detector_impl.cc",
- "leak_detector/leak_detector_impl.h",
- "leak_detector/leak_detector_value_type.cc",
- "leak_detector/leak_detector_value_type.h",
- "leak_detector/ranked_set.cc",
- "leak_detector/ranked_set.h",
- ]
-
- deps = [
- "//base",
- "//components/metrics/proto:proto",
- ]
- }
-}
-
-# GYP version: components/metrics.gypi:metrics_net
static_library("net") {
sources = [
"net/cellular_logic_helper.cc",
@@ -195,8 +164,7 @@ static_library("net") {
}
}
-# GYP version: components/metrics.gypi:metrics_profiler
-source_set("profiler") {
+static_library("profiler") {
sources = [
"profiler/profiler_metrics_provider.cc",
"profiler/profiler_metrics_provider.h",
@@ -216,8 +184,7 @@ source_set("profiler") {
]
}
-# GYP version: components/metrics.gypi:metrics_ui
-source_set("ui") {
+static_library("ui") {
sources = [
"ui/screen_info_metrics_provider.cc",
"ui/screen_info_metrics_provider.h",
@@ -235,8 +202,7 @@ source_set("ui") {
}
if (!is_ios) {
- # GYP version: components/metrics.gypi:metrics_profiler_content
- source_set("profiler_content") {
+ static_library("profiler_content") {
sources = [
"profiler/content/content_tracking_synchronizer_delegate.cc",
"profiler/content/content_tracking_synchronizer_delegate.h",
@@ -253,8 +219,7 @@ if (!is_ios) {
]
}
} else {
- # GYP version: components/metrics.gypi:metrics_profiler_ios
- source_set("profiler_ios") {
+ static_library("profiler_ios") {
sources = [
"profiler/ios/ios_tracking_synchronizer_delegate.cc",
"profiler/ios/ios_tracking_synchronizer_delegate.h",
@@ -269,8 +234,36 @@ if (!is_ios) {
}
}
-# GYP version: components/metrics.gypi:metrics_test_support
-source_set("test_support") {
+source_set("call_stack_profile_params") {
+ sources = [
+ "call_stack_profile_params.cc",
+ "call_stack_profile_params.h",
+ ]
+}
+
+source_set("call_stacks") {
+ sources = [
+ "call_stack_profile_collector.cc",
+ "call_stack_profile_collector.h",
+ ]
+ deps = [
+ ":metrics",
+ "//components/metrics/public/interfaces:call_stack_mojo_bindings",
+ ]
+}
+
+source_set("child_call_stacks") {
+ sources = [
+ "child_call_stack_profile_collector.cc",
+ "child_call_stack_profile_collector.h",
+ ]
+ deps = [
+ "//components/metrics/public/interfaces:call_stack_mojo_bindings",
+ "//services/shell/public/cpp",
+ ]
+}
+
+static_library("test_support") {
testonly = true
sources = [
"test_enabled_state_provider.cc",
@@ -290,8 +283,7 @@ source_set("test_support") {
}
if (is_linux) {
- # GYP version: components/metrics.gypi:metrics_serialization
- source_set("serialization") {
+ static_library("serialization") {
sources = [
"serialization/metric_sample.cc",
"serialization/metric_sample.h",
@@ -304,32 +296,11 @@ if (is_linux) {
}
}
-if (is_chromeos) {
- source_set("leak_detector_unit_tests") {
- testonly = true
- sources = [
- "leak_detector/call_stack_manager_unittest.cc",
- "leak_detector/call_stack_table_unittest.cc",
- "leak_detector/leak_analyzer_unittest.cc",
- "leak_detector/leak_detector_impl_unittest.cc",
- "leak_detector/leak_detector_unittest.cc",
- "leak_detector/ranked_set_unittest.cc",
- ]
-
- deps = [
- ":leak_detector",
- "//base",
- "//components/metrics/proto:proto",
- "//content/test:test_support",
- "//testing/gtest",
- ]
- }
-}
-
source_set("unit_tests") {
testonly = true
sources = [
"call_stack_profile_metrics_provider_unittest.cc",
+ "child_call_stack_profile_collector_unittest.cc",
"cloned_install_detector_unittest.cc",
"daily_event_unittest.cc",
"data_use_tracker_unittest.cc",
@@ -351,15 +322,20 @@ source_set("unit_tests") {
]
deps = [
+ ":call_stack_profile_params",
+ ":child_call_stacks",
":metrics",
":net",
":profiler",
":test_support",
":ui",
"//base/test:test_support",
+ "//components/metrics/public/cpp:call_stack_unit_tests",
"//components/prefs:test_support",
"//components/variations",
+ "//mojo/public/cpp/bindings",
"//net:test_support",
+ "//services/shell/public/cpp:sources",
"//testing/gtest",
"//third_party/zlib:compression_utils",
"//ui/gfx/geometry",
@@ -371,6 +347,13 @@ source_set("unit_tests") {
}
if (is_chromeos) {
- deps += [ ":leak_detector_unit_tests" ]
+ deps += [ "leak_detector:unit_tests" ]
+ }
+
+ # iOS is not supported by the profiler and the ios-simulator bot chokes on
+ # these tests.
+ if (is_ios) {
+ sources -= [ "child_call_stack_profile_collector_unittest.cc" ]
+ deps -= [ "//components/metrics/public/cpp:call_stack_unit_tests" ]
}
}
diff --git a/chromium/components/metrics/DEPS b/chromium/components/metrics/DEPS
index 030dd191a6a..a7bf8dc8799 100644
--- a/chromium/components/metrics/DEPS
+++ b/chromium/components/metrics/DEPS
@@ -8,6 +8,8 @@ include_rules = [
"+components/variations",
"+components/version_info",
"+content/public/test",
+ "+mojo/public/cpp",
+ "+services/shell/public/cpp",
"+third_party/zlib/google",
"-net",
]
diff --git a/chromium/components/metrics/call_stack_profile_collector.cc b/chromium/components/metrics/call_stack_profile_collector.cc
new file mode 100644
index 00000000000..cbf466f859a
--- /dev/null
+++ b/chromium/components/metrics/call_stack_profile_collector.cc
@@ -0,0 +1,41 @@
+// Copyright 2016 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/metrics/call_stack_profile_collector.h"
+
+#include "base/memory/ptr_util.h"
+#include "components/metrics/call_stack_profile_metrics_provider.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
+
+namespace metrics {
+
+CallStackProfileCollector::CallStackProfileCollector(
+ CallStackProfileParams::Process expected_process)
+ : expected_process_(expected_process) {}
+
+CallStackProfileCollector::~CallStackProfileCollector() {}
+
+// static
+void CallStackProfileCollector::Create(
+ CallStackProfileParams::Process expected_process,
+ mojom::CallStackProfileCollectorRequest request) {
+ mojo::MakeStrongBinding(
+ base::MakeUnique<CallStackProfileCollector>(expected_process),
+ std::move(request));
+}
+
+void CallStackProfileCollector::Collect(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles) {
+ if (params.process != expected_process_)
+ return;
+
+ CallStackProfileMetricsProvider::ReceiveCompletedProfiles(params,
+ start_timestamp,
+ profiles);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/call_stack_profile_collector.h b/chromium/components/metrics/call_stack_profile_collector.h
new file mode 100644
index 00000000000..f6a2ca1ce53
--- /dev/null
+++ b/chromium/components/metrics/call_stack_profile_collector.h
@@ -0,0 +1,41 @@
+// Copyright 2016 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_METRICS_CALL_STACK_PROFILE_COLLECTOR_H_
+#define COMPONENTS_METRICS_CALL_STACK_PROFILE_COLLECTOR_H_
+
+#include "base/macros.h"
+#include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h"
+
+namespace metrics {
+
+class CallStackProfileCollector : public mojom::CallStackProfileCollector {
+ public:
+ using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
+
+ explicit CallStackProfileCollector(
+ CallStackProfileParams::Process expected_process);
+ ~CallStackProfileCollector() override;
+
+ // Create a collector to receive profiles from |expected_process|.
+ static void Create(CallStackProfileParams::Process expected_process,
+ mojom::CallStackProfileCollectorRequest request);
+
+ // mojom::CallStackProfileCollector:
+ void Collect(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles) override;
+
+ private:
+ // Profile params are validated to come from this process. Profiles with a
+ // different process declared in the params are considered untrustworthy and
+ // ignored.
+ const CallStackProfileParams::Process expected_process_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallStackProfileCollector);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CALL_STACK_PROFILE_COLLECTOR_H_
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.cc b/chromium/components/metrics/call_stack_profile_metrics_provider.cc
index 3b0b3279411..3dc55b9ea6d 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider.cc
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider.cc
@@ -38,13 +38,13 @@ namespace {
// A set of profiles and the CallStackProfileMetricsProvider state associated
// with them.
struct ProfilesState {
- ProfilesState(const CallStackProfileMetricsProvider::Params& params,
+ ProfilesState(const CallStackProfileParams& params,
const base::StackSamplingProfiler::CallStackProfiles& profiles,
base::TimeTicks start_timestamp);
// The metrics-related parameters provided to
// CallStackProfileMetricsProvider::GetProfilerCallback().
- CallStackProfileMetricsProvider::Params params;
+ CallStackProfileParams params;
// The call stack profiles collected by the profiler.
base::StackSamplingProfiler::CallStackProfiles profiles;
@@ -57,7 +57,7 @@ struct ProfilesState {
};
ProfilesState::ProfilesState(
- const CallStackProfileMetricsProvider::Params& params,
+ const CallStackProfileParams& params,
const base::StackSamplingProfiler::CallStackProfiles& profiles,
base::TimeTicks start_timestamp)
: params(params),
@@ -186,10 +186,10 @@ PendingProfiles::~PendingProfiles() {}
// Functions to process completed profiles ------------------------------------
-// Invoked on the profiler's thread. Provides the profiles to PendingProfiles to
-// append, if the collecting state allows.
-void ReceiveCompletedProfiles(
- const CallStackProfileMetricsProvider::Params& params,
+// Will be invoked on either the main thread or the profiler's thread. Provides
+// the profiles to PendingProfiles to append, if the collecting state allows.
+void ReceiveCompletedProfilesImpl(
+ const CallStackProfileParams& params,
base::TimeTicks start_timestamp,
const StackSamplingProfiler::CallStackProfiles& profiles) {
PendingProfiles::GetInstance()->CollectProfilesIfCollectionEnabled(
@@ -239,12 +239,12 @@ void CopySampleToProto(
// Transcode |profile| into |proto_profile|.
void CopyProfileToProto(
const StackSamplingProfiler::CallStackProfile& profile,
- bool preserve_sample_ordering,
+ CallStackProfileParams::SampleOrderingSpec ordering_spec,
CallStackProfile* proto_profile) {
if (profile.samples.empty())
return;
- if (preserve_sample_ordering) {
+ if (ordering_spec == CallStackProfileParams::PRESERVE_ORDER) {
// Collapse only consecutive repeated samples together.
CallStackProfile::Sample* current_sample_proto = nullptr;
for (auto it = profile.samples.begin(); it != profile.samples.end(); ++it) {
@@ -289,23 +289,77 @@ void CopyProfileToProto(
profile.sampling_period.InMilliseconds());
}
-// Translates CallStackProfileMetricsProvider's trigger to the corresponding
+// Translates CallStackProfileParams's process to the corresponding
+// execution context Process.
+Process ToExecutionContextProcess(CallStackProfileParams::Process process) {
+ switch (process) {
+ case CallStackProfileParams::UNKNOWN_PROCESS:
+ return UNKNOWN_PROCESS;
+ case CallStackProfileParams::BROWSER_PROCESS:
+ return BROWSER_PROCESS;
+ case CallStackProfileParams::RENDERER_PROCESS:
+ return RENDERER_PROCESS;
+ case CallStackProfileParams::GPU_PROCESS:
+ return GPU_PROCESS;
+ case CallStackProfileParams::UTILITY_PROCESS:
+ return UTILITY_PROCESS;
+ case CallStackProfileParams::ZYGOTE_PROCESS:
+ return ZYGOTE_PROCESS;
+ case CallStackProfileParams::SANDBOX_HELPER_PROCESS:
+ return SANDBOX_HELPER_PROCESS;
+ case CallStackProfileParams::PPAPI_PLUGIN_PROCESS:
+ return PPAPI_PLUGIN_PROCESS;
+ case CallStackProfileParams::PPAPI_BROKER_PROCESS:
+ return PPAPI_BROKER_PROCESS;
+ }
+ NOTREACHED();
+ return UNKNOWN_PROCESS;
+}
+
+// Translates CallStackProfileParams's thread to the corresponding
+// SampledProfile TriggerEvent.
+Thread ToExecutionContextThread(CallStackProfileParams::Thread thread) {
+ switch (thread) {
+ case CallStackProfileParams::UNKNOWN_THREAD:
+ return UNKNOWN_THREAD;
+ case CallStackProfileParams::UI_THREAD:
+ return UI_THREAD;
+ case CallStackProfileParams::FILE_THREAD:
+ return FILE_THREAD;
+ case CallStackProfileParams::FILE_USER_BLOCKING_THREAD:
+ return FILE_USER_BLOCKING_THREAD;
+ case CallStackProfileParams::PROCESS_LAUNCHER_THREAD:
+ return PROCESS_LAUNCHER_THREAD;
+ case CallStackProfileParams::CACHE_THREAD:
+ return CACHE_THREAD;
+ case CallStackProfileParams::IO_THREAD:
+ return IO_THREAD;
+ case CallStackProfileParams::DB_THREAD:
+ return DB_THREAD;
+ case CallStackProfileParams::GPU_MAIN_THREAD:
+ return GPU_MAIN_THREAD;
+ case CallStackProfileParams::RENDER_THREAD:
+ return RENDER_THREAD;
+ case CallStackProfileParams::UTILITY_THREAD:
+ return UTILITY_THREAD;
+ }
+ NOTREACHED();
+ return UNKNOWN_THREAD;
+}
+
+// Translates CallStackProfileParams's trigger to the corresponding
// SampledProfile TriggerEvent.
SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
- CallStackProfileMetricsProvider::Trigger trigger) {
+ CallStackProfileParams::Trigger trigger) {
switch (trigger) {
- case CallStackProfileMetricsProvider::UNKNOWN:
+ case CallStackProfileParams::UNKNOWN:
return SampledProfile::UNKNOWN_TRIGGER_EVENT;
- break;
- case CallStackProfileMetricsProvider::PROCESS_STARTUP:
+ case CallStackProfileParams::PROCESS_STARTUP:
return SampledProfile::PROCESS_STARTUP;
- break;
- case CallStackProfileMetricsProvider::JANKY_TASK:
+ case CallStackProfileParams::JANKY_TASK:
return SampledProfile::JANKY_TASK;
- break;
- case CallStackProfileMetricsProvider::THREAD_HUNG:
+ case CallStackProfileParams::THREAD_HUNG:
return SampledProfile::THREAD_HUNG;
- break;
}
NOTREACHED();
return SampledProfile::UNKNOWN_TRIGGER_EVENT;
@@ -313,20 +367,6 @@ SampledProfile::TriggerEvent ToSampledProfileTriggerEvent(
} // namespace
-// CallStackProfileMetricsProvider::Params ------------------------------------
-
-CallStackProfileMetricsProvider::Params::Params(
- CallStackProfileMetricsProvider::Trigger trigger)
- : Params(trigger, false) {
-}
-
-CallStackProfileMetricsProvider::Params::Params(
- CallStackProfileMetricsProvider::Trigger trigger,
- bool preserve_sample_ordering)
- : trigger(trigger),
- preserve_sample_ordering(preserve_sample_ordering) {
-}
-
// CallStackProfileMetricsProvider --------------------------------------------
const char CallStackProfileMetricsProvider::kFieldTrialName[] =
@@ -342,14 +382,24 @@ CallStackProfileMetricsProvider::~CallStackProfileMetricsProvider() {
// This function can be invoked on an abitrary thread.
base::StackSamplingProfiler::CompletedCallback
-CallStackProfileMetricsProvider::GetProfilerCallback(const Params& params) {
+CallStackProfileMetricsProvider::GetProfilerCallback(
+ const CallStackProfileParams& params) {
// Ignore the profiles if the collection is disabled. If the collection state
// changes while collecting, this will be detected by the callback and
// profiles will be ignored at that point.
if (!PendingProfiles::GetInstance()->IsCollectionEnabled())
return base::Bind(&IgnoreCompletedProfiles);
- return base::Bind(&ReceiveCompletedProfiles, params, base::TimeTicks::Now());
+ return base::Bind(&ReceiveCompletedProfilesImpl, params,
+ base::TimeTicks::Now());
+}
+
+// static
+void CallStackProfileMetricsProvider::ReceiveCompletedProfiles(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles) {
+ ReceiveCompletedProfilesImpl(params, start_timestamp, profiles);
}
void CallStackProfileMetricsProvider::OnRecordingEnabled() {
@@ -371,10 +421,13 @@ void CallStackProfileMetricsProvider::ProvideGeneralMetrics(
for (const StackSamplingProfiler::CallStackProfile& profile :
profiles_state.profiles) {
SampledProfile* sampled_profile = uma_proto->add_sampled_profile();
+ sampled_profile->set_process(ToExecutionContextProcess(
+ profiles_state.params.process));
+ sampled_profile->set_thread(ToExecutionContextThread(
+ profiles_state.params.thread));
sampled_profile->set_trigger_event(ToSampledProfileTriggerEvent(
profiles_state.params.trigger));
- CopyProfileToProto(profile,
- profiles_state.params.preserve_sample_ordering,
+ CopyProfileToProto(profile, profiles_state.params.ordering_spec,
sampled_profile->mutable_call_stack_profile());
}
}
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider.h b/chromium/components/metrics/call_stack_profile_metrics_provider.h
index 746b82928ed..d26000be087 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider.h
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/profiler/stack_sampling_profiler.h"
+#include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/metrics_provider.h"
namespace metrics {
@@ -18,34 +19,6 @@ class ChromeUserMetricsExtension;
// Performs metrics logging for the stack sampling profiler.
class CallStackProfileMetricsProvider : public MetricsProvider {
public:
- // The event that triggered the profile collection.
- // This enum should be kept in sync with content/common/profiled_stack_state.h
- enum Trigger {
- UNKNOWN,
- PROCESS_STARTUP,
- JANKY_TASK,
- THREAD_HUNG,
- TRIGGER_LAST = THREAD_HUNG
- };
-
- // Parameters to pass back to the metrics provider.
- struct Params {
- explicit Params(Trigger trigger);
- Params(Trigger trigger, bool preserve_sample_ordering);
-
- // The triggering event.
- Trigger trigger;
-
- // True if sample ordering is important and should be preserved when the
- // associated profiles are compressed. This should only be set to true if
- // the intended use of the requires that the sequence of call stacks within
- // a particular profile be preserved. The default value of false provides
- // better compression of the encoded profile and is sufficient for the
- // typical use case of recording profiles for stack frequency analysis in
- // aggregate.
- bool preserve_sample_ordering;
- };
-
CallStackProfileMetricsProvider();
~CallStackProfileMetricsProvider() override;
@@ -54,7 +27,15 @@ class CallStackProfileMetricsProvider : public MetricsProvider {
// StackSamplingProfiler, and should not be reused between
// StackSamplingProfilers. This function may be called on any thread.
static base::StackSamplingProfiler::CompletedCallback GetProfilerCallback(
- const Params& params);
+ const CallStackProfileParams& params);
+
+ // Provides completed stack profiles to the metrics provider. Intended for use
+ // when receiving profiles over IPC. In-process StackSamplingProfiler users
+ // should use GetProfilerCallback() instead.
+ static void ReceiveCompletedProfiles(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles);
// MetricsProvider:
void OnRecordingEnabled() override;
diff --git a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
index e361137e168..e5dfb9ad9f6 100644
--- a/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/call_stack_profile_metrics_provider_unittest.cc
@@ -13,6 +13,7 @@
#include "base/run_loop.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
+#include "components/metrics/call_stack_profile_params.h"
#include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
#include "components/variations/entropy_provider.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -26,8 +27,6 @@ using Sample = StackSamplingProfiler::Sample;
namespace metrics {
-using Params = CallStackProfileMetricsProvider::Params;
-
// This test fixture enables the field trial that
// CallStackProfileMetricsProvider depends on to report profiles.
class CallStackProfileMetricsProviderTest : public testing::Test {
@@ -43,7 +42,8 @@ class CallStackProfileMetricsProviderTest : public testing::Test {
~CallStackProfileMetricsProviderTest() override {}
// Utility function to append profiles to the metrics provider.
- void AppendProfiles(const Params& params, const Profiles& profiles) {
+ void AppendProfiles(const CallStackProfileParams& params,
+ const Profiles& profiles) {
CallStackProfileMetricsProvider::GetProfilerCallback(params).Run(profiles);
}
@@ -205,7 +205,10 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
profiles);
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -266,6 +269,10 @@ TEST_F(CallStackProfileMetricsProviderTest, MultipleProfiles) {
ASSERT_TRUE(call_stack_profile.has_sampling_period_ms());
EXPECT_EQ(profile_sampling_periods[i].InMilliseconds(),
call_stack_profile.sampling_period_ms());
+ ASSERT_TRUE(sampled_profile.has_process());
+ EXPECT_EQ(BROWSER_PROCESS, sampled_profile.process());
+ ASSERT_TRUE(sampled_profile.has_thread());
+ EXPECT_EQ(UI_THREAD, sampled_profile.thread());
ASSERT_TRUE(sampled_profile.has_trigger_event());
EXPECT_EQ(SampledProfile::PROCESS_STARTUP, sampled_profile.trigger_event());
}
@@ -313,7 +320,10 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksUnordered) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -392,7 +402,10 @@ TEST_F(CallStackProfileMetricsProviderTest, RepeatedStacksOrdered) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
- AppendProfiles(Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, true),
+ AppendProfiles(CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::PRESERVE_ORDER),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -444,7 +457,10 @@ TEST_F(CallStackProfileMetricsProviderTest, UnknownModule) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingEnabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -481,7 +497,10 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesProvidedOnlyOnce) {
provider.OnRecordingEnabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -508,7 +527,10 @@ TEST_F(CallStackProfileMetricsProviderTest,
profile.sampling_period = base::TimeDelta::FromMilliseconds(10);
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
CallStackProfileMetricsProvider provider;
@@ -532,7 +554,10 @@ TEST_F(CallStackProfileMetricsProviderTest, ProfilesNotProvidedWhileDisabled) {
CallStackProfileMetricsProvider provider;
provider.OnRecordingDisabled();
AppendProfiles(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false),
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE),
std::vector<Profile>(1, profile));
ChromeUserMetricsExtension uma_proto;
provider.ProvideGeneralMetrics(&uma_proto);
@@ -555,7 +580,10 @@ TEST_F(CallStackProfileMetricsProviderTest,
provider.OnRecordingEnabled();
base::StackSamplingProfiler::CompletedCallback callback =
CallStackProfileMetricsProvider::GetProfilerCallback(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false));
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE));
provider.OnRecordingDisabled();
callback.Run(std::vector<Profile>(1, profile));
@@ -580,7 +608,10 @@ TEST_F(CallStackProfileMetricsProviderTest,
provider.OnRecordingEnabled();
base::StackSamplingProfiler::CompletedCallback callback =
CallStackProfileMetricsProvider::GetProfilerCallback(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false));
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE));
provider.OnRecordingDisabled();
provider.OnRecordingEnabled();
@@ -606,7 +637,10 @@ TEST_F(CallStackProfileMetricsProviderTest,
provider.OnRecordingDisabled();
base::StackSamplingProfiler::CompletedCallback callback =
CallStackProfileMetricsProvider::GetProfilerCallback(
- Params(CallStackProfileMetricsProvider::PROCESS_STARTUP, false));
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::MAY_SHUFFLE));
provider.OnRecordingEnabled();
callback.Run(std::vector<Profile>(1, profile));
diff --git a/chromium/components/metrics/call_stack_profile_params.cc b/chromium/components/metrics/call_stack_profile_params.cc
new file mode 100644
index 00000000000..e937283616c
--- /dev/null
+++ b/chromium/components/metrics/call_stack_profile_params.cc
@@ -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.
+
+#include "components/metrics/call_stack_profile_params.h"
+
+namespace metrics {
+
+CallStackProfileParams::CallStackProfileParams()
+ : CallStackProfileParams(UNKNOWN_PROCESS, UNKNOWN_THREAD, UNKNOWN) {}
+
+CallStackProfileParams::CallStackProfileParams(Process process, Thread thread,
+ Trigger trigger)
+ : CallStackProfileParams(process, thread, trigger, MAY_SHUFFLE) {}
+
+CallStackProfileParams::CallStackProfileParams(Process process, Thread thread,
+ Trigger trigger,
+ SampleOrderingSpec ordering_spec)
+ : process(process), thread(thread), trigger(trigger),
+ ordering_spec(ordering_spec) {}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/call_stack_profile_params.h b/chromium/components/metrics/call_stack_profile_params.h
new file mode 100644
index 00000000000..4dd7cd4fef2
--- /dev/null
+++ b/chromium/components/metrics/call_stack_profile_params.h
@@ -0,0 +1,87 @@
+// Copyright 2016 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_METRICS_CALL_STACK_PROFILE_PARAMS_H_
+#define COMPONENTS_METRICS_CALL_STACK_PROFILE_PARAMS_H_
+
+namespace metrics {
+
+// Parameters to pass back to the metrics provider.
+struct CallStackProfileParams {
+ // The process in which the collection occurred.
+ enum Process {
+ UNKNOWN_PROCESS,
+ BROWSER_PROCESS,
+ RENDERER_PROCESS,
+ GPU_PROCESS,
+ UTILITY_PROCESS,
+ ZYGOTE_PROCESS,
+ SANDBOX_HELPER_PROCESS,
+ PPAPI_PLUGIN_PROCESS,
+ PPAPI_BROKER_PROCESS
+ };
+
+ // The thread from which the collection occurred.
+ enum Thread {
+ UNKNOWN_THREAD,
+
+ // Browser process threads, some of which occur in other processes as well.
+ UI_THREAD,
+ FILE_THREAD,
+ FILE_USER_BLOCKING_THREAD,
+ PROCESS_LAUNCHER_THREAD,
+ CACHE_THREAD,
+ IO_THREAD,
+ DB_THREAD,
+
+ // GPU process thread.
+ GPU_MAIN_THREAD,
+
+ // Renderer process threads.
+ RENDER_THREAD,
+ UTILITY_THREAD
+ };
+
+ // The event that triggered the profile collection.
+ enum Trigger {
+ UNKNOWN,
+ PROCESS_STARTUP,
+ JANKY_TASK,
+ THREAD_HUNG,
+ TRIGGER_LAST = THREAD_HUNG
+ };
+
+ // Allows the caller to specify whether sample ordering is
+ // important. MAY_SHUFFLE should always be used to enable better compression,
+ // unless the use case needs order to be preserved for a specific reason.
+ enum SampleOrderingSpec {
+ // The provider may shuffle the sample order to improve compression.
+ MAY_SHUFFLE,
+ // The provider will not change the sample order.
+ PRESERVE_ORDER
+ };
+
+ // The default constructor is required for mojo and should not be used
+ // otherwise. A valid trigger should always be specified.
+ CallStackProfileParams();
+ CallStackProfileParams(Process process, Thread thread, Trigger trigger);
+ CallStackProfileParams(Process process, Thread thread, Trigger trigger,
+ SampleOrderingSpec ordering_spec);
+
+ // The collection process.
+ Process process;
+
+ // The collection thread.
+ Thread thread;
+
+ // The triggering event.
+ Trigger trigger;
+
+ // Whether to preserve sample ordering.
+ SampleOrderingSpec ordering_spec;
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CALL_STACK_PROFILE_PARAMS_H_
diff --git a/chromium/components/metrics/child_call_stack_profile_collector.cc b/chromium/components/metrics/child_call_stack_profile_collector.cc
new file mode 100644
index 00000000000..9c62af85568
--- /dev/null
+++ b/chromium/components/metrics/child_call_stack_profile_collector.cc
@@ -0,0 +1,86 @@
+// Copyright 2016 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/metrics/child_call_stack_profile_collector.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "services/shell/public/cpp/interface_provider.h"
+
+namespace metrics {
+
+ChildCallStackProfileCollector::ProfilesState::ProfilesState() = default;
+ChildCallStackProfileCollector::ProfilesState::ProfilesState(
+ const ProfilesState&) = default;
+
+ChildCallStackProfileCollector::ProfilesState::ProfilesState(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles)
+ : params(params), start_timestamp(start_timestamp), profiles(profiles) {}
+
+ChildCallStackProfileCollector::ProfilesState::~ProfilesState() = default;
+
+ChildCallStackProfileCollector::ChildCallStackProfileCollector() {}
+
+ChildCallStackProfileCollector::~ChildCallStackProfileCollector() {}
+
+base::StackSamplingProfiler::CompletedCallback
+ChildCallStackProfileCollector::GetProfilerCallback(
+ const CallStackProfileParams& params) {
+ return base::Bind(&ChildCallStackProfileCollector::Collect,
+ // This class has lazy instance lifetime.
+ base::Unretained(this), params,
+ base::TimeTicks::Now());
+}
+
+void ChildCallStackProfileCollector::SetParentProfileCollector(
+ metrics::mojom::CallStackProfileCollectorPtr parent_collector) {
+ base::AutoLock alock(lock_);
+ // This function should only invoked once, during the mode of operation when
+ // retaining profiles after construction.
+ DCHECK(retain_profiles_);
+ retain_profiles_ = false;
+ task_runner_ = base::ThreadTaskRunnerHandle::Get();
+ parent_collector_ = std::move(parent_collector);
+ if (parent_collector_) {
+ for (const ProfilesState& state : profiles_) {
+ parent_collector_->Collect(state.params, state.start_timestamp,
+ state.profiles);
+ }
+ }
+ profiles_.clear();
+}
+
+void ChildCallStackProfileCollector::Collect(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles) {
+ base::AutoLock alock(lock_);
+ if (task_runner_ &&
+ // The profiler thread does not have a task runner. Attempting to
+ // invoke Get() on it results in a DCHECK.
+ (!base::ThreadTaskRunnerHandle::IsSet() ||
+ base::ThreadTaskRunnerHandle::Get() != task_runner_)) {
+ // Post back to the thread that owns the the parent interface.
+ task_runner_->PostTask(FROM_HERE, base::Bind(
+ &ChildCallStackProfileCollector::Collect,
+ // This class has lazy instance lifetime.
+ base::Unretained(this),
+ params,
+ start_timestamp,
+ profiles));
+ return;
+ }
+
+ if (parent_collector_) {
+ parent_collector_->Collect(params, start_timestamp, profiles);
+ } else if (retain_profiles_) {
+ profiles_.push_back(ProfilesState(params, start_timestamp, profiles));
+ }
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/child_call_stack_profile_collector.h b/chromium/components/metrics/child_call_stack_profile_collector.h
new file mode 100644
index 00000000000..adc356d110f
--- /dev/null
+++ b/chromium/components/metrics/child_call_stack_profile_collector.h
@@ -0,0 +1,120 @@
+// Copyright 2016 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_METRICS_CHILD_CALL_STACK_PROFILE_COLLECTOR_H_
+#define COMPONENTS_METRICS_CHILD_CALL_STACK_PROFILE_COLLECTOR_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/synchronization/lock.h"
+#include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h"
+
+namespace shell {
+class InterfaceProvider;
+}
+
+namespace metrics {
+
+// ChildCallStackProfileCollector collects stacks at startup, caching them
+// internally until a CallStackProfileCollector interface is available. If a
+// CallStackProfileCollector is provided via the InterfaceProvider supplied to
+// SetParentProfileCollector, the cached stacks are sent via that interface. All
+// future stacks received via callbacks supplied by GetProfilerCallback are sent
+// via that interface as well.
+//
+// If no CallStackProfileCollector is provided via InterfaceProvider, any cached
+// stacks and all future stacks received via callbacks supplied by
+// GetProfilerCallback are flushed. In typical usage this should not happen
+// because the browser is expected to always supply a CallStackProfileCollector.
+//
+// This class is only necessary if a CallStackProfileCollector is not available
+// at the time the profiler is created. Otherwise the CallStackProfileCollector
+// can be used directly.
+//
+// To use, create as a leaky lazy instance:
+//
+// base::LazyInstance<metrics::ChildCallStackProfileCollector>::Leaky
+// g_call_stack_profile_collector = LAZY_INSTANCE_INITIALIZER;
+//
+// Then, invoke CreateCompletedCallback() to generate the CompletedCallback to
+// pass when creating the StackSamplingProfiler.
+//
+// When the mojo InterfaceProvider becomes available, provide it via
+// SetParentProfileCollector().
+class ChildCallStackProfileCollector {
+ public:
+ ChildCallStackProfileCollector();
+ ~ChildCallStackProfileCollector();
+
+ // Get a callback for use with StackSamplingProfiler that provides completed
+ // profiles to this object. The callback should be immediately passed to the
+ // StackSamplingProfiler, and should not be reused between
+ // StackSamplingProfilers. This function may be called on any thread.
+ base::StackSamplingProfiler::CompletedCallback GetProfilerCallback(
+ const CallStackProfileParams& params);
+
+ // Sets the CallStackProfileCollector interface from |parent_collector|. This
+ // function MUST be invoked exactly once, regardless of whether
+ // |parent_collector| is null, as it flushes pending data in either case.
+ void SetParentProfileCollector(
+ metrics::mojom::CallStackProfileCollectorPtr parent_collector);
+
+ private:
+ friend class ChildCallStackProfileCollectorTest;
+
+ // Bundles together a set of collected profiles and the collection state for
+ // storage, pending availability of the parent mojo interface.
+ struct ProfilesState {
+ ProfilesState();
+ ProfilesState(const ProfilesState&);
+ ProfilesState(
+ const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles);
+ ~ProfilesState();
+
+ CallStackProfileParams params;
+ base::TimeTicks start_timestamp;
+
+ // The sampled profiles.
+ base::StackSamplingProfiler::CallStackProfiles profiles;
+ };
+
+ using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
+
+ void Collect(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles);
+
+ // This object may be accessed on any thread, including the profiler
+ // thread. The expected use case for the object is to be created and have
+ // GetProfilerCallback before the message loop starts, which prevents the use
+ // of PostTask and the like for inter-thread communication.
+ base::Lock lock_;
+
+ // Whether to retain profiles when the interface is not set. Remains true
+ // until the invocation of SetParentProfileCollector(), at which point it is
+ // false for the rest of the object lifetime.
+ bool retain_profiles_ = true;
+
+ // The task runner associated with the parent interface.
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
+
+ // The interface to use to collect the stack profiles provided to this
+ // object. Initially null until SetParentProfileCollector() is invoked, at
+ // which point it may either become set or remain null. If set, stacks are
+ // collected via the interface, otherwise they are ignored.
+ mojom::CallStackProfileCollectorPtr parent_collector_;
+
+ // Profiles being cached by this object, pending a parent interface to be
+ // supplied.
+ std::vector<ProfilesState> profiles_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildCallStackProfileCollector);
+};
+
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_CHILD_CALL_STACK_PROFILE_COLLECTOR_H_
diff --git a/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc b/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc
new file mode 100644
index 00000000000..556124feed9
--- /dev/null
+++ b/chromium/components/metrics/child_call_stack_profile_collector_unittest.cc
@@ -0,0 +1,175 @@
+// Copyright 2016 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/metrics/child_call_stack_profile_collector.h"
+
+#include <memory>
+#include <vector>
+
+#include "base/bind.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "components/metrics/call_stack_profile_params.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/interface_request.h"
+#include "services/shell/public/cpp/interface_provider.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+namespace {
+
+
+} // namespace
+
+class ChildCallStackProfileCollectorTest : public testing::Test {
+ protected:
+ class Receiver : public mojom::CallStackProfileCollector {
+ public:
+ using CallStackProfile = base::StackSamplingProfiler::CallStackProfile;
+
+ Receiver(mojom::CallStackProfileCollectorRequest request)
+ : binding_(this, std::move(request)) {}
+ ~Receiver() override {}
+
+ void Collect(const CallStackProfileParams& params,
+ base::TimeTicks start_timestamp,
+ const std::vector<CallStackProfile>& profiles) override {
+ this->profiles.push_back(ChildCallStackProfileCollector::ProfilesState(
+ params,
+ start_timestamp,
+ profiles));
+ }
+
+ std::vector<ChildCallStackProfileCollector::ProfilesState> profiles;
+
+ private:
+ mojo::Binding<mojom::CallStackProfileCollector> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(Receiver);
+ };
+
+ ChildCallStackProfileCollectorTest()
+ : receiver_impl_(new Receiver(GetProxy(&receiver_))) {}
+
+ void CollectProfiles(
+ const CallStackProfileParams& params,
+ const base::StackSamplingProfiler::CallStackProfiles& profiles) {
+ child_collector_.GetProfilerCallback(params).Run(profiles);
+ }
+
+ const std::vector<ChildCallStackProfileCollector::ProfilesState>&
+ profiles() const {
+ return child_collector_.profiles_;
+ }
+
+ base::MessageLoop loop_;
+ mojom::CallStackProfileCollectorPtr receiver_;
+ std::unique_ptr<Receiver> receiver_impl_;
+ ChildCallStackProfileCollector child_collector_;
+
+ DISALLOW_COPY_AND_ASSIGN(ChildCallStackProfileCollectorTest);
+};
+
+// Test the behavior when an interface is provided.
+TEST_F(ChildCallStackProfileCollectorTest, InterfaceProvided) {
+ EXPECT_EQ(0u, profiles().size());
+
+ // Add profiles before providing the interface.
+ CollectProfiles(
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::JANKY_TASK,
+ CallStackProfileParams::PRESERVE_ORDER),
+ { base::StackSamplingProfiler::CallStackProfile(),
+ base::StackSamplingProfiler::CallStackProfile() });
+ ASSERT_EQ(1u, profiles().size());
+ EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS,
+ profiles()[0].params.process);
+ EXPECT_EQ(CallStackProfileParams::UI_THREAD, profiles()[0].params.thread);
+ EXPECT_EQ(CallStackProfileParams::JANKY_TASK, profiles()[0].params.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
+ profiles()[0].params.ordering_spec);
+ base::TimeTicks start_timestamp = profiles()[0].start_timestamp;
+ EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
+ base::TimeTicks::Now() - start_timestamp);
+ EXPECT_EQ(2u, profiles()[0].profiles.size());
+
+ // Set the interface. The profiles should be passed to it.
+ child_collector_.SetParentProfileCollector(std::move(receiver_));
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, profiles().size());
+ ASSERT_EQ(1u, receiver_impl_->profiles.size());
+ EXPECT_EQ(CallStackProfileParams::JANKY_TASK,
+ receiver_impl_->profiles[0].params.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
+ receiver_impl_->profiles[0].params.ordering_spec);
+ EXPECT_EQ(start_timestamp, receiver_impl_->profiles[0].start_timestamp);
+ EXPECT_EQ(2u, receiver_impl_->profiles[0].profiles.size());
+
+ // Add profiles after providing the interface. They should also be passed to
+ // it.
+ receiver_impl_->profiles.clear();
+ CollectProfiles(
+ CallStackProfileParams(CallStackProfileParams::GPU_PROCESS,
+ CallStackProfileParams::GPU_MAIN_THREAD,
+ CallStackProfileParams::THREAD_HUNG,
+ CallStackProfileParams::PRESERVE_ORDER),
+ { base::StackSamplingProfiler::CallStackProfile() });
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, profiles().size());
+ ASSERT_EQ(1u, receiver_impl_->profiles.size());
+ EXPECT_EQ(CallStackProfileParams::GPU_PROCESS,
+ receiver_impl_->profiles[0].params.process);
+ EXPECT_EQ(CallStackProfileParams::GPU_MAIN_THREAD,
+ receiver_impl_->profiles[0].params.thread);
+ EXPECT_EQ(CallStackProfileParams::THREAD_HUNG,
+ receiver_impl_->profiles[0].params.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
+ receiver_impl_->profiles[0].params.ordering_spec);
+ EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
+ (base::TimeTicks::Now() -
+ receiver_impl_->profiles[0].start_timestamp));
+ EXPECT_EQ(1u, receiver_impl_->profiles[0].profiles.size());
+}
+
+TEST_F(ChildCallStackProfileCollectorTest, InterfaceNotProvided) {
+ EXPECT_EQ(0u, profiles().size());
+
+ // Add profiles before providing a null interface.
+ CollectProfiles(
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::JANKY_TASK,
+ CallStackProfileParams::PRESERVE_ORDER),
+ { base::StackSamplingProfiler::CallStackProfile(),
+ base::StackSamplingProfiler::CallStackProfile() });
+ ASSERT_EQ(1u, profiles().size());
+ EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS,
+ profiles()[0].params.process);
+ EXPECT_EQ(CallStackProfileParams::UI_THREAD, profiles()[0].params.thread);
+ EXPECT_EQ(CallStackProfileParams::JANKY_TASK, profiles()[0].params.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER,
+ profiles()[0].params.ordering_spec);
+ EXPECT_GE(base::TimeDelta::FromMilliseconds(10),
+ base::TimeTicks::Now() - profiles()[0].start_timestamp);
+ EXPECT_EQ(2u, profiles()[0].profiles.size());
+
+ // Set the null interface. The profiles should be flushed.
+ child_collector_.SetParentProfileCollector(
+ mojom::CallStackProfileCollectorPtr());
+ base::RunLoop().RunUntilIdle();
+ EXPECT_EQ(0u, profiles().size());
+
+ // Add profiles after providing a null interface. They should also be flushed.
+ CollectProfiles(
+ CallStackProfileParams(CallStackProfileParams::GPU_PROCESS,
+ CallStackProfileParams::GPU_MAIN_THREAD,
+ CallStackProfileParams::THREAD_HUNG,
+ CallStackProfileParams::PRESERVE_ORDER),
+ { base::StackSamplingProfiler::CallStackProfile() });
+ EXPECT_EQ(0u, profiles().size());
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/file_metrics_provider.cc b/chromium/components/metrics/file_metrics_provider.cc
index 2d331d63bfa..aa81a0cd1f0 100644
--- a/chromium/components/metrics/file_metrics_provider.cc
+++ b/chromium/components/metrics/file_metrics_provider.cc
@@ -325,8 +325,8 @@ FileMetricsProvider::AccessResult FileMetricsProvider::CheckAndMapMetricSource(
// Create an allocator for the mapped file. Ownership passes to the allocator.
source->allocator.reset(new base::PersistentHistogramAllocator(
- base::WrapUnique(new base::FilePersistentMemoryAllocator(
- std::move(mapped), 0, 0, base::StringPiece(), read_only))));
+ base::MakeUnique<base::FilePersistentMemoryAllocator>(
+ std::move(mapped), 0, 0, base::StringPiece(), read_only)));
return ACCESS_RESULT_SUCCESS;
}
@@ -372,7 +372,7 @@ void FileMetricsProvider::RecordHistogramSnapshotsFromSource(
std::unique_ptr<base::HistogramBase> histogram = histogram_iter.GetNext();
if (!histogram)
break;
- snapshot_manager->PrepareFinalDeltaTakingOwnership(std::move(histogram));
+ snapshot_manager->PrepareFinalDelta(histogram.get());
++histogram_count;
}
diff --git a/chromium/components/metrics/file_metrics_provider_unittest.cc b/chromium/components/metrics/file_metrics_provider_unittest.cc
index d1d340b9f95..11977099c3e 100644
--- a/chromium/components/metrics/file_metrics_provider_unittest.cc
+++ b/chromium/components/metrics/file_metrics_provider_unittest.cc
@@ -95,9 +95,9 @@ class FileMetricsProviderTest : public testing::TestWithParam<bool> {
}
TestingPrefServiceSimple* prefs() { return prefs_.get(); }
- base::FilePath temp_dir() { return temp_dir_.path(); }
+ base::FilePath temp_dir() { return temp_dir_.GetPath(); }
base::FilePath metrics_file() {
- return temp_dir_.path().AppendASCII(kMetricsFilename);
+ return temp_dir_.GetPath().AppendASCII(kMetricsFilename);
}
FileMetricsProvider* provider() {
@@ -286,36 +286,40 @@ TEST_P(FileMetricsProviderTest, AccessDirectory) {
// ensure that each file has a later timestamp on disk than the previous one.
base::ScopedTempDir metrics_files;
EXPECT_TRUE(metrics_files.CreateUniqueTempDir());
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII(".foo.pma"),
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII(".foo.pma"),
allocator, base_time);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("_bar.pma"),
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("_bar.pma"),
allocator, base_time);
histogram = base::Histogram::FactoryGet("h1", 1, 100, 10, 0);
histogram->Add(1);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("a1.pma"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("a1.pma"),
+ allocator,
base_time + base::TimeDelta::FromMinutes(1));
histogram = base::Histogram::FactoryGet("h2", 1, 100, 10, 0);
histogram->Add(2);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("c2.pma"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("c2.pma"),
+ allocator,
base_time + base::TimeDelta::FromMinutes(2));
histogram = base::Histogram::FactoryGet("h3", 1, 100, 10, 0);
histogram->Add(3);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("b3.pma"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("b3.pma"),
+ allocator,
base_time + base::TimeDelta::FromMinutes(3));
histogram = base::Histogram::FactoryGet("h4", 1, 100, 10, 0);
histogram->Add(3);
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("d4.pma"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("d4.pma"),
+ allocator,
base_time + base::TimeDelta::FromMinutes(4));
- base::TouchFile(metrics_files.path().AppendASCII("b3.pma"),
+ base::TouchFile(metrics_files.GetPath().AppendASCII("b3.pma"),
base_time + base::TimeDelta::FromMinutes(5),
base_time + base::TimeDelta::FromMinutes(5));
- WriteMetricsFileAtTime(metrics_files.path().AppendASCII("baz"), allocator,
+ WriteMetricsFileAtTime(metrics_files.GetPath().AppendASCII("baz"), allocator,
base_time + base::TimeDelta::FromMinutes(6));
// The global allocator has to be detached here so that no metrics created
@@ -324,7 +328,7 @@ TEST_P(FileMetricsProviderTest, AccessDirectory) {
base::GlobalHistogramAllocator::ReleaseForTesting();
// Register the file and allow the "checker" task to run.
- provider()->RegisterSource(metrics_files.path(),
+ provider()->RegisterSource(metrics_files.GetPath(),
FileMetricsProvider::SOURCE_HISTOGRAMS_ATOMIC_DIR,
FileMetricsProvider::ASSOCIATE_CURRENT_RUN,
kMetricsName);
@@ -339,13 +343,15 @@ TEST_P(FileMetricsProviderTest, AccessDirectory) {
EXPECT_EQ(expect_order[i], GetSnapshotHistogramCount()) << i;
}
- EXPECT_FALSE(base::PathExists(metrics_files.path().AppendASCII("a1.pma")));
- EXPECT_FALSE(base::PathExists(metrics_files.path().AppendASCII("c2.pma")));
- EXPECT_FALSE(base::PathExists(metrics_files.path().AppendASCII("b3.pma")));
- EXPECT_FALSE(base::PathExists(metrics_files.path().AppendASCII("d4.pma")));
- EXPECT_TRUE(base::PathExists(metrics_files.path().AppendASCII(".foo.pma")));
- EXPECT_TRUE(base::PathExists(metrics_files.path().AppendASCII("_bar.pma")));
- EXPECT_TRUE(base::PathExists(metrics_files.path().AppendASCII("baz")));
+ EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("a1.pma")));
+ EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("c2.pma")));
+ EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("b3.pma")));
+ EXPECT_FALSE(base::PathExists(metrics_files.GetPath().AppendASCII("d4.pma")));
+ EXPECT_TRUE(
+ base::PathExists(metrics_files.GetPath().AppendASCII(".foo.pma")));
+ EXPECT_TRUE(
+ base::PathExists(metrics_files.GetPath().AppendASCII("_bar.pma")));
+ EXPECT_TRUE(base::PathExists(metrics_files.GetPath().AppendASCII("baz")));
}
TEST_P(FileMetricsProviderTest, AccessReadWriteMetrics) {
@@ -411,9 +417,7 @@ TEST_P(FileMetricsProviderTest, AccessInitialMetrics) {
{
HistogramFlattenerDeltaRecorder flattener;
base::HistogramSnapshotManager snapshot_manager(&flattener);
- snapshot_manager.StartDeltas();
RecordInitialHistogramSnapshots(&snapshot_manager);
- snapshot_manager.FinishDeltas();
EXPECT_EQ(2U, flattener.GetRecordedDeltaHistogramNames().size());
}
EXPECT_TRUE(base::PathExists(metrics_file()));
diff --git a/chromium/components/metrics/leak_detector/BUILD.gn b/chromium/components/metrics/leak_detector/BUILD.gn
new file mode 100644
index 00000000000..0e13520174f
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/BUILD.gn
@@ -0,0 +1,66 @@
+# Copyright 2016 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+if (is_chromeos) {
+ source_set("leak_detector") {
+ sources = [
+ "call_stack_manager.cc",
+ "call_stack_manager.h",
+ "call_stack_table.cc",
+ "call_stack_table.h",
+ "custom_allocator.cc",
+ "custom_allocator.h",
+ "gnu_build_id_reader.cc",
+ "gnu_build_id_reader.h",
+ "leak_analyzer.cc",
+ "leak_analyzer.h",
+ "leak_detector.cc",
+ "leak_detector.h",
+ "leak_detector_impl.cc",
+ "leak_detector_impl.h",
+ "leak_detector_value_type.cc",
+ "leak_detector_value_type.h",
+ "protobuf_to_mojo_converter.cc",
+ "protobuf_to_mojo_converter.h",
+ "ranked_set.cc",
+ "ranked_set.h",
+ ]
+
+ deps = [
+ ":interfaces",
+ "//base",
+ "//components/metrics/proto:proto",
+ ]
+ }
+
+ mojom("interfaces") {
+ sources = [
+ "leak_detector.mojom",
+ ]
+ }
+
+ source_set("unit_tests") {
+ testonly = true
+ sources = [
+ "call_stack_manager_unittest.cc",
+ "call_stack_table_unittest.cc",
+ "leak_analyzer_unittest.cc",
+ "leak_detector_impl_unittest.cc",
+ "leak_detector_unittest.cc",
+ "protobuf_to_mojo_converter_unittest.cc",
+ "ranked_set_unittest.cc",
+ ]
+
+ deps = [
+ ":interfaces",
+ ":leak_detector",
+ "//base",
+ "//components/metrics/proto:proto",
+ "//content/test:test_support",
+ "//testing/gtest",
+ ]
+ }
+}
diff --git a/chromium/components/metrics/leak_detector/OWNERS b/chromium/components/metrics/leak_detector/OWNERS
index d8bfc45aa54..cde5a71325c 100644
--- a/chromium/components/metrics/leak_detector/OWNERS
+++ b/chromium/components/metrics/leak_detector/OWNERS
@@ -1,2 +1,7 @@
sque@chromium.org
wfh@chromium.org
+
+# Changes to Mojo interfaces require a security review to avoid
+# introducing new sandbox escapes.
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/metrics/leak_detector/gnu_build_id_reader.cc b/chromium/components/metrics/leak_detector/gnu_build_id_reader.cc
new file mode 100644
index 00000000000..ac0f07daecc
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/gnu_build_id_reader.cc
@@ -0,0 +1,124 @@
+// Copyright 2016 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/metrics/leak_detector/gnu_build_id_reader.h"
+
+#include <elf.h>
+
+#include <algorithm>
+
+#if defined(OS_CHROMEOS)
+#include <link.h> // for dl_iterate_phdr
+#else
+#error "Getting binary mapping info is not supported on this platform."
+#endif // defined(OS_CHROMEOS)
+
+namespace metrics {
+namespace leak_detector {
+namespace gnu_build_id_reader {
+
+namespace {
+
+// Contains data passed to dl_iterate_phdr() for reading build ID.
+struct ReadBuildIDData {
+ // Points to a vector for storing the build ID.
+ std::vector<uint8_t>* build_id;
+ // Indicates whether build ID was read successfully.
+ bool success;
+};
+
+// Given a pointer and an offset, add the offset to the pointer and round it up
+// to the next uint32_t.
+const void* AlignPtrAndOffsetToUint32(const void* ptr, intptr_t offset) {
+ uintptr_t addr = reinterpret_cast<uintptr_t>(ptr) + offset;
+ uintptr_t aligned_addr =
+ (addr + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
+ return reinterpret_cast<const void*>(aligned_addr);
+}
+
+// Searches for the ELF note containing the build ID within the data range
+// specified by [start, end). Returns the build ID in |*result|. If the build ID
+// is not found, |*result| will be unchanged. Returns true if the build ID was
+// successfully read or false otherwise.
+bool GetBuildIdFromNotes(const void* start,
+ const void* end,
+ std::vector<uint8_t>* result) {
+ using NoteHeaderPtr = const ElfW(Nhdr)*;
+ NoteHeaderPtr note = reinterpret_cast<NoteHeaderPtr>(start);
+
+ while (note < end) {
+ const char* name_ptr = reinterpret_cast<const char*>(note + 1);
+ if (name_ptr >= end) {
+ break;
+ }
+ // |desc_ptr| points the to the actual build ID data.
+ const uint8_t* desc_ptr = reinterpret_cast<const uint8_t*>(
+ AlignPtrAndOffsetToUint32(name_ptr, note->n_namesz));
+ if (note->n_type == NT_GNU_BUILD_ID &&
+ note->n_namesz == sizeof(ELF_NOTE_GNU) &&
+ std::equal(name_ptr, name_ptr + sizeof(ELF_NOTE_GNU), ELF_NOTE_GNU)) {
+ result->assign(desc_ptr, desc_ptr + note->n_descsz);
+ return true;
+ }
+ NoteHeaderPtr next_ptr = reinterpret_cast<NoteHeaderPtr>(
+ AlignPtrAndOffsetToUint32(desc_ptr, note->n_descsz));
+ note = next_ptr;
+ }
+ return false;
+}
+
+// Callback for dl_iterate_phdr(). Finds the notes section and looks for the
+// build ID in there. |data| points to a ReadBuildIDData struct whose |build_id|
+// field should point to a valid std::vector<uint8_t>. Returns the build ID in
+// that field, and sets |ReadBuildIDData::success| based on whether the build ID
+// was successfully read.
+//
+// This function always returns 1 to signal the end of dl_iterate_phdr()'s
+// iteration, because it is only interested in the first binary iterated by
+// dl_iterate_phdr(), which is the current binary.
+int FindNotesAndGetBuildID(struct dl_phdr_info* info,
+ size_t /* size */,
+ void* data) {
+ uintptr_t mapping_addr = reinterpret_cast<uintptr_t>(info->dlpi_addr);
+ const ElfW(Ehdr)* file_header =
+ reinterpret_cast<const ElfW(Ehdr)*>(mapping_addr);
+
+ // Make sure that a valid |mapping_addr| was read.
+ if (!file_header || file_header->e_phentsize != sizeof(ElfW(Phdr))) {
+ return 1;
+ }
+
+ // Find the ELF segment header for the NOTES section.
+ for (int i = 0; i < info->dlpi_phnum; ++i) {
+ const ElfW(Phdr)& segment_header = info->dlpi_phdr[i];
+ if (segment_header.p_type == PT_NOTE) {
+ const void* note = reinterpret_cast<const void*>(
+ mapping_addr + segment_header.p_vaddr);
+ const void* note_end = reinterpret_cast<const void*>(
+ mapping_addr + segment_header.p_vaddr + segment_header.p_memsz);
+ ReadBuildIDData* read_data = reinterpret_cast<ReadBuildIDData*>(data);
+ read_data->success =
+ GetBuildIdFromNotes(note, note_end, read_data->build_id);
+ }
+ }
+ return 1;
+}
+
+} // namespace
+
+bool ReadBuildID(std::vector<uint8_t>* build_id) {
+ ReadBuildIDData data;
+ data.build_id = build_id;
+ data.success = false;
+
+#if defined(OS_CHROMEOS)
+ dl_iterate_phdr(FindNotesAndGetBuildID, &data);
+#endif // defined(OS_CHROMEOS)
+
+ return data.success;
+}
+
+} // namespace gnu_build_id_reader
+} // namespace leak_detector
+} // namespace metrics
diff --git a/chromium/components/metrics/leak_detector/gnu_build_id_reader.h b/chromium/components/metrics/leak_detector/gnu_build_id_reader.h
new file mode 100644
index 00000000000..5cda9f3869a
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/gnu_build_id_reader.h
@@ -0,0 +1,24 @@
+// Copyright 2016 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_METRICS_LEAK_DETECTOR_GNU_BUILD_ID_READER_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_GNU_BUILD_ID_READER_H_
+
+#include <stdint.h>
+
+#include <vector>
+
+namespace metrics {
+namespace leak_detector {
+namespace gnu_build_id_reader {
+
+// Reads the build ID from the GNU build notes and stores it in |*build_id|.
+// Returns true if it was successfully read, or false otherwise.
+bool ReadBuildID(std::vector<uint8_t>* build_id);
+
+} // namespace gnu_build_id_reader
+} // namespace leak_detector
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_LEAK_DETECTOR_GNU_BUILD_ID_READER_H_
diff --git a/chromium/components/metrics/leak_detector/leak_detector.mojom b/chromium/components/metrics/leak_detector/leak_detector.mojom
new file mode 100644
index 00000000000..d985b79024c
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/leak_detector.mojom
@@ -0,0 +1,40 @@
+// Copyright 2016 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.
+
+module metrics.mojom;
+
+struct LeakDetectorParams {
+ float sampling_rate;
+ uint32 max_stack_depth;
+ uint64 analysis_interval_bytes;
+ uint32 size_suspicion_threshold;
+ uint32 call_stack_suspicion_threshold;
+};
+
+struct AllocationBreakdown {
+ array<uint32> counts_by_size;
+ uint32 count_for_call_stack;
+};
+
+struct MemoryLeakReport {
+ uint32 size_bytes;
+ array<uint64> call_stack;
+
+ array<AllocationBreakdown> alloc_breakdown_history;
+};
+
+// Provides a remote interface for enabling LeakDetector on remote processes.
+interface LeakDetector {
+ // Returns a LeakDetectorParams struct. Used to indicate to the remote process
+ // what parameters to use when initializing LeakDetector. Can also return
+ // |params.sampling_rate| == 0 to indicate that LeakDetector should not be
+ // initialized on a particular process.
+ GetParams() => (LeakDetectorParams params);
+
+ // When a remote process running LeakDetector gets some leak reports, it
+ // should call this function to return the leak reports back to the main
+ // process that implements this function. The reports should be sent back as
+ // an array of serialized MemoryLeakReportProtos.
+ SendLeakReports(array<MemoryLeakReport> reports);
+};
diff --git a/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.cc b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.cc
new file mode 100644
index 00000000000..24202dbcb8c
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.cc
@@ -0,0 +1,67 @@
+// Copyright 2016 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/metrics/leak_detector/protobuf_to_mojo_converter.h"
+
+namespace metrics {
+namespace leak_detector {
+namespace protobuf_to_mojo_converter {
+
+void ParamsToMojo(const MemoryLeakReportProto::Params& params,
+ mojom::LeakDetectorParams* mojo_params) {
+ mojo_params->sampling_rate = params.sampling_rate();
+ mojo_params->max_stack_depth = params.max_stack_depth();
+ mojo_params->analysis_interval_bytes = params.analysis_interval_bytes();
+ mojo_params->size_suspicion_threshold = params.size_suspicion_threshold();
+ mojo_params->call_stack_suspicion_threshold =
+ params.call_stack_suspicion_threshold();
+}
+
+void MojoToParams(const mojom::LeakDetectorParams& mojo_params,
+ MemoryLeakReportProto::Params* params) {
+ params->set_sampling_rate(mojo_params.sampling_rate);
+ params->set_max_stack_depth(mojo_params.max_stack_depth);
+ params->set_analysis_interval_bytes(mojo_params.analysis_interval_bytes);
+ params->set_size_suspicion_threshold(mojo_params.size_suspicion_threshold);
+ params->set_call_stack_suspicion_threshold(
+ mojo_params.call_stack_suspicion_threshold);
+}
+
+void ReportToMojo(const MemoryLeakReportProto& report,
+ mojom::MemoryLeakReport* mojo_report) {
+ mojo_report->size_bytes = report.size_bytes();
+ for (auto call_stack_value : report.call_stack()) {
+ mojo_report->call_stack.push_back(call_stack_value);
+ }
+
+ for (const auto& history_entry : report.alloc_breakdown_history()) {
+ metrics::mojom::AllocationBreakdownPtr mojo_entry =
+ metrics::mojom::AllocationBreakdown::New();
+ for (auto count : history_entry.counts_by_size()) {
+ mojo_entry->counts_by_size.push_back(count);
+ }
+ mojo_entry->count_for_call_stack = history_entry.count_for_call_stack();
+
+ mojo_report->alloc_breakdown_history.push_back(std::move(mojo_entry));
+ }
+}
+
+void MojoToReport(const mojom::MemoryLeakReport& mojo_report,
+ MemoryLeakReportProto* report) {
+ report->set_size_bytes(mojo_report.size_bytes);
+ for (auto call_stack_addr : mojo_report.call_stack)
+ report->add_call_stack(call_stack_addr);
+
+ for (const auto& history_entry : mojo_report.alloc_breakdown_history) {
+ auto proto_entry = report->add_alloc_breakdown_history();
+ for (auto count : history_entry->counts_by_size) {
+ proto_entry->add_counts_by_size(count);
+ }
+ proto_entry->set_count_for_call_stack(history_entry->count_for_call_stack);
+ }
+}
+
+} // namespace protobuf_to_mojo_converter
+} // namespace leak_detector
+} // namespace metrics
diff --git a/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.h b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.h
new file mode 100644
index 00000000000..9447f76ffab
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter.h
@@ -0,0 +1,36 @@
+// Copyright 2016 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_METRICS_LEAK_DETECTOR_PROTOBUF_TO_MOJO_CONVERTER_H_
+#define COMPONENTS_METRICS_LEAK_DETECTOR_PROTOBUF_TO_MOJO_CONVERTER_H_
+
+#include "components/metrics/leak_detector/leak_detector.mojom.h"
+#include "components/metrics/proto/memory_leak_report.pb.h"
+
+namespace metrics {
+namespace leak_detector {
+namespace protobuf_to_mojo_converter {
+
+// Converts between a MemoryLeakReportProto::Params protobuf and a
+// mojom::LeakDetectorParams Mojo structure. The Mojo structure must already be
+// allocated.
+void ParamsToMojo(const MemoryLeakReportProto::Params& params,
+ mojom::LeakDetectorParams* mojo_params);
+void MojoToParams(const mojom::LeakDetectorParams& mojo_params,
+ MemoryLeakReportProto::Params* params);
+
+// Converts between a MemoryLeakReportProto protobuf and a
+// mojom::MemoryLeakReport Mojo structure. The Mojo structure must already be
+// allocated. The conversion only covers the fields that are filled in by the
+// LeakDetector class.
+void ReportToMojo(const MemoryLeakReportProto& report,
+ mojom::MemoryLeakReport* mojo_report);
+void MojoToReport(const mojom::MemoryLeakReport& mojo_report,
+ MemoryLeakReportProto* report);
+
+} // namespace protobuf_to_mojo_converter
+} // namespace leak_detector
+} // namespace metrics
+
+#endif // COMPONENTS_METRICS_LEAK_DETECTOR_PROTOBUF_TO_MOJO_CONVERTER_H_
diff --git a/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter_unittest.cc b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter_unittest.cc
new file mode 100644
index 00000000000..f768c312f05
--- /dev/null
+++ b/chromium/components/metrics/leak_detector/protobuf_to_mojo_converter_unittest.cc
@@ -0,0 +1,139 @@
+// Copyright 2016 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/metrics/leak_detector/protobuf_to_mojo_converter.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+namespace leak_detector {
+
+TEST(protobuf_to_mojo_converterTest, ConvertParams) {
+ MemoryLeakReportProto::Params params;
+ params.set_sampling_rate(0.75);
+ params.set_max_stack_depth(19);
+ params.set_analysis_interval_bytes(25 * 1024 * 1024);
+ params.set_size_suspicion_threshold(8);
+ params.set_call_stack_suspicion_threshold(11);
+
+ // Convert to equivalent Mojo struct.
+ mojo::StructPtr<mojom::LeakDetectorParams> mojo_params =
+ mojom::LeakDetectorParams::New();
+ protobuf_to_mojo_converter::ParamsToMojo(params, mojo_params.get());
+
+ EXPECT_DOUBLE_EQ(0.75, mojo_params->sampling_rate);
+ EXPECT_EQ(19U, mojo_params->max_stack_depth);
+ EXPECT_EQ(25U * 1024 * 1024, mojo_params->analysis_interval_bytes);
+ EXPECT_EQ(8U, mojo_params->size_suspicion_threshold);
+ EXPECT_EQ(11U, mojo_params->call_stack_suspicion_threshold);
+
+ // Convert Mojo struct back to protobuf.
+ MemoryLeakReportProto::Params new_params;
+ protobuf_to_mojo_converter::MojoToParams(*mojo_params, &new_params);
+
+ EXPECT_DOUBLE_EQ(0.75, new_params.sampling_rate());
+ EXPECT_EQ(19U, new_params.max_stack_depth());
+ EXPECT_EQ(25U * 1024 * 1024, new_params.analysis_interval_bytes());
+ EXPECT_EQ(8U, new_params.size_suspicion_threshold());
+ EXPECT_EQ(11U, new_params.call_stack_suspicion_threshold());
+}
+
+TEST(protobuf_to_mojo_converterTest, ConvertReport) {
+ MemoryLeakReportProto report;
+ report.add_call_stack(0xdeadbeef);
+ report.add_call_stack(0xc001d00d);
+ report.add_call_stack(0x900df00d);
+ report.set_size_bytes(24);
+
+ auto entry1 = report.add_alloc_breakdown_history();
+ entry1->add_counts_by_size(1);
+ entry1->add_counts_by_size(2);
+ entry1->add_counts_by_size(3);
+ entry1->set_count_for_call_stack(4);
+
+ auto entry2 = report.add_alloc_breakdown_history();
+ entry2->add_counts_by_size(11);
+ entry2->add_counts_by_size(12);
+ entry2->add_counts_by_size(13);
+ entry2->add_counts_by_size(14);
+ entry2->set_count_for_call_stack(15);
+
+ auto entry3 = report.add_alloc_breakdown_history();
+ entry3->add_counts_by_size(21);
+ entry3->add_counts_by_size(22);
+ entry3->add_counts_by_size(23);
+ entry3->add_counts_by_size(24);
+ entry3->add_counts_by_size(25);
+ entry3->set_count_for_call_stack(26);
+
+ // Convert to equivalent Mojo struct.
+ mojo::StructPtr<mojom::MemoryLeakReport> mojo_report =
+ mojom::MemoryLeakReport::New();
+ protobuf_to_mojo_converter::ReportToMojo(report, mojo_report.get());
+
+ ASSERT_EQ(3U, mojo_report->call_stack.size());
+ EXPECT_EQ(0xdeadbeef, mojo_report->call_stack[0]);
+ EXPECT_EQ(0xc001d00d, mojo_report->call_stack[1]);
+ EXPECT_EQ(0x900df00d, mojo_report->call_stack[2]);
+ EXPECT_EQ(24U, mojo_report->size_bytes);
+
+ ASSERT_EQ(3U, mojo_report->alloc_breakdown_history.size());
+
+ ASSERT_EQ(3U, mojo_report->alloc_breakdown_history[0]->counts_by_size.size());
+ EXPECT_EQ(1U, mojo_report->alloc_breakdown_history[0]->counts_by_size[0]);
+ EXPECT_EQ(2U, mojo_report->alloc_breakdown_history[0]->counts_by_size[1]);
+ EXPECT_EQ(3U, mojo_report->alloc_breakdown_history[0]->counts_by_size[2]);
+ EXPECT_EQ(4U, mojo_report->alloc_breakdown_history[0]->count_for_call_stack);
+
+ ASSERT_EQ(4U, mojo_report->alloc_breakdown_history[1]->counts_by_size.size());
+ EXPECT_EQ(11U, mojo_report->alloc_breakdown_history[1]->counts_by_size[0]);
+ EXPECT_EQ(12U, mojo_report->alloc_breakdown_history[1]->counts_by_size[1]);
+ EXPECT_EQ(13U, mojo_report->alloc_breakdown_history[1]->counts_by_size[2]);
+ EXPECT_EQ(14U, mojo_report->alloc_breakdown_history[1]->counts_by_size[3]);
+ EXPECT_EQ(15U, mojo_report->alloc_breakdown_history[1]->count_for_call_stack);
+
+ ASSERT_EQ(5U, mojo_report->alloc_breakdown_history[2]->counts_by_size.size());
+ EXPECT_EQ(21U, mojo_report->alloc_breakdown_history[2]->counts_by_size[0]);
+ EXPECT_EQ(22U, mojo_report->alloc_breakdown_history[2]->counts_by_size[1]);
+ EXPECT_EQ(23U, mojo_report->alloc_breakdown_history[2]->counts_by_size[2]);
+ EXPECT_EQ(24U, mojo_report->alloc_breakdown_history[2]->counts_by_size[3]);
+ EXPECT_EQ(25U, mojo_report->alloc_breakdown_history[2]->counts_by_size[4]);
+ EXPECT_EQ(26U, mojo_report->alloc_breakdown_history[2]->count_for_call_stack);
+
+ // Convert Mojo struct back to protobuf.
+ MemoryLeakReportProto new_report;
+ protobuf_to_mojo_converter::MojoToReport(*mojo_report, &new_report);
+
+ ASSERT_EQ(3, new_report.call_stack().size());
+ EXPECT_EQ(0xdeadbeef, new_report.call_stack(0));
+ EXPECT_EQ(0xc001d00d, new_report.call_stack(1));
+ EXPECT_EQ(0x900df00d, new_report.call_stack(2));
+ EXPECT_EQ(24U, new_report.size_bytes());
+
+ ASSERT_EQ(3, new_report.alloc_breakdown_history().size());
+
+ ASSERT_EQ(3, new_report.alloc_breakdown_history(0).counts_by_size().size());
+ EXPECT_EQ(1U, new_report.alloc_breakdown_history(0).counts_by_size(0));
+ EXPECT_EQ(2U, new_report.alloc_breakdown_history(0).counts_by_size(1));
+ EXPECT_EQ(3U, new_report.alloc_breakdown_history(0).counts_by_size(2));
+ EXPECT_EQ(4U, new_report.alloc_breakdown_history(0).count_for_call_stack());
+
+ ASSERT_EQ(4, new_report.alloc_breakdown_history(1).counts_by_size().size());
+ EXPECT_EQ(11U, new_report.alloc_breakdown_history(1).counts_by_size(0));
+ EXPECT_EQ(12U, new_report.alloc_breakdown_history(1).counts_by_size(1));
+ EXPECT_EQ(13U, new_report.alloc_breakdown_history(1).counts_by_size(2));
+ EXPECT_EQ(14U, new_report.alloc_breakdown_history(1).counts_by_size(3));
+ EXPECT_EQ(15U, new_report.alloc_breakdown_history(1).count_for_call_stack());
+
+ ASSERT_EQ(5, new_report.alloc_breakdown_history(2).counts_by_size().size());
+ EXPECT_EQ(21U, new_report.alloc_breakdown_history(2).counts_by_size(0));
+ EXPECT_EQ(22U, new_report.alloc_breakdown_history(2).counts_by_size(1));
+ EXPECT_EQ(23U, new_report.alloc_breakdown_history(2).counts_by_size(2));
+ EXPECT_EQ(24U, new_report.alloc_breakdown_history(2).counts_by_size(3));
+ EXPECT_EQ(25U, new_report.alloc_breakdown_history(2).counts_by_size(4));
+ EXPECT_EQ(26U, new_report.alloc_breakdown_history(2).count_for_call_stack());
+}
+
+} // namespace leak_detector
+} // namespace metrics
diff --git a/chromium/components/metrics/metrics_log.cc b/chromium/components/metrics/metrics_log.cc
index 3d8cc1886a8..3824762e217 100644
--- a/chromium/components/metrics/metrics_log.cc
+++ b/chromium/components/metrics/metrics_log.cc
@@ -117,9 +117,9 @@ MetricsLog::~MetricsLog() {
// static
void MetricsLog::RegisterPrefs(PrefRegistrySimple* registry) {
- registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail, 0);
registry->RegisterIntegerPref(
prefs::kStabilityBreakpadRegistrationSuccess, 0);
@@ -129,6 +129,9 @@ void MetricsLog::RegisterPrefs(PrefRegistrySimple* registry) {
std::string());
registry->RegisterStringPref(prefs::kStabilitySavedSystemProfileHash,
std::string());
+ registry->RegisterIntegerPref(prefs::kStabilityDeferredCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityDiscardCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityVersionMismatchCount, 0);
}
// static
@@ -203,37 +206,70 @@ void MetricsLog::RecordStabilityMetrics(
metrics_providers[i]->ProvideStabilityMetrics(system_profile);
}
- // Omit some stats unless this is the initial stability log.
- if (log_type() != INITIAL_STABILITY_LOG)
- return;
+ SystemProfileProto::Stability* stability =
+ system_profile->mutable_stability();
int incomplete_shutdown_count =
pref->GetInteger(prefs::kStabilityIncompleteSessionEndCount);
- pref->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
+ if (incomplete_shutdown_count) {
+ pref->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
+ stability->set_incomplete_shutdown_count(incomplete_shutdown_count);
+ }
+
int breakpad_registration_success_count =
pref->GetInteger(prefs::kStabilityBreakpadRegistrationSuccess);
- pref->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
+ if (breakpad_registration_success_count) {
+ pref->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
+ stability->set_breakpad_registration_success_count(
+ breakpad_registration_success_count);
+ }
+
int breakpad_registration_failure_count =
pref->GetInteger(prefs::kStabilityBreakpadRegistrationFail);
- pref->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
+ if (breakpad_registration_failure_count) {
+ pref->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
+ stability->set_breakpad_registration_failure_count(
+ breakpad_registration_failure_count);
+ }
+
int debugger_present_count =
pref->GetInteger(prefs::kStabilityDebuggerPresent);
- pref->SetInteger(prefs::kStabilityDebuggerPresent, 0);
+ if (debugger_present_count) {
+ pref->SetInteger(prefs::kStabilityDebuggerPresent, 0);
+ stability->set_debugger_present_count(debugger_present_count);
+ }
+
int debugger_not_present_count =
pref->GetInteger(prefs::kStabilityDebuggerNotPresent);
- pref->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
+ if (debugger_not_present_count) {
+ pref->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
+ stability->set_debugger_not_present_count(debugger_not_present_count);
+ }
- // TODO(jar): The following are all optional, so we *could* optimize them for
- // values of zero (and not include them).
- SystemProfileProto::Stability* stability =
- system_profile->mutable_stability();
- stability->set_incomplete_shutdown_count(incomplete_shutdown_count);
- stability->set_breakpad_registration_success_count(
- breakpad_registration_success_count);
- stability->set_breakpad_registration_failure_count(
- breakpad_registration_failure_count);
- stability->set_debugger_present_count(debugger_present_count);
- stability->set_debugger_not_present_count(debugger_not_present_count);
+ // Note: only logging the following histograms for non-zero values.
+
+ int deferred_count = pref->GetInteger(prefs::kStabilityDeferredCount);
+ if (deferred_count) {
+ local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
+ UMA_STABILITY_HISTOGRAM_COUNTS_100(
+ "Stability.Internals.InitialStabilityLogDeferredCount", deferred_count);
+ }
+
+ int discard_count = local_state_->GetInteger(prefs::kStabilityDiscardCount);
+ if (discard_count) {
+ local_state_->SetInteger(prefs::kStabilityDiscardCount, 0);
+ UMA_STABILITY_HISTOGRAM_COUNTS_100("Stability.Internals.DataDiscardCount",
+ discard_count);
+ }
+
+ int version_mismatch_count =
+ local_state_->GetInteger(prefs::kStabilityVersionMismatchCount);
+ if (version_mismatch_count) {
+ local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
+ UMA_STABILITY_HISTOGRAM_COUNTS_100(
+ "Stability.Internals.VersionMismatchCount",
+ version_mismatch_count);
+ }
}
void MetricsLog::RecordGeneralMetrics(
@@ -285,9 +321,11 @@ bool MetricsLog::HasStabilityMetrics() const {
// protobufs is complete.
void MetricsLog::WriteRequiredStabilityAttributes(PrefService* pref) {
int launch_count = pref->GetInteger(prefs::kStabilityLaunchCount);
- pref->SetInteger(prefs::kStabilityLaunchCount, 0);
+ if (launch_count)
+ pref->SetInteger(prefs::kStabilityLaunchCount, 0);
int crash_count = pref->GetInteger(prefs::kStabilityCrashCount);
- pref->SetInteger(prefs::kStabilityCrashCount, 0);
+ if (crash_count)
+ pref->SetInteger(prefs::kStabilityCrashCount, 0);
SystemProfileProto::Stability* stability =
uma_proto()->mutable_system_profile()->mutable_stability();
@@ -379,19 +417,22 @@ void MetricsLog::RecordEnvironment(
for (size_t i = 0; i < metrics_providers.size(); ++i)
metrics_providers[i]->ProvideSystemProfileMetrics(system_profile);
- std::string serialied_system_profile;
+ std::string serialized_system_profile;
std::string base64_system_profile;
- if (system_profile->SerializeToString(&serialied_system_profile)) {
- base::Base64Encode(serialied_system_profile, &base64_system_profile);
+ if (system_profile->SerializeToString(&serialized_system_profile)) {
+ base::Base64Encode(serialized_system_profile, &base64_system_profile);
PrefService* local_state = local_state_;
local_state->SetString(prefs::kStabilitySavedSystemProfile,
base64_system_profile);
local_state->SetString(prefs::kStabilitySavedSystemProfileHash,
- ComputeSHA1(serialied_system_profile));
+ ComputeSHA1(serialized_system_profile));
}
}
-bool MetricsLog::LoadSavedEnvironmentFromPrefs() {
+bool MetricsLog::LoadSavedEnvironmentFromPrefs(std::string* app_version) {
+ DCHECK(app_version);
+ app_version->clear();
+
PrefService* local_state = local_state_;
const std::string base64_system_profile =
local_state->GetString(prefs::kStabilitySavedSystemProfile);
@@ -404,10 +445,15 @@ bool MetricsLog::LoadSavedEnvironmentFromPrefs() {
local_state->ClearPref(prefs::kStabilitySavedSystemProfileHash);
SystemProfileProto* system_profile = uma_proto()->mutable_system_profile();
- std::string serialied_system_profile;
- return base::Base64Decode(base64_system_profile, &serialied_system_profile) &&
- ComputeSHA1(serialied_system_profile) == system_profile_hash &&
- system_profile->ParseFromString(serialied_system_profile);
+ std::string serialized_system_profile;
+
+ bool success =
+ base::Base64Decode(base64_system_profile, &serialized_system_profile) &&
+ ComputeSHA1(serialized_system_profile) == system_profile_hash &&
+ system_profile->ParseFromString(serialized_system_profile);
+ if (success)
+ *app_version = system_profile->app_version();
+ return success;
}
void MetricsLog::CloseLog() {
diff --git a/chromium/components/metrics/metrics_log.h b/chromium/components/metrics/metrics_log.h
index 0506df28db0..6b37e7b4c98 100644
--- a/chromium/components/metrics/metrics_log.h
+++ b/chromium/components/metrics/metrics_log.h
@@ -100,9 +100,11 @@ class MetricsLog {
int64_t metrics_reporting_enabled_date);
// Loads the environment proto that was saved by the last RecordEnvironment()
- // call from prefs and clears the pref value. Returns true on success or false
- // if there was no saved environment in prefs or it could not be decoded.
- bool LoadSavedEnvironmentFromPrefs();
+ // call from prefs and clears the pref value. On success, returns true and
+ // |app_version| contains the recovered version. Otherwise (if there was no
+ // saved environment in prefs or it could not be decoded), returns false and
+ // |app_version| is empty.
+ bool LoadSavedEnvironmentFromPrefs(std::string* app_version);
// Writes application stability metrics, including stability metrics provided
// by the specified set of |metrics_providers|. The system profile portion of
diff --git a/chromium/components/metrics/metrics_log_manager.cc b/chromium/components/metrics/metrics_log_manager.cc
index 415db785656..d06b5ae0ada 100644
--- a/chromium/components/metrics/metrics_log_manager.cc
+++ b/chromium/components/metrics/metrics_log_manager.cc
@@ -42,11 +42,13 @@ MetricsLogManager::MetricsLogManager(PrefService* local_state,
: unsent_logs_loaded_(false),
initial_log_queue_(local_state,
prefs::kMetricsInitialLogs,
+ prefs::kDeprecatedMetricsInitialLogs,
kInitialLogsPersistLimit,
kStorageByteLimitPerLogType,
0),
ongoing_log_queue_(local_state,
prefs::kMetricsOngoingLogs,
+ prefs::kDeprecatedMetricsOngoingLogs,
kOngoingLogsPersistLimit,
kStorageByteLimitPerLogType,
max_ongoing_log_size) {}
diff --git a/chromium/components/metrics/metrics_log_manager_unittest.cc b/chromium/components/metrics/metrics_log_manager_unittest.cc
index 7a634609a54..fbd1dd5d2b5 100644
--- a/chromium/components/metrics/metrics_log_manager_unittest.cc
+++ b/chromium/components/metrics/metrics_log_manager_unittest.cc
@@ -37,7 +37,7 @@ class TestLogPrefService : public TestingPrefServiceSimple {
list_length = GetList(prefs::kMetricsInitialLogs)->GetSize();
else
list_length = GetList(prefs::kMetricsOngoingLogs)->GetSize();
- return list_length / 2;
+ return list_length;
}
};
@@ -133,11 +133,11 @@ TEST(MetricsLogManagerTest, InterjectedLogPreservesType) {
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.PauseCurrentLog();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
log_manager.ResumePausedLog();
log_manager.StageNextLogForUpload();
@@ -163,8 +163,8 @@ TEST(MetricsLogManagerTest, StoreAndLoad) {
// Simulate a log having already been unsent from a previous session.
{
std::string log("proto");
- PersistedLogs ongoing_logs(&pref_service, prefs::kMetricsOngoingLogs, 1,
- 1, 0);
+ PersistedLogs ongoing_logs(&pref_service, prefs::kMetricsOngoingLogs,
+ prefs::kDeprecatedMetricsOngoingLogs, 1, 1, 0);
ongoing_logs.StoreLog(log);
ongoing_logs.SerializeLogs();
}
@@ -173,11 +173,11 @@ TEST(MetricsLogManagerTest, StoreAndLoad) {
log_manager.LoadPersistedUnsentLogs();
EXPECT_TRUE(log_manager.has_unsent_logs());
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.StageNextLogForUpload();
log_manager.FinishCurrentLog();
@@ -234,8 +234,8 @@ TEST(MetricsLogManagerTest, StoreStagedLogTypes) {
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.PersistUnsentLogs();
@@ -249,8 +249,8 @@ TEST(MetricsLogManagerTest, StoreStagedLogTypes) {
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
log_manager.StageNextLogForUpload();
log_manager.PersistUnsentLogs();
@@ -267,11 +267,11 @@ TEST(MetricsLogManagerTest, LargeLogDiscarding) {
MetricsLogManager log_manager(&pref_service, 1);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
// Only the ongoing log should be written out, due to the threshold.
@@ -289,11 +289,11 @@ TEST(MetricsLogManagerTest, DiscardOrder) {
MetricsLogManager log_manager(&pref_service, 0);
log_manager.LoadPersistedUnsentLogs();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::INITIAL_STABILITY_LOG, &client, &pref_service));
log_manager.FinishCurrentLog();
- log_manager.BeginLoggingWithLog(base::WrapUnique(new MetricsLog(
- "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service)));
+ log_manager.BeginLoggingWithLog(base::MakeUnique<MetricsLog>(
+ "id", 0, MetricsLog::ONGOING_LOG, &client, &pref_service));
log_manager.StageNextLogForUpload();
log_manager.FinishCurrentLog();
log_manager.DiscardStagedLog();
diff --git a/chromium/components/metrics/metrics_log_unittest.cc b/chromium/components/metrics/metrics_log_unittest.cc
index fe03ff8607c..57a1209f1ad 100644
--- a/chromium/components/metrics/metrics_log_unittest.cc
+++ b/chromium/components/metrics/metrics_log_unittest.cc
@@ -276,12 +276,15 @@ TEST_F(MetricsLogTest, LoadSavedEnvironmentFromPrefs) {
prefs::kStabilitySavedSystemProfileHash;
TestMetricsServiceClient client;
+ client.set_version_string("bogus version");
// The pref value is empty, so loading it from prefs should fail.
{
TestMetricsLog log(
kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
- EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs());
+ std::string app_version;
+ EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs(&app_version));
+ EXPECT_TRUE(app_version.empty());
}
// Do a RecordEnvironment() call and check whether the pref is recorded.
@@ -298,7 +301,9 @@ TEST_F(MetricsLogTest, LoadSavedEnvironmentFromPrefs) {
{
TestMetricsLog log(
kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
- EXPECT_TRUE(log.LoadSavedEnvironmentFromPrefs());
+ std::string app_version;
+ EXPECT_TRUE(log.LoadSavedEnvironmentFromPrefs(&app_version));
+ EXPECT_EQ("bogus version", app_version);
// Check some values in the system profile.
EXPECT_EQ(kInstallDateExpected, log.system_profile().install_date());
EXPECT_EQ(kEnabledDateExpected, log.system_profile().uma_enabled_date());
@@ -322,7 +327,9 @@ TEST_F(MetricsLogTest, LoadSavedEnvironmentFromPrefs) {
prefs_.SetString(kSystemProfileHashPref, "deadbeef");
TestMetricsLog log(
kClientId, kSessionId, MetricsLog::ONGOING_LOG, &client, &prefs_);
- EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs());
+ std::string app_version;
+ EXPECT_FALSE(log.LoadSavedEnvironmentFromPrefs(&app_version));
+ EXPECT_TRUE(app_version.empty());
// Ensure that the prefs are cleared, even if the call failed.
EXPECT_TRUE(prefs_.GetString(kSystemProfilePref).empty());
EXPECT_TRUE(prefs_.GetString(kSystemProfileHashPref).empty());
@@ -388,12 +395,12 @@ TEST_F(MetricsLogTest, InitialLogStabilityMetrics) {
// Required metrics:
EXPECT_TRUE(stability.has_launch_count());
EXPECT_TRUE(stability.has_crash_count());
- // Initial log metrics:
- EXPECT_TRUE(stability.has_incomplete_shutdown_count());
- EXPECT_TRUE(stability.has_breakpad_registration_success_count());
- EXPECT_TRUE(stability.has_breakpad_registration_failure_count());
- EXPECT_TRUE(stability.has_debugger_present_count());
- EXPECT_TRUE(stability.has_debugger_not_present_count());
+ // Initial log metrics: only expected if non-zero.
+ EXPECT_FALSE(stability.has_incomplete_shutdown_count());
+ EXPECT_FALSE(stability.has_breakpad_registration_success_count());
+ EXPECT_FALSE(stability.has_breakpad_registration_failure_count());
+ EXPECT_FALSE(stability.has_debugger_present_count());
+ EXPECT_FALSE(stability.has_debugger_not_present_count());
// The test provider should have been called upon to provide initial
// stability and regular stability metrics.
@@ -418,7 +425,7 @@ TEST_F(MetricsLogTest, OngoingLogStabilityMetrics) {
// Required metrics:
EXPECT_TRUE(stability.has_launch_count());
EXPECT_TRUE(stability.has_crash_count());
- // Initial log metrics:
+ // Initial log metrics: only expected if non-zero.
EXPECT_FALSE(stability.has_incomplete_shutdown_count());
EXPECT_FALSE(stability.has_breakpad_registration_success_count());
EXPECT_FALSE(stability.has_breakpad_registration_failure_count());
diff --git a/chromium/components/metrics/metrics_pref_names.cc b/chromium/components/metrics/metrics_pref_names.cc
index b751c02d4f4..1d5a7b63e84 100644
--- a/chromium/components/metrics/metrics_pref_names.cc
+++ b/chromium/components/metrics/metrics_pref_names.cc
@@ -7,6 +7,21 @@
namespace metrics {
namespace prefs {
+// Array of strings that are each UMA logs that were supposed to be sent in the
+// first minute of a browser session. These logs include things like crash count
+// info, etc.
+// Deprecated by kMetricsInitialLogs.
+const char kDeprecatedMetricsInitialLogs[] =
+ "user_experience_metrics.initial_logs_list";
+
+// Array of strings that are each UMA logs that were not sent because the
+// browser terminated before these accumulated metrics could be sent. These
+// logs typically include histograms and memory reports, as well as ongoing
+// user activities.
+// Deprecated by kMetricsOngoingLogs.
+const char kDeprecatedMetricsOngoingLogs[] =
+ "user_experience_metrics.ongoing_logs_list";
+
// Set once, to the current epoch time, on the first run of chrome on this
// machine. Attached to metrics reports forever thereafter.
const char kInstallDate[] = "uninstall_metrics.installation_date2";
@@ -23,11 +38,10 @@ const char kMetricsClientID[] = "user_experience_metrics.client_id2";
// used for the value is metrics::MetricsServiceClient::EnableMetricsDefault.
const char kMetricsDefaultOptIn[] = "user_experience_metrics.default_opt_in";
-// Array of strings that are each UMA logs that were supposed to be sent in the
-// first minute of a browser session. These logs include things like crash count
-// info, etc.
-const char kMetricsInitialLogs[] =
- "user_experience_metrics.initial_logs_list";
+// Array of dictionaries that are each UMA logs that were supposed to be sent in
+// the first minute of a browser session. These logs include things like crash
+// count info, etc.
+const char kMetricsInitialLogs[] = "user_experience_metrics.initial_logs2";
// The metrics entropy source.
// Note: The name low_entropy_source2 is a result of creating
@@ -39,12 +53,11 @@ const char kMetricsLowEntropySource[] =
// stored locally and never transmitted in metrics reports.
const char kMetricsMachineId[] = "user_experience_metrics.machine_id";
-// Array of strings that are each UMA logs that were not sent because the
-// browser terminated before these accumulated metrics could be sent. These
+// Array of dictionaries that are each UMA logs that were not sent because the
+// browser terminated before these accumulated metrics could be sent. These
// logs typically include histograms and memory reports, as well as ongoing
// user activities.
-const char kMetricsOngoingLogs[] =
- "user_experience_metrics.ongoing_logs_list";
+const char kMetricsOngoingLogs[] = "user_experience_metrics.ongoing_logs2";
// Boolean that indicates a cloned install has been detected and the metrics
// client id and low entropy source should be reset.
@@ -55,8 +68,8 @@ const char kMetricsResetIds[] = "user_experience_metrics.reset_metrics_ids";
const char kMetricsReportingEnabled[] =
"user_experience_metrics.reporting_enabled";
-// Date/time when the user opted in to UMA and generated the client id for the
-// very first time (local machine time, stored as a 64-bit time_t value).
+// Date/time when the user opted in to UMA and generated the client id most
+// recently (local machine time, stored as a 64-bit time_t value).
const char kMetricsReportingEnabledTimestamp[] =
"user_experience_metrics.client_id_timestamp";
@@ -86,6 +99,16 @@ const char kStabilityChildProcessCrashCount[] =
const char kStabilityCrashCount[] =
"user_experience_metrics.stability.crash_count";
+// Number of times the initial stability log upload was deferred to the next
+// startup.
+const char kStabilityDeferredCount[] =
+ "user_experience_metrics.stability.deferred_count";
+
+// Number of times stability data was discarded. This is accumulated since the
+// last report, even across versions.
+const char kStabilityDiscardCount[] =
+ "user_experience_metrics.stability.discard_count";
+
// Number of times the browser has been run under a debugger.
const char kStabilityDebuggerPresent[] =
"user_experience_metrics.stability.debugger_present";
@@ -111,6 +134,11 @@ const char kStabilityExtensionRendererCrashCount[] =
const char kStabilityExtensionRendererFailedLaunchCount[] =
"user_experience_metrics.stability.extension_renderer_failed_launch_count";
+// Number of times an extension renderer process successfully launched since the
+// last report.
+const char kStabilityExtensionRendererLaunchCount[] =
+ "user_experience_metrics.stability.extension_renderer_launch_count";
+
// Number of times the session end did not complete.
const char kStabilityIncompleteSessionEndCount[] =
"user_experience_metrics.stability.incomplete_session_end_count";
@@ -145,6 +173,11 @@ const char kStabilityRendererFailedLaunchCount[] =
const char kStabilityRendererHangCount[] =
"user_experience_metrics.stability.renderer_hang_count";
+// Number of times a renderer process successfully launched since the last
+// report.
+const char kStabilityRendererLaunchCount[] =
+ "user_experience_metrics.stability.renderer_launch_count";
+
// Base64 encoded serialized UMA system profile proto from the previous session.
const char kStabilitySavedSystemProfile[] =
"user_experience_metrics.stability.saved_system_profile";
@@ -168,6 +201,11 @@ const char kStabilityStatsBuildTime[] =
const char kStabilityStatsVersion[] =
"user_experience_metrics.stability.stats_version";
+// Number of times the version number stored in prefs did not match the
+// serialized system profile version number.
+const char kStabilityVersionMismatchCount[] =
+ "user_experience_metrics.stability.version_mismatch_count";
+
// The keys below are strictly increasing counters over the lifetime of
// a chrome installation. They are (optionally) sent up to the uninstall
// survey in the event of uninstallation.
diff --git a/chromium/components/metrics/metrics_pref_names.h b/chromium/components/metrics/metrics_pref_names.h
index bcd531892d8..df25e3854a9 100644
--- a/chromium/components/metrics/metrics_pref_names.h
+++ b/chromium/components/metrics/metrics_pref_names.h
@@ -10,6 +10,8 @@ namespace prefs {
// Alphabetical list of preference names specific to the metrics
// component. Document each in the .cc file.
+extern const char kDeprecatedMetricsInitialLogs[];
+extern const char kDeprecatedMetricsOngoingLogs[];
extern const char kInstallDate[];
extern const char kMetricsClientID[];
extern const char kMetricsDefaultOptIn[];
@@ -34,9 +36,12 @@ extern const char kStabilityChildProcessCrashCount[];
extern const char kStabilityCrashCount[];
extern const char kStabilityDebuggerPresent[];
extern const char kStabilityDebuggerNotPresent[];
+extern const char kStabilityDeferredCount[];
+extern const char kStabilityDiscardCount[];
extern const char kStabilityExecutionPhase[];
extern const char kStabilityExtensionRendererCrashCount[];
extern const char kStabilityExtensionRendererFailedLaunchCount[];
+extern const char kStabilityExtensionRendererLaunchCount[];
extern const char kStabilityExitedCleanly[];
extern const char kStabilityIncompleteSessionEndCount[];
extern const char kStabilityLastTimestampSec[];
@@ -46,11 +51,13 @@ extern const char kStabilityPageLoadCount[];
extern const char kStabilityRendererCrashCount[];
extern const char kStabilityRendererFailedLaunchCount[];
extern const char kStabilityRendererHangCount[];
+extern const char kStabilityRendererLaunchCount[];
extern const char kStabilitySavedSystemProfile[];
extern const char kStabilitySavedSystemProfileHash[];
extern const char kStabilitySessionEndCompleted[];
extern const char kStabilityStatsBuildTime[];
extern const char kStabilityStatsVersion[];
+extern const char kStabilityVersionMismatchCount[];
extern const char kUninstallLaunchCount[];
extern const char kUninstallMetricsPageLoadCount[];
extern const char kUninstallMetricsUptimeSec[];
diff --git a/chromium/components/metrics/metrics_provider.cc b/chromium/components/metrics/metrics_provider.cc
index 924cc6f3180..50f621a73ec 100644
--- a/chromium/components/metrics/metrics_provider.cc
+++ b/chromium/components/metrics/metrics_provider.cc
@@ -24,6 +24,9 @@ void MetricsProvider::OnRecordingEnabled() {
void MetricsProvider::OnRecordingDisabled() {
}
+void MetricsProvider::OnAppEnterBackground() {
+}
+
void MetricsProvider::ProvideSystemProfileMetrics(
SystemProfileProto* system_profile_proto) {
}
diff --git a/chromium/components/metrics/metrics_provider.h b/chromium/components/metrics/metrics_provider.h
index 6a690f5251c..d76b6772ccd 100644
--- a/chromium/components/metrics/metrics_provider.h
+++ b/chromium/components/metrics/metrics_provider.h
@@ -36,6 +36,13 @@ class MetricsProvider {
// Called when metrics recording has been disabled.
virtual void OnRecordingDisabled();
+ // Called when the application is going into background mode, on platforms
+ // where applications may be killed when going into the background (Android,
+ // iOS). Providers that buffer histogram data in memory should persist
+ // histograms in this callback, as the application may be killed without
+ // further notification after this callback.
+ virtual void OnAppEnterBackground();
+
// Provides additional metrics into the system profile.
virtual void ProvideSystemProfileMetrics(
SystemProfileProto* system_profile_proto);
diff --git a/chromium/components/metrics/metrics_service.cc b/chromium/components/metrics/metrics_service.cc
index a14b047a6c2..2acc9cb0b88 100644
--- a/chromium/components/metrics/metrics_service.cc
+++ b/chromium/components/metrics/metrics_service.cc
@@ -361,13 +361,6 @@ bool MetricsService::WasLastShutdownClean() const {
return clean_exit_beacon_.exited_cleanly();
}
-std::unique_ptr<const base::FieldTrial::EntropyProvider>
-MetricsService::CreateEntropyProvider() {
- // TODO(asvitkine): Refactor the code so that MetricsService does not expose
- // this method.
- return state_manager_->CreateDefaultEntropyProvider();
-}
-
void MetricsService::EnableRecording() {
DCHECK(IsSingleThreaded());
@@ -396,8 +389,6 @@ void MetricsService::DisableRecording() {
return;
recording_state_ = INACTIVE;
- client_->OnRecordingDisabled();
-
base::RemoveActionCallback(action_callback_);
for (MetricsProvider* provider : metrics_providers_)
@@ -469,6 +460,11 @@ void MetricsService::OnAppEnterBackground() {
MarkAppCleanShutdownAndCommit(&clean_exit_beacon_, local_state_);
+ // Give providers a chance to persist histograms as part of being
+ // backgrounded.
+ for (MetricsProvider* provider : metrics_providers_)
+ provider->OnAppEnterBackground();
+
// At this point, there's no way of knowing when the process will be
// killed, so this has to be treated similar to a shutdown, closing and
// persisting all logs. Unlinke a shutdown, the state is primed to be ready
@@ -520,12 +516,20 @@ void MetricsService::ClearSavedStabilityMetrics() {
provider->ClearSavedStabilityMetrics();
// Reset the prefs that are managed by MetricsService/MetricsLog directly.
+ local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0);
+ local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0);
local_state_->SetInteger(prefs::kStabilityCrashCount, 0);
+ local_state_->SetInteger(prefs::kStabilityDebuggerPresent, 0);
+ local_state_->SetInteger(prefs::kStabilityDebuggerNotPresent, 0);
local_state_->SetInteger(prefs::kStabilityExecutionPhase,
UNINITIALIZED_PHASE);
local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0);
local_state_->SetInteger(prefs::kStabilityLaunchCount, 0);
local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true);
+ local_state_->SetInteger(prefs::kStabilityDeferredCount, 0);
+ // Note: kStabilityDiscardCount is not cleared as its intent is to measure
+ // the number of times data is discarded, even across versions.
+ local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0);
}
void MetricsService::PushExternalLog(const std::string& log) {
@@ -542,6 +546,11 @@ UpdateUsagePrefCallbackType MetricsService::GetDataUseForwardingCallback() {
return UpdateUsagePrefCallbackType();
}
+void MetricsService::MergeHistogramDeltas() {
+ for (MetricsProvider* provider : metrics_providers_)
+ provider->MergeHistogramDeltas();
+}
+
//------------------------------------------------------------------------------
// private methods
//------------------------------------------------------------------------------
@@ -554,8 +563,11 @@ void MetricsService::InitializeMetricsState() {
const int64_t buildtime = MetricsLog::GetBuildTime();
const std::string version = client_->GetVersionString();
bool version_changed = false;
- if (local_state_->GetInt64(prefs::kStabilityStatsBuildTime) != buildtime ||
- local_state_->GetString(prefs::kStabilityStatsVersion) != version) {
+ int64_t previous_buildtime =
+ local_state_->GetInt64(prefs::kStabilityStatsBuildTime);
+ std::string previous_version =
+ local_state_->GetString(prefs::kStabilityStatsVersion);
+ if (previous_buildtime != buildtime || previous_version != version) {
local_state_->SetString(prefs::kStabilityStatsVersion, version);
local_state_->SetInt64(prefs::kStabilityStatsBuildTime, buildtime);
version_changed = true;
@@ -587,8 +599,11 @@ void MetricsService::InitializeMetricsState() {
// If the previous session didn't exit cleanly, or if any provider
// explicitly requests it, prepare an initial stability log -
// provided UMA is enabled.
- if (state_manager_->IsMetricsReportingEnabled())
- has_initial_stability_log = PrepareInitialStabilityLog();
+ if (state_manager_->IsMetricsReportingEnabled()) {
+ has_initial_stability_log = PrepareInitialStabilityLog(previous_version);
+ if (!has_initial_stability_log)
+ IncrementPrefValue(prefs::kStabilityDeferredCount);
+ }
}
// If no initial stability log was generated and there was a version upgrade,
@@ -597,8 +612,10 @@ void MetricsService::InitializeMetricsState() {
// number of different edge cases, such as if the last version crashed before
// it could save off a system profile or if UMA reporting is disabled (which
// normally results in stats being accumulated).
- if (!has_initial_stability_log && version_changed)
+ if (!has_initial_stability_log && version_changed) {
ClearSavedStabilityMetrics();
+ IncrementPrefValue(prefs::kStabilityDiscardCount);
+ }
// Update session ID.
++session_id_;
@@ -637,9 +654,6 @@ void MetricsService::InitializeMetricsState() {
}
void MetricsService::OnUserAction(const std::string& action) {
- if (!ShouldLogEvents())
- return;
-
log_manager_.current_log()->RecordUserAction(action);
HandleIdleSinceLastTransmission(false);
}
@@ -894,7 +908,8 @@ bool MetricsService::ProvidersHaveInitialStabilityMetrics() {
return false;
}
-bool MetricsService::PrepareInitialStabilityLog() {
+bool MetricsService::PrepareInitialStabilityLog(
+ const std::string& prefs_previous_version) {
DCHECK_EQ(INITIALIZED, state_);
std::unique_ptr<MetricsLog> initial_stability_log(
@@ -902,9 +917,13 @@ bool MetricsService::PrepareInitialStabilityLog() {
// Do not call NotifyOnDidCreateMetricsLog here because the stability
// log describes stats from the _previous_ session.
-
- if (!initial_stability_log->LoadSavedEnvironmentFromPrefs())
+ std::string system_profile_app_version;
+ if (!initial_stability_log->LoadSavedEnvironmentFromPrefs(
+ &system_profile_app_version)) {
return false;
+ }
+ if (system_profile_app_version != prefs_previous_version)
+ IncrementPrefValue(prefs::kStabilityVersionMismatchCount);
log_manager_.PauseCurrentLog();
log_manager_.BeginLoggingWithLog(std::move(initial_stability_log));
@@ -1070,6 +1089,33 @@ void MetricsService::RegisterSyntheticFieldTrial(
NotifySyntheticTrialObservers();
}
+void MetricsService::RegisterSyntheticMultiGroupFieldTrial(
+ uint32_t trial_name_hash,
+ const std::vector<uint32_t>& group_name_hashes) {
+ auto has_same_trial_name =
+ [trial_name_hash](const variations::SyntheticTrialGroup& x) {
+ return x.id.name == trial_name_hash;
+ };
+ synthetic_trial_groups_.erase(
+ std::remove_if(synthetic_trial_groups_.begin(),
+ synthetic_trial_groups_.end(), has_same_trial_name),
+ synthetic_trial_groups_.end());
+
+ if (group_name_hashes.empty())
+ return;
+
+ variations::SyntheticTrialGroup trial_group(trial_name_hash,
+ group_name_hashes[0]);
+ trial_group.start_time = base::TimeTicks::Now();
+ for (uint32_t group_name_hash : group_name_hashes) {
+ // Note: Adding the trial group will copy it, so this re-uses the same
+ // |trial_group| struct for convenience (e.g. so start_time's all match).
+ trial_group.id.group = group_name_hash;
+ synthetic_trial_groups_.push_back(trial_group);
+ }
+ NotifySyntheticTrialObservers();
+}
+
void MetricsService::GetCurrentSyntheticFieldTrialsForTesting(
std::vector<variations::ActiveGroupId>* synthetic_trials) {
GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(), synthetic_trials);
@@ -1105,9 +1151,8 @@ void MetricsService::GetSyntheticFieldTrialsOlderThan(
std::unique_ptr<MetricsLog> MetricsService::CreateLog(
MetricsLog::LogType log_type) {
- return base::WrapUnique(new MetricsLog(state_manager_->client_id(),
- session_id_, log_type, client_,
- local_state_));
+ return base::MakeUnique<MetricsLog>(state_manager_->client_id(), session_id_,
+ log_type, client_, local_state_);
}
void MetricsService::RecordCurrentEnvironment(MetricsLog* log) {
@@ -1121,32 +1166,24 @@ void MetricsService::RecordCurrentHistograms() {
DCHECK(log_manager_.current_log());
SCOPED_UMA_HISTOGRAM_TIMER("UMA.MetricsService.RecordCurrentHistograms.Time");
- // Merge any data from metrics providers into the global StatisticsRecorder.
- for (MetricsProvider* provider : metrics_providers_)
- provider->MergeHistogramDeltas();
-
- histogram_snapshot_manager_.StartDeltas();
// "true" to the begin() call indicates that StatisticsRecorder should include
// histograms held in persistent storage.
- histogram_snapshot_manager_.PrepareDeltasWithoutStartFinish(
+ histogram_snapshot_manager_.PrepareDeltas(
base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
for (MetricsProvider* provider : metrics_providers_)
provider->RecordHistogramSnapshots(&histogram_snapshot_manager_);
- histogram_snapshot_manager_.FinishDeltas();
}
void MetricsService::RecordCurrentStabilityHistograms() {
DCHECK(log_manager_.current_log());
- histogram_snapshot_manager_.StartDeltas();
// "true" indicates that StatisticsRecorder should include histograms in
// persistent storage.
- histogram_snapshot_manager_.PrepareDeltasWithoutStartFinish(
+ histogram_snapshot_manager_.PrepareDeltas(
base::StatisticsRecorder::begin(true), base::StatisticsRecorder::end(),
base::Histogram::kNoFlags, base::Histogram::kUmaStabilityHistogramFlag);
for (MetricsProvider* provider : metrics_providers_)
provider->RecordInitialHistogramSnapshots(&histogram_snapshot_manager_);
- histogram_snapshot_manager_.FinishDeltas();
}
void MetricsService::LogCleanShutdown() {
@@ -1160,13 +1197,6 @@ void MetricsService::LogCleanShutdown() {
MetricsService::SHUTDOWN_COMPLETE);
}
-bool MetricsService::ShouldLogEvents() {
- // We simply don't log events to UMA if there is a single incognito
- // session visible. The problem is that we always notify using the original
- // profile in order to simplify notification processing.
- return !client_->IsOffTheRecordSessionActive();
-}
-
void MetricsService::RecordBooleanPrefValue(const char* path, bool value) {
DCHECK(IsSingleThreaded());
local_state_->SetBoolean(path, value);
diff --git a/chromium/components/metrics/metrics_service.h b/chromium/components/metrics/metrics_service.h
index a1f4f63c5a6..3f19a5b3490 100644
--- a/chromium/components/metrics/metrics_service.h
+++ b/chromium/components/metrics/metrics_service.h
@@ -124,16 +124,6 @@ class MetricsService : public base::HistogramFlattener {
// Returns true if the last session exited cleanly.
bool WasLastShutdownClean() const;
- // Returns the preferred entropy provider used to seed persistent activities
- // based on whether or not metrics reporting will be permitted on this client.
- //
- // If metrics reporting is enabled, this method returns an entropy provider
- // that has a high source of entropy, partially based on the client ID.
- // Otherwise, it returns an entropy provider that is based on a low entropy
- // source.
- std::unique_ptr<const base::FieldTrial::EntropyProvider>
- CreateEntropyProvider();
-
// At startup, prefs needs to be called with a list of all the pref names and
// types we'll be using.
static void RegisterPrefs(PrefRegistrySimple* registry);
@@ -220,6 +210,9 @@ class MetricsService : public base::HistogramFlattener {
// from any thread, but this function should be called on UI thread.
UpdateUsagePrefCallbackType GetDataUseForwardingCallback();
+ // Merge any data from metrics providers into the global StatisticsRecorder.
+ void MergeHistogramDeltas();
+
protected:
// Exposed for testing.
MetricsLogManager* log_manager() { return &log_manager_; }
@@ -259,9 +252,18 @@ class MetricsService : public base::HistogramFlattener {
// registered at a time for a given trial_name. Only the last group name that
// is registered for a given trial name will be recorded. The values passed
// in must not correspond to any real field trial in the code.
+ // Note: Should not be used to replace trials that were registered with
+ // RegisterMultiGroupSyntheticFieldTrial().
void RegisterSyntheticFieldTrial(
const variations::SyntheticTrialGroup& trial_group);
+ // Similar to RegisterSyntheticFieldTrial(), but registers a synthetic trial
+ // that has multiple active groups for a given trial name hash. Any previous
+ // groups registered for |trial_name_hash| will be replaced.
+ void RegisterSyntheticMultiGroupFieldTrial(
+ uint32_t trial_name_hash,
+ const std::vector<uint32_t>& group_name_hashes);
+
// Calls into the client to initialize some system profile metrics.
void StartInitTask();
@@ -340,9 +342,10 @@ class MetricsService : public base::HistogramFlattener {
// Prepares the initial stability log, which is only logged when the previous
// run of Chrome crashed. This log contains any stability metrics left over
// from that previous run, and only these stability metrics. It uses the
- // system profile from the previous session. Returns true if a log was
- // created.
- bool PrepareInitialStabilityLog();
+ // system profile from the previous session. |prefs_previous_version| is used
+ // to validate the version number recovered from the system profile. Returns
+ // true if a log was created.
+ bool PrepareInitialStabilityLog(const std::string& prefs_previous_version);
// Prepares the initial metrics log, which includes startup histograms and
// profiler data, as well as incremental stability-related metrics.
@@ -368,9 +371,6 @@ class MetricsService : public base::HistogramFlattener {
// buffered plugin stability statistics.
void RecordCurrentState(PrefService* pref);
- // Checks whether events should currently be logged.
- bool ShouldLogEvents();
-
// Sets the value of the specified path in prefs and schedules a save.
void RecordBooleanPrefValue(const char* path, bool value);
@@ -482,6 +482,8 @@ class MetricsService : public base::HistogramFlattener {
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
PermutedEntropyCacheClearedWhenLowEntropyReset);
FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest, RegisterSyntheticTrial);
+ FRIEND_TEST_ALL_PREFIXES(MetricsServiceTest,
+ RegisterSyntheticMultiGroupFieldTrial);
// Pointer used for obtaining data use pref updater callback on above layers.
std::unique_ptr<DataUseTracker> data_use_tracker_;
diff --git a/chromium/components/metrics/metrics_service_accessor.cc b/chromium/components/metrics/metrics_service_accessor.cc
index ac04ba9884d..786895b40a1 100644
--- a/chromium/components/metrics/metrics_service_accessor.cc
+++ b/chromium/components/metrics/metrics_service_accessor.cc
@@ -16,20 +16,13 @@ namespace metrics {
// static
bool MetricsServiceAccessor::IsMetricsReportingEnabled(
PrefService* pref_service) {
- return IsMetricsReportingEnabledWithPrefValue(
- pref_service->GetBoolean(prefs::kMetricsReportingEnabled));
-}
-
-// static
-bool MetricsServiceAccessor::IsMetricsReportingEnabledWithPrefValue(
- bool enabled_in_prefs) {
#if defined(GOOGLE_CHROME_BUILD)
// In official builds, disable metrics when reporting field trials are
// forced; otherwise, use the value of the user's preference to determine
// whether to enable metrics reporting.
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kForceFieldTrials) &&
- enabled_in_prefs;
+ pref_service->GetBoolean(prefs::kMetricsReportingEnabled);
#else
// In non-official builds, disable metrics reporting completely.
return false;
@@ -46,6 +39,19 @@ bool MetricsServiceAccessor::RegisterSyntheticFieldTrial(
}
// static
+bool MetricsServiceAccessor::RegisterSyntheticMultiGroupFieldTrial(
+ MetricsService* metrics_service,
+ const std::string& trial_name,
+ const std::vector<uint32_t>& group_name_hashes) {
+ if (!metrics_service)
+ return false;
+
+ metrics_service->RegisterSyntheticMultiGroupFieldTrial(HashName(trial_name),
+ group_name_hashes);
+ return true;
+}
+
+// static
bool MetricsServiceAccessor::RegisterSyntheticFieldTrialWithNameHash(
MetricsService* metrics_service,
uint32_t trial_name_hash,
diff --git a/chromium/components/metrics/metrics_service_accessor.h b/chromium/components/metrics/metrics_service_accessor.h
index 8d34675b5fe..c4b5e62f195 100644
--- a/chromium/components/metrics/metrics_service_accessor.h
+++ b/chromium/components/metrics/metrics_service_accessor.h
@@ -7,6 +7,7 @@
#include <stdint.h>
#include <string>
+#include <vector>
#include "base/macros.h"
@@ -28,32 +29,28 @@ class MetricsServiceAccessor {
// Returns whether metrics reporting is enabled, using the value of the
// kMetricsReportingEnabled pref in |pref_service| to determine whether user
// has enabled reporting.
- // NOTE: This method currently does not return the correct value on ChromeOS
- // and Android due to http://crbug.com/362192 and http://crbug.com/532084. See
- // ChromeMetricsServiceAccessor::IsMetricsAndCrashReportingEnabled().
static bool IsMetricsReportingEnabled(PrefService* pref_service);
- // Returns whether metrics reporting is enabled, using the value of
- // |enabled_in_prefs| to determine whether the user has enabled reporting.
- // Exists because kMetricsReportingEnabled is currently not used on all
- // platforms.
- // TODO(gayane): Consolidate metric prefs on all platforms and eliminate this
- // method. http://crbug.com/362192, http://crbug.com/532084
- static bool IsMetricsReportingEnabledWithPrefValue(bool enabled_in_prefs);
// Registers a field trial name and group with |metrics_service| (if not
// null), to be used to annotate a UMA report with a particular configuration
- // state. A UMA report will be annotated with this trial group if and only if
- // all events in the report were created after the trial is registered. Only
- // one group name may be registered at a time for a given trial name. Only the
- // last group name that is registered for a given trial name will be recorded.
- // The values passed in must not correspond to any real field trial in the
- // code. Returns true on success.
- // See the comment on MetricsService::RegisterSyntheticFieldTrial for details.
+ // state. Returns true on success.
+ // See the comment on MetricsService::RegisterSyntheticFieldTrial() for
+ // details.
static bool RegisterSyntheticFieldTrial(MetricsService* metrics_service,
const std::string& trial_name,
const std::string& group_name);
+ // Registers a field trial name and set of groups with |metrics_service| (if
+ // not null), to be used to annotate a UMA report with a particular
+ // configuration state. Returns true on success.
+ // See the comment on MetricsService::RegisterSyntheticMultiGroupFieldTrial()
+ // for details.
+ static bool RegisterSyntheticMultiGroupFieldTrial(
+ MetricsService* metrics_service,
+ const std::string& trial_name,
+ const std::vector<uint32_t>& group_name_hashes);
+
// Same as RegisterSyntheticFieldTrial above, but takes in the trial name as a
// hash rather than computing the hash from the string.
static bool RegisterSyntheticFieldTrialWithNameHash(
diff --git a/chromium/components/metrics/metrics_service_client.h b/chromium/components/metrics/metrics_service_client.h
index 8624477d567..af4257784f5 100644
--- a/chromium/components/metrics/metrics_service_client.h
+++ b/chromium/components/metrics/metrics_service_client.h
@@ -41,13 +41,6 @@ class MetricsServiceClient {
// when metrics recording gets enabled.
virtual void SetMetricsClientId(const std::string& client_id) = 0;
- // Notifies the client that recording is disabled, so that other services
- // (such as crash reporting) can clear any association with metrics.
- virtual void OnRecordingDisabled() = 0;
-
- // Whether there's an "off the record" (aka "Incognito") session active.
- virtual bool IsOffTheRecordSessionActive() = 0;
-
// Returns the product value to use in uploaded reports, which will be used to
// set the ChromeUserMetricsExtension.product field. See comments on that
// field on why it's an int32_t rather than an enum.
diff --git a/chromium/components/metrics/metrics_service_unittest.cc b/chromium/components/metrics/metrics_service_unittest.cc
index 96e62f141c0..37dbbddbdbd 100644
--- a/chromium/components/metrics/metrics_service_unittest.cc
+++ b/chromium/components/metrics/metrics_service_unittest.cc
@@ -393,6 +393,53 @@ TEST_F(MetricsServiceTest, RegisterSyntheticTrial) {
service.log_manager_.FinishCurrentLog();
}
+TEST_F(MetricsServiceTest, RegisterSyntheticMultiGroupFieldTrial) {
+ TestMetricsServiceClient client;
+ MetricsService service(GetMetricsStateManager(), &client, GetLocalState());
+
+ // Register a synthetic trial TestTrial1 with groups A and B.
+ uint32_t trial_name_hash = HashName("TestTrial1");
+ std::vector<uint32_t> group_name_hashes = {HashName("A"), HashName("B")};
+ service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
+ group_name_hashes);
+ // Ensure that time has advanced by at least a tick before proceeding.
+ WaitUntilTimeChanges(base::TimeTicks::Now());
+
+ service.log_manager_.BeginLoggingWithLog(std::unique_ptr<MetricsLog>(
+ new MetricsLog("clientID", 1, MetricsLog::INITIAL_STABILITY_LOG, &client,
+ GetLocalState())));
+
+ std::vector<variations::ActiveGroupId> synthetic_trials;
+ service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
+ &synthetic_trials);
+ EXPECT_EQ(2U, synthetic_trials.size());
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "A"));
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "B"));
+
+ // Change the group for the trial to a single group.
+ group_name_hashes = {HashName("X")};
+ service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
+ group_name_hashes);
+ // Ensure that time has advanced by at least a tick before proceeding.
+ WaitUntilTimeChanges(base::TimeTicks::Now());
+
+ service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
+ &synthetic_trials);
+ EXPECT_EQ(1U, synthetic_trials.size());
+ EXPECT_TRUE(HasSyntheticTrial(synthetic_trials, "TestTrial1", "X"));
+
+ // Register a trial with no groups, which should effectively remove the trial.
+ group_name_hashes.clear();
+ service.RegisterSyntheticMultiGroupFieldTrial(trial_name_hash,
+ group_name_hashes);
+ // Ensure that time has advanced by at least a tick before proceeding.
+ WaitUntilTimeChanges(base::TimeTicks::Now());
+
+ service.GetSyntheticFieldTrialsOlderThan(base::TimeTicks::Now(),
+ &synthetic_trials);
+ service.log_manager_.FinishCurrentLog();
+}
+
TEST_F(MetricsServiceTest,
MetricsProviderOnRecordingDisabledCalledOnInitialStop) {
TestMetricsServiceClient client;
diff --git a/chromium/components/metrics/metrics_state_manager.cc b/chromium/components/metrics/metrics_state_manager.cc
index cf1b4a126ab..4cae20d3ae7 100644
--- a/chromium/components/metrics/metrics_state_manager.cc
+++ b/chromium/components/metrics/metrics_state_manager.cc
@@ -83,10 +83,15 @@ bool MetricsStateManager::IsMetricsReportingEnabled() {
}
void MetricsStateManager::ForceClientIdCreation() {
- if (!client_id_.empty())
- return;
+ {
+ std::string client_id_from_prefs =
+ local_state_->GetString(prefs::kMetricsClientID);
+ // If client id in prefs matches the cached copy, return early.
+ if (!client_id_from_prefs.empty() && client_id_from_prefs == client_id_)
+ return;
+ client_id_.swap(client_id_from_prefs);
+ }
- client_id_ = local_state_->GetString(prefs::kMetricsClientID);
if (!client_id_.empty()) {
// It is technically sufficient to only save a backup of the client id when
// it is initially generated below, but since the backup was only introduced
@@ -256,8 +261,10 @@ MetricsStateManager::LoadClientInfoAndMaybeMigrate() {
}
// The GUID retrieved (and possibly fixed above) should be valid unless
- // retrieval failed.
- DCHECK(!client_info || base::IsValidGUID(client_info->client_id));
+ // retrieval failed. If not, return nullptr. This will result in a new GUID
+ // being generated by the calling function ForceClientIdCreation().
+ if (client_info && !base::IsValidGUID(client_info->client_id))
+ return nullptr;
return client_info;
}
diff --git a/chromium/components/metrics/net/cellular_logic_helper.cc b/chromium/components/metrics/net/cellular_logic_helper.cc
index 3651e878cdc..33b351e0a4d 100644
--- a/chromium/components/metrics/net/cellular_logic_helper.cc
+++ b/chromium/components/metrics/net/cellular_logic_helper.cc
@@ -4,7 +4,6 @@
#include "components/metrics/net/cellular_logic_helper.h"
-#include "components/variations/variations_associated_data.h"
#include "net/base/network_change_notifier.h"
namespace metrics {
@@ -21,10 +20,8 @@ const int kStandardUploadIntervalSeconds = 30 * 60; // Thirty minutes.
#if defined(OS_ANDROID)
const bool kDefaultCellularLogicEnabled = true;
-const bool kDefaultCellularLogicOptimization = true;
#else
const bool kDefaultCellularLogicEnabled = false;
-const bool kDefaultCellularLogicOptimization = false;
#endif
} // namespace
@@ -37,22 +34,10 @@ base::TimeDelta GetUploadInterval() {
return base::TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
}
-// Returns true if current connection type is cellular and user is assigned to
-// experimental group for enabled cellular uploads.
+// Returns true if current connection type is cellular and cellular logic is
+// enabled.
bool IsCellularLogicEnabled() {
- std::string enabled = variations::GetVariationParamValue(
- "UMA_EnableCellularLogUpload", "Enabled");
- std::string optimized = variations::GetVariationParamValue(
- "UMA_EnableCellularLogUpload", "Optimize");
- bool is_enabled = kDefaultCellularLogicEnabled;
- if (!enabled.empty())
- is_enabled = (enabled == "true");
-
- bool is_optimized = kDefaultCellularLogicOptimization;
- if (!optimized.empty())
- is_optimized = (optimized == "true");
-
- if (!is_enabled || !is_optimized)
+ if (!kDefaultCellularLogicEnabled)
return false;
return net::NetworkChangeNotifier::IsConnectionCellular(
diff --git a/chromium/components/metrics/persisted_logs.cc b/chromium/components/metrics/persisted_logs.cc
index 52292da55cc..12d3a682188 100644
--- a/chromium/components/metrics/persisted_logs.cc
+++ b/chromium/components/metrics/persisted_logs.cc
@@ -4,12 +4,15 @@
#include "components/metrics/persisted_logs.h"
+#include <memory>
#include <string>
+#include <utility>
#include "base/base64.h"
#include "base/md5.h"
#include "base/metrics/histogram_macros.h"
#include "base/sha1.h"
+#include "base/strings/string_number_conversions.h"
#include "base/timer/elapsed_timer.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
@@ -19,6 +22,10 @@ namespace metrics {
namespace {
+const char kLogHashKey[] = "hash";
+const char kLogTimestampKey[] = "timestamp";
+const char kLogDataKey[] = "data";
+
PersistedLogs::LogReadStatus MakeRecallStatusHistogram(
PersistedLogs::LogReadStatus status) {
UMA_HISTOGRAM_ENUMERATION("PrefService.PersistentLogRecallProtobufs",
@@ -37,16 +44,22 @@ bool ReadBase64String(const base::ListValue& list_value,
return base::Base64Decode(base64_result, result);
}
-// Base64-encodes |str| and appends the result to |list_value|.
-void AppendBase64String(const std::string& str, base::ListValue* list_value) {
- std::string base64_str;
- base::Base64Encode(str, &base64_str);
- list_value->AppendString(base64_str);
+std::string EncodeToBase64(const std::string& to_convert) {
+ std::string base64_result;
+ base::Base64Encode(to_convert, &base64_result);
+ return base64_result;
+}
+
+std::string DecodeFromBase64(const std::string& to_convert) {
+ std::string result;
+ base::Base64Decode(to_convert, &result);
+ return result;
}
} // namespace
-void PersistedLogs::LogHashPair::Init(const std::string& log_data) {
+void PersistedLogs::LogInfo::Init(const std::string& log_data,
+ const std::string& log_timestamp) {
DCHECK(!log_data.empty());
if (!compression::GzipCompress(log_data, &compressed_log_data)) {
@@ -59,15 +72,18 @@ void PersistedLogs::LogHashPair::Init(const std::string& log_data) {
static_cast<int>(100 * compressed_log_data.size() / log_data.size()));
hash = base::SHA1HashString(log_data);
+ timestamp = log_timestamp;
}
PersistedLogs::PersistedLogs(PrefService* local_state,
const char* pref_name,
+ const char* outdated_pref_name,
size_t min_log_count,
size_t min_log_bytes,
size_t max_log_size)
: local_state_(local_state),
pref_name_(pref_name),
+ outdated_pref_name_(outdated_pref_name),
min_log_count_(min_log_count),
min_log_bytes_(min_log_bytes),
max_log_size_(max_log_size != 0 ? max_log_size : static_cast<size_t>(-1)),
@@ -82,15 +98,26 @@ PersistedLogs::~PersistedLogs() {}
void PersistedLogs::SerializeLogs() const {
ListPrefUpdate update(local_state_, pref_name_);
WriteLogsToPrefList(update.Get());
+
+ // After writing all the logs to the new pref remove old outdated pref.
+ // TODO(gayane): Remove when all users are migrated. crbug.com/649440
+ if (local_state_->HasPrefPath(outdated_pref_name_))
+ local_state_->ClearPref(outdated_pref_name_);
}
PersistedLogs::LogReadStatus PersistedLogs::DeserializeLogs() {
+ // TODO(gayane): Remove the code for reading logs from outdated pref when all
+ // users are migrated. crbug.com/649440
+ if (local_state_->HasPrefPath(outdated_pref_name_)) {
+ return ReadLogsFromOldFormatPrefList(
+ *local_state_->GetList(outdated_pref_name_));
+ }
return ReadLogsFromPrefList(*local_state_->GetList(pref_name_));
}
void PersistedLogs::StoreLog(const std::string& log_data) {
- list_.push_back(LogHashPair());
- list_.back().Init(log_data);
+ list_.push_back(LogInfo());
+ list_.back().Init(log_data, base::Int64ToString(base::Time::Now().ToTimeT()));
}
void PersistedLogs::StageLog() {
@@ -109,6 +136,38 @@ void PersistedLogs::DiscardStagedLog() {
staged_log_index_ = -1;
}
+PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromPrefList(
+ const base::ListValue& list_value) {
+ if (list_value.empty())
+ return MakeRecallStatusHistogram(LIST_EMPTY);
+
+ const size_t log_count = list_value.GetSize();
+
+ DCHECK(list_.empty());
+ list_.resize(log_count);
+
+ for (size_t i = 0; i < log_count; ++i) {
+ const base::DictionaryValue* dict;
+ if (!list_value.GetDictionary(i, &dict) ||
+ !dict->GetString(kLogDataKey, &list_[i].compressed_log_data) ||
+ !dict->GetString(kLogHashKey, &list_[i].hash)) {
+ list_.clear();
+ return MakeRecallStatusHistogram(LOG_STRING_CORRUPTION);
+ }
+
+ list_[i].compressed_log_data =
+ DecodeFromBase64(list_[i].compressed_log_data);
+ list_[i].hash = DecodeFromBase64(list_[i].hash);
+ // Ignoring the success of this step as timestamp might not be there for
+ // older logs.
+ // NOTE: Should be added to the check with other fields once migration is
+ // over.
+ dict->GetString(kLogTimestampKey, &list_[i].timestamp);
+ }
+
+ return MakeRecallStatusHistogram(RECALL_SUCCESS);
+}
+
void PersistedLogs::WriteLogsToPrefList(base::ListValue* list_value) const {
list_value->Clear();
@@ -140,14 +199,19 @@ void PersistedLogs::WriteLogsToPrefList(base::ListValue* list_value) const {
dropped_logs_num++;
continue;
}
- AppendBase64String(list_[i].compressed_log_data, list_value);
- AppendBase64String(list_[i].hash, list_value);
+ std::unique_ptr<base::DictionaryValue> dict_value(
+ new base::DictionaryValue);
+ dict_value->SetString(kLogHashKey, EncodeToBase64(list_[i].hash));
+ dict_value->SetString(kLogDataKey,
+ EncodeToBase64(list_[i].compressed_log_data));
+ dict_value->SetString(kLogTimestampKey, list_[i].timestamp);
+ list_value->Append(std::move(dict_value));
}
if (dropped_logs_num > 0)
UMA_HISTOGRAM_COUNTS("UMA.UnsentLogs.Dropped", dropped_logs_num);
}
-PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromPrefList(
+PersistedLogs::LogReadStatus PersistedLogs::ReadLogsFromOldFormatPrefList(
const base::ListValue& list_value) {
if (list_value.empty())
return MakeRecallStatusHistogram(LIST_EMPTY);
diff --git a/chromium/components/metrics/persisted_logs.h b/chromium/components/metrics/persisted_logs.h
index 73ad79a5b06..479924fd0fd 100644
--- a/chromium/components/metrics/persisted_logs.h
+++ b/chromium/components/metrics/persisted_logs.h
@@ -51,6 +51,7 @@ class PersistedLogs {
// that limit will be skipped when writing to disk.
PersistedLogs(PrefService* local_state,
const char* pref_name,
+ const char* outdated_pref_name,
size_t min_log_count,
size_t min_log_bytes,
size_t max_log_size);
@@ -87,6 +88,12 @@ class PersistedLogs {
return list_[staged_log_index_].hash;
}
+ // Returns the timestamp of the element in the front of the list.
+ const std::string& staged_log_timestamp() const {
+ DCHECK(has_staged_log());
+ return list_[staged_log_index_].timestamp;
+ }
+
// The number of elements currently stored.
size_t size() const { return list_.size(); }
@@ -100,6 +107,9 @@ class PersistedLogs {
// Reads the list from the ListValue.
LogReadStatus ReadLogsFromPrefList(const base::ListValue& list);
+ // Reads the list from the ListValue in the old Log-hash pair format.
+ LogReadStatus ReadLogsFromOldFormatPrefList(const base::ListValue& list);
+
// A weak pointer to the PrefService object to read and write the preference
// from. Calling code should ensure this object continues to exist for the
// lifetime of the PersistedLogs object.
@@ -108,6 +118,10 @@ class PersistedLogs {
// The name of the preference to serialize logs to/from.
const char* pref_name_;
+ // The name of the preference to serialize logs to/from which may contain log
+ // in the old formatting.
+ const char* outdated_pref_name_;
+
// We will keep at least this |min_log_count_| logs or |min_log_bytes_| bytes
// of logs, whichever is greater, when writing to disk. These apply after
// skipping logs greater than |max_log_size_|.
@@ -117,19 +131,23 @@ class PersistedLogs {
// Logs greater than this size will not be written to disk.
const size_t max_log_size_;
- struct LogHashPair {
- // Initializes the members based on uncompressed |log_data|.
- void Init(const std::string& log_data);
+ struct LogInfo {
+ // Initializes the members based on uncompressed |log_data| and
+ // |log_timestamp|.
+ void Init(const std::string& log_data, const std::string& log_timestamp);
// Compressed log data - a serialized protobuf that's been gzipped.
std::string compressed_log_data;
// The SHA1 hash of log, stored to catch errors from memory corruption.
std::string hash;
+
+ // The timestamp of when the log was created as a time_t value.
+ std::string timestamp;
};
// A list of all of the stored logs, stored with SHA1 hashes to check for
// corruption while they are stored in memory.
- std::vector<LogHashPair> list_;
+ std::vector<LogInfo> list_;
// The index and type of the log staged for upload. If nothing has been
// staged, the index will be -1.
diff --git a/chromium/components/metrics/persisted_logs_unittest.cc b/chromium/components/metrics/persisted_logs_unittest.cc
index b4a79a73ea6..94b8b7e97de 100644
--- a/chromium/components/metrics/persisted_logs_unittest.cc
+++ b/chromium/components/metrics/persisted_logs_unittest.cc
@@ -22,6 +22,7 @@ namespace metrics {
namespace {
const char kTestPrefName[] = "TestPref";
+const char kTestOutdatedPrefName[] = "OutdatedTestPref";
const size_t kLogCountLimit = 3;
const size_t kLogByteLimit = 1000;
@@ -63,9 +64,12 @@ class PersistedLogsTest : public testing::Test {
class TestPersistedLogs : public PersistedLogs {
public:
TestPersistedLogs(PrefService* service, size_t min_log_bytes)
- : PersistedLogs(service, kTestPrefName, kLogCountLimit, min_log_bytes,
- 0) {
- }
+ : PersistedLogs(service,
+ kTestPrefName,
+ kTestOutdatedPrefName,
+ kLogCountLimit,
+ min_log_bytes,
+ 0) {}
// Stages and removes the next log, while testing it's value.
void ExpectNextLog(const std::string& expected_log) {
@@ -111,6 +115,8 @@ TEST_F(PersistedLogsTest, SingleElementLogList) {
EXPECT_EQ(persisted_logs.staged_log(), result_persisted_logs.staged_log());
EXPECT_EQ(persisted_logs.staged_log_hash(),
result_persisted_logs.staged_log_hash());
+ EXPECT_EQ(persisted_logs.staged_log_timestamp(),
+ result_persisted_logs.staged_log_timestamp());
}
// Store a set of logs over the length limit, but smaller than the min number of
diff --git a/chromium/components/metrics/profiler/profiler_metrics_provider.cc b/chromium/components/metrics/profiler/profiler_metrics_provider.cc
index df64e293aee..2ab8c0314f6 100644
--- a/chromium/components/metrics/profiler/profiler_metrics_provider.cc
+++ b/chromium/components/metrics/profiler/profiler_metrics_provider.cc
@@ -107,7 +107,8 @@ void ProfilerMetricsProvider::RecordProfilerData(
if (IsCellularLogicEnabled())
return;
- const bool new_phase = !ContainsKey(profiler_events_cache_, profiling_phase);
+ const bool new_phase =
+ !base::ContainsKey(profiler_events_cache_, profiling_phase);
ProfilerEventProto* profiler_event = &profiler_events_cache_[profiling_phase];
if (new_phase) {
diff --git a/chromium/components/metrics/profiler/tracking_synchronizer.cc b/chromium/components/metrics/profiler/tracking_synchronizer.cc
index 21ccb85f532..1dc8fa75db4 100644
--- a/chromium/components/metrics/profiler/tracking_synchronizer.cc
+++ b/chromium/components/metrics/profiler/tracking_synchronizer.cc
@@ -9,7 +9,7 @@
#include "base/bind.h"
#include "base/callback.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/threading/thread.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/tracked_objects.h"
diff --git a/chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc b/chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc
index 016315caf46..cae6cb208fe 100644
--- a/chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc
+++ b/chromium/components/metrics/profiler/tracking_synchronizer_unittest.cc
@@ -120,8 +120,8 @@ class TestTrackingSynchronizer : public TrackingSynchronizer {
TEST(TrackingSynchronizerTest, ProfilerData) {
// Testing how TrackingSynchronizer reports 2 phases of profiling.
- auto clock = new base::SimpleTestTickClock(); // Will be owned by
- // |tracking_synchronizer|.
+ auto* clock = new base::SimpleTestTickClock(); // Will be owned by
+ // |tracking_synchronizer|.
clock->Advance(base::TimeDelta::FromMilliseconds(111));
scoped_refptr<TestTrackingSynchronizer> tracking_synchronizer =
diff --git a/chromium/components/metrics/proto/BUILD.gn b/chromium/components/metrics/proto/BUILD.gn
index 3271f184cdf..0afdeea21b7 100644
--- a/chromium/components/metrics/proto/BUILD.gn
+++ b/chromium/components/metrics/proto/BUILD.gn
@@ -4,12 +4,12 @@
import("//third_party/protobuf/proto_library.gni")
-# GYP version: components/
proto_library("proto") {
sources = [
"call_stack_profile.proto",
"cast_logs.proto",
"chrome_user_metrics_extension.proto",
+ "execution_context.proto",
"histogram_event.proto",
"memory_leak_report.proto",
"omnibox_event.proto",
diff --git a/chromium/components/metrics/proto/cast_logs.proto b/chromium/components/metrics/proto/cast_logs.proto
index 951dfb24767..987c4f5dde6 100644
--- a/chromium/components/metrics/proto/cast_logs.proto
+++ b/chromium/components/metrics/proto/cast_logs.proto
@@ -22,6 +22,7 @@ message CastLogsProto {
enum CastProductType {
CAST_PRODUCT_TYPE_UNKNOWN = 0;
CAST_PRODUCT_TYPE_CHROMECAST = 1;
+ CAST_PRODUCT_TYPE_TV = 2;
CAST_PRODUCT_TYPE_AUDIO = 3;
CAST_PRODUCT_TYPE_ANDROID_TV = 4;
}
@@ -50,7 +51,7 @@ message CastLogsProto {
// This message describes a detail sender device and sdk. Those are
// parsed from the user agent string sent from sender sdk during connection.
- // Next tag: 9
+ // Next tag: 10
message SenderInfo {
// The identifier for the sender device, that is not tied any kind of
// device id outside of UMA, and this id is reset when user resets sender
@@ -107,6 +108,11 @@ message CastLogsProto {
// Sender device model.
optional string model = 8;
+
+ // Last 2 bytes of the sender’s local IP addresses (both IP4/IP6) when
+ // the sender connected. This field stores ip fragment to last 2 bytes and
+ // first 2 bytes won't be used.
+ optional int32 sender_local_ip_fragment = 9;
}
optional SenderInfo sender_info = 3;
}
@@ -115,7 +121,7 @@ message CastLogsProto {
repeated CastConnectionInfo cast_connection_info = 2;
// Stores Cast-enabled device specific events with a various context data.
- // Next tag: 10
+ // Next tag: 12
message CastEventProto {
// The name of the action, hashed by same logic used to hash user action
// event and histogram.
@@ -147,6 +153,10 @@ message CastLogsProto {
// An optional value for the multi-room group uuid.
optional fixed64 group_uuid = 10;
+
+ // For application events associated with an assistant session, identifies
+ // the assistant conversation.
+ optional string conversation_key = 11;
}
repeated CastEventProto cast_event = 3;
@@ -173,6 +183,10 @@ message CastLogsProto {
// System version which the cast_shell is running.
optional fixed64 system_build_number = 2;
+
+ // An identifier that is specific to the combination of app and device, in
+ // this case the one used by backdrop.
+ optional string backdrop_app_device_id = 3;
}
optional CastDeviceMutableInfo cast_device_mutable_info = 5;
diff --git a/chromium/components/metrics/proto/chrome_user_metrics_extension.proto b/chromium/components/metrics/proto/chrome_user_metrics_extension.proto
index 8b82933ab77..4b9bf68be16 100644
--- a/chromium/components/metrics/proto/chrome_user_metrics_extension.proto
+++ b/chromium/components/metrics/proto/chrome_user_metrics_extension.proto
@@ -31,6 +31,9 @@ message ChromeUserMetricsExtension {
// UMA metrics from Android Webview.
ANDROID_WEBVIEW = 20;
+
+ // Cast receivers, e.g. Chromecast
+ CAST = 35;
}
// The product corresponding to this log. The field type is int32 instead of
// Product so that downstream users of the Chromium metrics component can
diff --git a/chromium/components/metrics/proto/execution_context.proto b/chromium/components/metrics/proto/execution_context.proto
new file mode 100644
index 00000000000..3d8679fe9db
--- /dev/null
+++ b/chromium/components/metrics/proto/execution_context.proto
@@ -0,0 +1,49 @@
+// Copyright 2016 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.
+
+syntax = "proto2";
+
+option optimize_for = LITE_RUNTIME;
+option java_outer_classname = "ExecutionContextProtos";
+option java_package = "org.chromium.components.metrics";
+
+package metrics;
+
+// Enums corresponding to the Chrome execution context in which data was
+// collected.
+
+// Chrome process type. Derived from content/public/common/process_type.h.
+enum Process {
+ UNKNOWN_PROCESS = 0;
+ BROWSER_PROCESS = 1;
+ RENDERER_PROCESS = 2;
+ GPU_PROCESS = 3;
+ UTILITY_PROCESS = 4;
+ ZYGOTE_PROCESS = 5;
+ SANDBOX_HELPER_PROCESS = 6;
+ PPAPI_PLUGIN_PROCESS = 7;
+ PPAPI_BROKER_PROCESS = 8;
+}
+
+// Chrome thread. This list is not exhaustive.
+enum Thread {
+ UNKNOWN_THREAD = 0;
+
+ // Browser process threads from content/public/browser/browser_thread.h,
+ // some of which occur in other processes as well.
+ UI_THREAD = 1;
+ FILE_THREAD = 2;
+ FILE_USER_BLOCKING_THREAD = 3;
+ PROCESS_LAUNCHER_THREAD = 4;
+ CACHE_THREAD = 5;
+ IO_THREAD = 6;
+ DB_THREAD = 7;
+
+ // GPU process thread.
+ GPU_MAIN_THREAD = 8;
+
+ // Renderer process threads.
+ RENDER_THREAD = 9;
+ UTILITY_THREAD = 10;
+}
diff --git a/chromium/components/metrics/proto/memory_leak_report.proto b/chromium/components/metrics/proto/memory_leak_report.proto
index bbd2dbc7a66..1a998fefa0b 100644
--- a/chromium/components/metrics/proto/memory_leak_report.proto
+++ b/chromium/components/metrics/proto/memory_leak_report.proto
@@ -8,7 +8,7 @@ option optimize_for = LITE_RUNTIME;
package metrics;
-// Next tag: 6
+// Next tag: 10
message MemoryLeakReportProto {
// The call stack at which the leak was found. This is a list of offsets
// within the program binary. The first entry is the deepest level of the call
@@ -69,6 +69,12 @@ message MemoryLeakReportProto {
}
optional ProcessType source_process = 5;
+ // The build ID of the Chrome binary from which this leak report was obtained.
+ // The build ID is typically a 16- or 20-byte hash that is generated by the
+ // compiler that built the binary. This value will be read directly from the
+ // GNU build notes section of the Chrome binary.
+ optional bytes build_id = 6;
+
//////////////////////////////////////////////////////////////////////////////
// Represents a single snapshot of the internal bookkeeping of the Runtime
@@ -96,4 +102,39 @@ message MemoryLeakReportProto {
// allocation. The oldest record is at the beginning. The most recent record,
// taken at the time the report was generated, is at the end.
repeated AllocationBreakdown alloc_breakdown_history = 4;
+
+ // The following two fields describe the last increasing trend in the number
+ // of allocations from the size and call stack that generated this
+ // leak report.
+ //
+ // |num_rising_intervals| equals timeslot_now - timeslot_drop,
+ // where timeslot_drop is the timeslot number of the last frame that saw
+ // a drop in the number of allocations (or 0 if there were no drops).
+ // If it is < 32, it will be visible in the allocation history graph.
+ // If it is >= 32, it will not be seen in the graph.
+ // E.g. for history [3,2,4,4,7] |num_rising_intervals| equals 3.
+ optional uint32 num_rising_intervals = 7;
+
+ // Indicates the magnitude of the current uptrend in allocations.
+ // E.g. for history [3,2,4,4,7] |num_allocs_increase| equals 5.
+ optional uint32 num_allocs_increase = 8;
+
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Contains additional data about the memory usage from the OS.
+ // There is no need to store the total system memory as it is
+ // available under SystemProfileProto::Hardware::system_ram_mb.
+ //
+ // Next tag: 3
+ message MemoryUsageInfo {
+ // How much available physical memory the system has.
+ optional uint64 available_ram_mb = 1;
+
+ // Total private working set memory across all Chrome processes.
+ optional uint64 chrome_ram_usage_mb = 2;
+ }
+
+ // Information about the memory usage from the OS collected right after
+ // the leak report was created in the leak detector.
+ optional MemoryUsageInfo memory_usage_info = 9;
}
diff --git a/chromium/components/metrics/proto/omnibox_event.proto b/chromium/components/metrics/proto/omnibox_event.proto
index 5d4f7199657..2f8f24da94f 100644
--- a/chromium/components/metrics/proto/omnibox_event.proto
+++ b/chromium/components/metrics/proto/omnibox_event.proto
@@ -111,10 +111,8 @@ message OmniboxEventProto {
// The instant new tab page enum value was deprecated on August 2, 2013.
OBSOLETE_INSTANT_NTP = 5;
- // The user is on a search result page that's doing search term
- // replacement, meaning the search terms should've appeared in the omnibox
- // before the user started editing it, not the URL of the page.
- SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT = 6;
+ // The search term replacement enum value was deprecated in August 2016.
+ OBSOLETE_SEARCH_RESULT_PAGE_DOING_SEARCH_TERM_REPLACEMENT = 6;
// The new tab page in which this omnibox interaction first started
// with the user having focus in the omnibox.
@@ -168,6 +166,8 @@ message OmniboxEventProto {
// a suggestion powered by a Chrome content provider.
ON_DEVICE_CHROME = 13;
CLIPBOARD_URL = 14; // Suggestion coming from clipboard (iOS only).
+ PHYSICAL_WEB = 15; // Suggestions triggered by URLs broadcast by nearby
+ // devices (iOS only).
}
// The result set displayed on the completion popup
@@ -226,6 +226,9 @@ message OmniboxEventProto {
// suggestions of any type.
CALCULATOR = 23; // A calculator answer.
CLIPBOARD = 24; // An URL based on the clipboard.
+ PHYSICAL_WEB = 25; // A Physical Web nearby URL.
+ PHYSICAL_WEB_OVERFLOW = 26; // An item representing multiple Physical
+ // Web nearby URLs.
}
optional ResultType result_type = 2;
diff --git a/chromium/components/metrics/proto/sampled_profile.proto b/chromium/components/metrics/proto/sampled_profile.proto
index b8936e114c6..0d8fcae42b5 100644
--- a/chromium/components/metrics/proto/sampled_profile.proto
+++ b/chromium/components/metrics/proto/sampled_profile.proto
@@ -11,13 +11,14 @@ option java_package = "org.chromium.components.metrics";
package metrics;
import "call_stack_profile.proto";
+import "execution_context.proto";
import "perf_data.proto";
import "perf_stat.proto";
// Protocol buffer for collected sample-based profiling data.
// Contains the parameters and data from a single profile collection event.
-// Next tag: 11
+// Next tag: 13
message SampledProfile {
// Indicates the event that triggered this collection.
enum TriggerEvent {
@@ -35,7 +36,7 @@ message SampledProfile {
// The profile was collected upon restoring a previous session.
RESTORE_SESSION = 3;
-
+
// The profile was collected at process startup.
PROCESS_STARTUP = 4;
@@ -47,6 +48,12 @@ message SampledProfile {
}
optional TriggerEvent trigger_event = 1;
+ // The process in which the profile was collected.
+ optional Process process = 11;
+
+ // The thread in which the profile was collected.
+ optional Thread thread = 12;
+
// Fields 2-3: Time durations are given in ticks, and represent system uptime
// rather than wall time.
diff --git a/chromium/components/metrics/proto/system_profile.proto b/chromium/components/metrics/proto/system_profile.proto
index d814b3597fe..c116a0a1d19 100644
--- a/chromium/components/metrics/proto/system_profile.proto
+++ b/chromium/components/metrics/proto/system_profile.proto
@@ -440,7 +440,7 @@ message SystemProfileProto {
// Figures that can be used to generate application stability metrics.
// All values are counts of events since the last time that these
// values were reported.
- // Next tag: 26
+ // Next tag: 28
message Stability {
// Total amount of time that the program was running, in seconds,
// since the last time a log was recorded, as measured using a client-side
@@ -458,17 +458,19 @@ message SystemProfileProto {
// This field was added for M-35.
optional int64 uptime_sec = 23;
- // Page loads along with renderer crashes, hangs and failed launches, since
- // page load count roughly corresponds to usage.
+ // Page loads along with renderer launches, crashes, hangs and failed
+ // launches, since page load count roughly corresponds to usage.
optional int32 page_load_count = 2;
optional int32 renderer_crash_count = 3;
optional int32 renderer_hang_count = 4;
optional int32 renderer_failed_launch_count = 24;
+ optional int32 renderer_launch_count = 26;
- // Number of renderer crashes and failed launches that were for extensions.
- // These are not counted in the renderer counts above.
+ // Number of renderer launches, crashes and failed launches that were for
+ // extensions. These are not counted in the renderer counts above.
optional int32 extension_renderer_crash_count = 5;
optional int32 extension_renderer_failed_launch_count = 25;
+ optional int32 extension_renderer_launch_count = 27;
// Number of non-renderer child process crashes.
optional int32 child_process_crash_count = 6;
@@ -602,10 +604,10 @@ message SystemProfileProto {
// be consistent between manufacturers.
optional int32 manufacture_week = 6;
- // Max horizontal resolution in pixels.
+ // Selected horizontal resolution in pixels.
optional int32 horizontal_resolution = 7;
- // Max vertical resolution in pixels.
+ // Selected vertical resolution in pixels.
optional int32 vertical_resolution = 8;
// Audio capabilities of the device.
@@ -651,7 +653,6 @@ message SystemProfileProto {
DIGITAL = 1;
}
optional OutputMode output_mode = 6;
-
}
repeated AudioDescription audio_description = 9;
@@ -704,6 +705,50 @@ message SystemProfileProto {
optional int32 num_aborted_unrecognized = 7;
}
repeated CECCommand cec_command = 13;
+
+ // Selected Frame rate
+ optional int32 frame_rate = 14;
+
+ // Selected color encoding.
+ enum ColorEncoding {
+ COLOR_ENCODING_UNKNOWN = 0;
+ COLOR_ENCODING_RGB = 1;
+ COLOR_ENCODING_YUV444 = 2;
+ COLOR_ENCODING_YUV422 = 3;
+ COLOR_ENCODING_YUV420 = 4;
+ }
+ optional ColorEncoding color_encoding = 15;
+
+ // Selected bit-depth.
+ optional int32 bit_depth = 16;
+
+ // Devices's max TMDS char rate.
+ optional int32 tmds = 17;
+
+ // HDR10 support.
+ optional bool hdr10_support = 18;
+
+ // Dolby vision support.
+ optional bool dolby_vision_support = 19;
+
+ // Supported EOTFs.
+ // EOTF support according to the spec:
+ // eotf_support & 0x1 -> SDR supported
+ // (eotf_support > 1) & 0x1 -> traditional HDR supported
+ // (eotf_support > 2) & 0x1 -> ST2084 supported
+ optional int32 eotf_support = 20;
+
+ // Supports YUV.
+ optional bool yuv_support = 21;
+
+ // Supports YUV_420.
+ optional bool yuv_420_support = 22;
+
+ // The maximum HDCP version supported by the sink.
+ optional int32 maximum_supported_hdcp_version = 23;
+
+ // The current HDCP version negotiated with the sink.
+ optional int32 current_hdcp_version = 24;
}
repeated ExternalAudioVideoDevice external_audio_video_device = 14;
diff --git a/chromium/components/metrics/public/cpp/BUILD.gn b/chromium/components/metrics/public/cpp/BUILD.gn
new file mode 100644
index 00000000000..ca2f05741c0
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/BUILD.gn
@@ -0,0 +1,19 @@
+# Copyright 2016 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+source_set("call_stack_unit_tests") {
+ testonly = true
+ sources = [
+ "call_stack_profile_struct_traits_unittest.cc",
+ ]
+
+ deps = [
+ "//base",
+ "//components/metrics/public/interfaces:call_stack_mojo_test_bindings",
+ "//mojo/public/cpp/bindings",
+ "//testing/gtest",
+ ]
+}
diff --git a/chromium/components/metrics/public/cpp/OWNERS b/chromium/components/metrics/public/cpp/OWNERS
new file mode 100644
index 00000000000..154435234ea
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/OWNERS
@@ -0,0 +1,4 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/metrics/public/cpp/call_stack_profile.typemap b/chromium/components/metrics/public/cpp/call_stack_profile.typemap
new file mode 100644
index 00000000000..a12ba83f473
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/call_stack_profile.typemap
@@ -0,0 +1,26 @@
+# Copyright 2016 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.
+
+mojom =
+ "//components/metrics/public/interfaces/call_stack_profile_collector.mojom"
+public_headers = [
+ "//base/profiler/stack_sampling_profiler.h",
+ "//components/metrics/call_stack_profile_params.h",
+]
+traits_headers =
+ [ "//components/metrics/public/cpp/call_stack_profile_struct_traits.h" ]
+deps = [
+ "//base",
+ "//components/metrics:call_stack_profile_params",
+]
+type_mappings = [
+ "metrics.mojom.CallStackModule=base::StackSamplingProfiler::Module",
+ "metrics.mojom.CallStackFrame=base::StackSamplingProfiler::Frame",
+ "metrics.mojom.CallStackProfile=base::StackSamplingProfiler::CallStackProfile",
+ "metrics.mojom.CallStackProfileParams=metrics::CallStackProfileParams",
+ "metrics.mojom.Process=metrics::CallStackProfileParams::Process",
+ "metrics.mojom.SampleOrderingSpec=metrics::CallStackProfileParams::SampleOrderingSpec",
+ "metrics.mojom.Thread=metrics::CallStackProfileParams::Thread",
+ "metrics.mojom.Trigger=metrics::CallStackProfileParams::Trigger",
+]
diff --git a/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h
new file mode 100644
index 00000000000..6e200341c09
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits.h
@@ -0,0 +1,384 @@
+// Copyright 2016 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.
+
+// Defines StructTraits specializations for translating between mojo types and
+// base::StackSamplingProfiler types, with data validity checks.
+
+#ifndef COMPONENTS_METRICS_CALL_STACK_PROFILE_STRUCT_TRAITS_H_
+#define COMPONENTS_METRICS_CALL_STACK_PROFILE_STRUCT_TRAITS_H_
+
+#include <vector>
+
+#include "base/files/file_path.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "components/metrics/public/interfaces/call_stack_profile_collector.mojom.h"
+
+namespace mojo {
+
+template <>
+struct StructTraits<metrics::mojom::CallStackModuleDataView,
+ base::StackSamplingProfiler::Module> {
+ static uint64_t base_address(
+ const base::StackSamplingProfiler::Module& module) {
+ return module.base_address;
+ }
+ static const std::string& id(
+ const base::StackSamplingProfiler::Module& module) {
+ return module.id;
+ }
+ static const base::FilePath& filename(
+ const base::StackSamplingProfiler::Module& module) {
+ return module.filename;
+ }
+
+ static bool Read(metrics::mojom::CallStackModuleDataView data,
+ base::StackSamplingProfiler::Module* out) {
+ // Linux has the longest build id at 40 bytes.
+ static const size_t kMaxIDSize = 40;
+
+ std::string id;
+ base::FilePath filename;
+ if (!data.ReadId(&id) || id.size() > kMaxIDSize ||
+ !data.ReadFilename(&filename))
+ return false;
+
+ *out =
+ base::StackSamplingProfiler::Module(data.base_address(), id, filename);
+ return true;
+ }
+};
+
+template <>
+struct StructTraits<metrics::mojom::CallStackFrameDataView,
+ base::StackSamplingProfiler::Frame> {
+ static uint64_t instruction_pointer(
+ const base::StackSamplingProfiler::Frame& frame) {
+ return frame.instruction_pointer;
+ }
+ static uint64_t module_index(
+ const base::StackSamplingProfiler::Frame& frame) {
+ return frame.module_index ==
+ base::StackSamplingProfiler::Frame::kUnknownModuleIndex ?
+ static_cast<uint64_t>(-1) :
+ frame.module_index;
+ }
+
+ static bool Read(metrics::mojom::CallStackFrameDataView data,
+ base::StackSamplingProfiler::Frame* out) {
+ size_t module_index = data.module_index() == static_cast<uint64_t>(-1) ?
+ base::StackSamplingProfiler::Frame::kUnknownModuleIndex :
+ data.module_index();
+
+ // We can't know whether the module_index field is valid at this point since
+ // we don't have access to the number of modules here. This will be checked
+ // in CallStackProfile's Read function below.
+ *out = base::StackSamplingProfiler::Frame(data.instruction_pointer(),
+ module_index);
+ return true;
+ }
+};
+
+template <>
+struct StructTraits<metrics::mojom::CallStackProfileDataView,
+ base::StackSamplingProfiler::CallStackProfile> {
+ static const std::vector<base::StackSamplingProfiler::Module>& modules(
+ const base::StackSamplingProfiler::CallStackProfile& profile) {
+ return profile.modules;
+ }
+ static const std::vector<base::StackSamplingProfiler::Sample>& samples(
+ const base::StackSamplingProfiler::CallStackProfile& profile) {
+ return profile.samples;
+ }
+ static const base::TimeDelta profile_duration(
+ const base::StackSamplingProfiler::CallStackProfile& profile) {
+ return profile.profile_duration;
+ }
+ static const base::TimeDelta sampling_period(
+ const base::StackSamplingProfiler::CallStackProfile& profile) {
+ return profile.sampling_period;
+ }
+
+ static bool ValidateSamples(
+ std::vector<base::StackSamplingProfiler::Sample> samples,
+ size_t module_count) {
+ for (const base::StackSamplingProfiler::Sample& sample : samples) {
+ for (const base::StackSamplingProfiler::Frame& frame : sample) {
+ if (frame.module_index >= module_count &&
+ frame.module_index !=
+ base::StackSamplingProfiler::Frame::kUnknownModuleIndex)
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static bool Read(metrics::mojom::CallStackProfileDataView data,
+ base::StackSamplingProfiler::CallStackProfile* out) {
+ std::vector<base::StackSamplingProfiler::Module> modules;
+ std::vector<base::StackSamplingProfiler::Sample> samples;
+ base::TimeDelta profile_duration, sampling_period;
+ if (!data.ReadModules(&modules) || !data.ReadSamples(&samples) ||
+ !data.ReadProfileDuration(&profile_duration) ||
+ !data.ReadSamplingPeriod(&sampling_period) ||
+ !ValidateSamples(samples, modules.size()))
+ return false;
+
+ *out = base::StackSamplingProfiler::CallStackProfile();
+ out->modules = std::move(modules);
+ out->samples = std::move(samples);
+ out->profile_duration = profile_duration;
+ out->sampling_period = sampling_period;
+ return true;
+ }
+};
+
+template <>
+struct EnumTraits<metrics::mojom::Process,
+ metrics::CallStackProfileParams::Process> {
+ static metrics::mojom::Process ToMojom(
+ metrics::CallStackProfileParams::Process process) {
+ switch (process) {
+ case metrics::CallStackProfileParams::Process::UNKNOWN_PROCESS:
+ return metrics::mojom::Process::UNKNOWN_PROCESS;
+ case metrics::CallStackProfileParams::Process::BROWSER_PROCESS:
+ return metrics::mojom::Process::BROWSER_PROCESS;
+ case metrics::CallStackProfileParams::Process::RENDERER_PROCESS:
+ return metrics::mojom::Process::RENDERER_PROCESS;
+ case metrics::CallStackProfileParams::Process::GPU_PROCESS:
+ return metrics::mojom::Process::GPU_PROCESS;
+ case metrics::CallStackProfileParams::Process::UTILITY_PROCESS:
+ return metrics::mojom::Process::UTILITY_PROCESS;
+ case metrics::CallStackProfileParams::Process::ZYGOTE_PROCESS:
+ return metrics::mojom::Process::ZYGOTE_PROCESS;
+ case metrics::CallStackProfileParams::Process::SANDBOX_HELPER_PROCESS:
+ return metrics::mojom::Process::SANDBOX_HELPER_PROCESS;
+ case metrics::CallStackProfileParams::Process::PPAPI_PLUGIN_PROCESS:
+ return metrics::mojom::Process::PPAPI_PLUGIN_PROCESS;
+ case metrics::CallStackProfileParams::Process::PPAPI_BROKER_PROCESS:
+ return metrics::mojom::Process::PPAPI_BROKER_PROCESS;
+ }
+ NOTREACHED();
+ return metrics::mojom::Process::UNKNOWN_PROCESS;
+ }
+
+ static bool FromMojom(metrics::mojom::Process process,
+ metrics::CallStackProfileParams::Process* out) {
+ switch (process) {
+ case metrics::mojom::Process::UNKNOWN_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::UNKNOWN_PROCESS;
+ return true;
+ case metrics::mojom::Process::BROWSER_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::BROWSER_PROCESS;
+ return true;
+ case metrics::mojom::Process::RENDERER_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::RENDERER_PROCESS;
+ return true;
+ case metrics::mojom::Process::GPU_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::GPU_PROCESS;
+ return true;
+ case metrics::mojom::Process::UTILITY_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::UTILITY_PROCESS;
+ return true;
+ case metrics::mojom::Process::ZYGOTE_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::ZYGOTE_PROCESS;
+ return true;
+ case metrics::mojom::Process::SANDBOX_HELPER_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::SANDBOX_HELPER_PROCESS;
+ return true;
+ case metrics::mojom::Process::PPAPI_PLUGIN_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::PPAPI_PLUGIN_PROCESS;
+ return true;
+ case metrics::mojom::Process::PPAPI_BROKER_PROCESS:
+ *out = metrics::CallStackProfileParams::Process::PPAPI_BROKER_PROCESS;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct EnumTraits<metrics::mojom::Thread,
+ metrics::CallStackProfileParams::Thread> {
+ static metrics::mojom::Thread ToMojom(
+ metrics::CallStackProfileParams::Thread thread) {
+ switch (thread) {
+ case metrics::CallStackProfileParams::Thread::UNKNOWN_THREAD:
+ return metrics::mojom::Thread::UNKNOWN_THREAD;
+ case metrics::CallStackProfileParams::Thread::UI_THREAD:
+ return metrics::mojom::Thread::UI_THREAD;
+ case metrics::CallStackProfileParams::Thread::FILE_THREAD:
+ return metrics::mojom::Thread::FILE_THREAD;
+ case metrics::CallStackProfileParams::Thread::FILE_USER_BLOCKING_THREAD:
+ return metrics::mojom::Thread::FILE_USER_BLOCKING_THREAD;
+ case metrics::CallStackProfileParams::Thread::PROCESS_LAUNCHER_THREAD:
+ return metrics::mojom::Thread::PROCESS_LAUNCHER_THREAD;
+ case metrics::CallStackProfileParams::Thread::CACHE_THREAD:
+ return metrics::mojom::Thread::CACHE_THREAD;
+ case metrics::CallStackProfileParams::Thread::IO_THREAD:
+ return metrics::mojom::Thread::IO_THREAD;
+ case metrics::CallStackProfileParams::Thread::DB_THREAD:
+ return metrics::mojom::Thread::DB_THREAD;
+ case metrics::CallStackProfileParams::Thread::GPU_MAIN_THREAD:
+ return metrics::mojom::Thread::GPU_MAIN_THREAD;
+ case metrics::CallStackProfileParams::Thread::RENDER_THREAD:
+ return metrics::mojom::Thread::RENDER_THREAD;
+ case metrics::CallStackProfileParams::Thread::UTILITY_THREAD:
+ return metrics::mojom::Thread::UTILITY_THREAD;
+ }
+ NOTREACHED();
+ return metrics::mojom::Thread::UNKNOWN_THREAD;
+ }
+
+ static bool FromMojom(metrics::mojom::Thread thread,
+ metrics::CallStackProfileParams::Thread* out) {
+ switch (thread) {
+ case metrics::mojom::Thread::UNKNOWN_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::UNKNOWN_THREAD;
+ return true;
+ case metrics::mojom::Thread::UI_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::UI_THREAD;
+ return true;
+ case metrics::mojom::Thread::FILE_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::FILE_THREAD;
+ return true;
+ case metrics::mojom::Thread::FILE_USER_BLOCKING_THREAD:
+ *out =
+ metrics::CallStackProfileParams::Thread::FILE_USER_BLOCKING_THREAD;
+ return true;
+ case metrics::mojom::Thread::PROCESS_LAUNCHER_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::PROCESS_LAUNCHER_THREAD;
+ return true;
+ case metrics::mojom::Thread::CACHE_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::CACHE_THREAD;
+ return true;
+ case metrics::mojom::Thread::IO_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::IO_THREAD;
+ return true;
+ case metrics::mojom::Thread::DB_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::DB_THREAD;
+ return true;
+ case metrics::mojom::Thread::GPU_MAIN_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::GPU_MAIN_THREAD;
+ return true;
+ case metrics::mojom::Thread::RENDER_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::RENDER_THREAD;
+ return true;
+ case metrics::mojom::Thread::UTILITY_THREAD:
+ *out = metrics::CallStackProfileParams::Thread::UTILITY_THREAD;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct EnumTraits<metrics::mojom::Trigger,
+ metrics::CallStackProfileParams::Trigger> {
+ static metrics::mojom::Trigger ToMojom(
+ metrics::CallStackProfileParams::Trigger trigger) {
+ switch (trigger) {
+ case metrics::CallStackProfileParams::Trigger::UNKNOWN:
+ return metrics::mojom::Trigger::UNKNOWN;
+ case metrics::CallStackProfileParams::Trigger::PROCESS_STARTUP:
+ return metrics::mojom::Trigger::PROCESS_STARTUP;
+ case metrics::CallStackProfileParams::Trigger::JANKY_TASK:
+ return metrics::mojom::Trigger::JANKY_TASK;
+ case metrics::CallStackProfileParams::Trigger::THREAD_HUNG:
+ return metrics::mojom::Trigger::THREAD_HUNG;
+ }
+ NOTREACHED();
+ return metrics::mojom::Trigger::UNKNOWN;
+ }
+
+ static bool FromMojom(metrics::mojom::Trigger trigger,
+ metrics::CallStackProfileParams::Trigger* out) {
+ switch (trigger) {
+ case metrics::mojom::Trigger::UNKNOWN:
+ *out = metrics::CallStackProfileParams::Trigger::UNKNOWN;
+ return true;
+ case metrics::mojom::Trigger::PROCESS_STARTUP:
+ *out = metrics::CallStackProfileParams::Trigger::PROCESS_STARTUP;
+ return true;
+ case metrics::mojom::Trigger::JANKY_TASK:
+ *out = metrics::CallStackProfileParams::Trigger::JANKY_TASK;
+ return true;
+ case metrics::mojom::Trigger::THREAD_HUNG:
+ *out = metrics::CallStackProfileParams::Trigger::THREAD_HUNG;
+ return true;
+ }
+ return false;
+ }
+};
+
+template <>
+struct StructTraits<metrics::mojom::CallStackProfileParamsDataView,
+ metrics::CallStackProfileParams> {
+ static metrics::CallStackProfileParams::Process process(
+ const metrics::CallStackProfileParams& params) {
+ return params.process;
+ }
+ static metrics::CallStackProfileParams::Thread thread(
+ const metrics::CallStackProfileParams& params) {
+ return params.thread;
+ }
+ static metrics::CallStackProfileParams::Trigger trigger(
+ const metrics::CallStackProfileParams& params) {
+ return params.trigger;
+ }
+ static metrics::CallStackProfileParams::SampleOrderingSpec ordering_spec(
+ const metrics::CallStackProfileParams& params) {
+ return params.ordering_spec;
+ }
+
+ static bool Read(metrics::mojom::CallStackProfileParamsDataView data,
+ metrics::CallStackProfileParams* out) {
+ metrics::CallStackProfileParams::Process process;
+ metrics::CallStackProfileParams::Thread thread;
+ metrics::CallStackProfileParams::Trigger trigger;
+ metrics::CallStackProfileParams::SampleOrderingSpec ordering_spec;
+ if (!data.ReadProcess(&process) || !data.ReadThread(&thread) ||
+ !data.ReadTrigger(&trigger) || !data.ReadOrderingSpec(&ordering_spec)) {
+ return false;
+ }
+ *out = metrics::CallStackProfileParams(process, thread, trigger,
+ ordering_spec);
+ return true;
+ }
+};
+
+template <>
+struct EnumTraits<metrics::mojom::SampleOrderingSpec,
+ metrics::CallStackProfileParams::SampleOrderingSpec> {
+
+ static metrics::mojom::SampleOrderingSpec ToMojom(
+ metrics::CallStackProfileParams::SampleOrderingSpec spec) {
+ switch (spec) {
+ case metrics::CallStackProfileParams::SampleOrderingSpec::MAY_SHUFFLE:
+ return metrics::mojom::SampleOrderingSpec::MAY_SHUFFLE;
+ case metrics::CallStackProfileParams::SampleOrderingSpec::PRESERVE_ORDER:
+ return metrics::mojom::SampleOrderingSpec::PRESERVE_ORDER;
+ }
+ NOTREACHED();
+ return metrics::mojom::SampleOrderingSpec::MAY_SHUFFLE;
+ }
+
+ static bool FromMojom(
+ metrics::mojom::SampleOrderingSpec spec,
+ metrics::CallStackProfileParams::SampleOrderingSpec* out) {
+ switch (spec) {
+ case metrics::mojom::SampleOrderingSpec::MAY_SHUFFLE:
+ *out = metrics::CallStackProfileParams::SampleOrderingSpec::MAY_SHUFFLE;
+ return true;
+ case metrics::mojom::SampleOrderingSpec::PRESERVE_ORDER:
+ *out =
+ metrics::CallStackProfileParams::SampleOrderingSpec::PRESERVE_ORDER;
+ return true;
+ }
+ return false;
+ }
+};
+
+} // mojo
+
+#endif // COMPONENTS_METRICS_CALL_STACK_PROFILE_STRUCT_TRAITS_H_
diff --git a/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc
new file mode 100644
index 00000000000..14db487f452
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/call_stack_profile_struct_traits_unittest.cc
@@ -0,0 +1,402 @@
+// Copyright 2016 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 <utility>
+
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/message_loop/message_loop.h"
+#include "components/metrics/public/interfaces/call_stack_profile_collector_test.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+
+namespace {
+
+base::StackSamplingProfiler::CallStackProfile CreateProfile(
+ const std::vector<base::StackSamplingProfiler::Module>& modules,
+ const std::vector<base::StackSamplingProfiler::Sample>& samples,
+ base::TimeDelta profile_duration,
+ base::TimeDelta sampling_period) {
+ base::StackSamplingProfiler::CallStackProfile profile;
+ profile.modules = modules;
+ profile.samples = samples;
+ profile.profile_duration = profile_duration;
+ profile.sampling_period = sampling_period;
+ return profile;
+}
+
+}
+
+class CallStackProfileCollectorTestImpl
+ : public mojom::CallStackProfileCollectorTest {
+ public:
+ explicit CallStackProfileCollectorTestImpl(
+ mojo::InterfaceRequest<mojom::CallStackProfileCollectorTest> request)
+ : binding_(this, std::move(request)) {
+ }
+
+ // CallStackProfileCollectorTest:
+ void BounceFrame(const base::StackSamplingProfiler::Frame& in,
+ const BounceFrameCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceModule(const base::StackSamplingProfiler::Module& in,
+ const BounceModuleCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceProfile(const base::StackSamplingProfiler::CallStackProfile& in,
+ const BounceProfileCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceTrigger(CallStackProfileParams::Trigger in,
+ const BounceTriggerCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceProcess(CallStackProfileParams::Process in,
+ const BounceProcessCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceThread(CallStackProfileParams::Thread in,
+ const BounceThreadCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceSampleOrderingSpec(
+ CallStackProfileParams::SampleOrderingSpec in,
+ const BounceSampleOrderingSpecCallback& callback) override {
+ callback.Run(in);
+ }
+
+ void BounceCallStackProfileParams(
+ const CallStackProfileParams& in,
+ const BounceCallStackProfileParamsCallback& callback) override {
+ callback.Run(in);
+ }
+
+ private:
+ mojo::Binding<CallStackProfileCollectorTest> binding_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallStackProfileCollectorTestImpl);
+};
+
+class CallStackProfileStructTraitsTest : public testing::Test {
+ public:
+ CallStackProfileStructTraitsTest() : impl_(GetProxy(&proxy_)) {}
+
+ protected:
+ base::MessageLoop message_loop_;
+ mojom::CallStackProfileCollectorTestPtr proxy_;
+ CallStackProfileCollectorTestImpl impl_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallStackProfileStructTraitsTest);
+};
+
+// Checks serialization/deserialization of Module fields.
+TEST_F(CallStackProfileStructTraitsTest, Module) {
+ using Module = base::StackSamplingProfiler::Module;
+
+ struct SerializeCase {
+ Module module;
+ bool expect_success;
+ };
+
+ const SerializeCase serialize_cases[] = {
+ // Null base address.
+ {
+ Module(0x0, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Non-null base address.
+ {
+ Module(0x10, "abcd", base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Base address with a bit set beyond 32 bits, when built for x64.
+ {
+ Module(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, "abcd",
+ base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Empty module id.
+ {
+ Module(0x10, "", base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Module id at the length limit.
+ {
+ Module(0x10, std::string(40, ' '),
+ base::FilePath(base::FilePath::kCurrentDirectory)),
+ true
+ },
+ // Module id beyond the length limit.
+ {
+ Module(0x10, std::string(41, ' '),
+ base::FilePath(base::FilePath::kCurrentDirectory)),
+ false
+ },
+ };
+
+ for (const SerializeCase& input : serialize_cases) {
+ Module output;
+ EXPECT_EQ(input.expect_success,
+ proxy_->BounceModule(input.module, &output));
+
+ if (!input.expect_success)
+ continue;
+
+ EXPECT_EQ(input.module.base_address, output.base_address);
+ EXPECT_EQ(input.module.id, output.id);
+ EXPECT_EQ(input.module.filename, output.filename);
+ }
+}
+
+// Checks serialization/deserialization of Frame fields.
+TEST_F(CallStackProfileStructTraitsTest, Frame) {
+ using Frame = base::StackSamplingProfiler::Frame;
+
+ const Frame serialize_cases[] = {
+ // Null instruction pointer.
+ Frame(0x0, 10),
+ // Non-null instruction pointer.
+ Frame(0x10, 10),
+ // Instruction pointer with a bit set beyond 32 bits, when built for x64.
+ Frame(1ULL << (sizeof(uintptr_t) * 8) * 3 / 4, 10),
+ // Zero module index.
+ Frame(0xabcd, 0),
+ // Non-zero module index.
+ Frame(0xabcd, 1),
+ // Non-zero module index.
+ Frame(0xabcd, 10),
+ // Unknown module index.
+ Frame(0xabcd, Frame::kUnknownModuleIndex),
+ };
+
+ for (const Frame& input : serialize_cases) {
+ Frame output;
+ EXPECT_TRUE(proxy_->BounceFrame(input, &output));
+
+ EXPECT_EQ(input.instruction_pointer, output.instruction_pointer);
+ EXPECT_EQ(input.module_index, output.module_index);
+ }
+}
+
+// Checks serialization/deserialization of Profile fields, including validation
+// of the Frame module_index field.
+TEST_F(CallStackProfileStructTraitsTest, Profile) {
+ using Module = base::StackSamplingProfiler::Module;
+ using Frame = base::StackSamplingProfiler::Frame;
+ using Sample = base::StackSamplingProfiler::Sample;
+ using Profile = base::StackSamplingProfiler::CallStackProfile;
+
+ struct SerializeCase {
+ Profile profile;
+ bool expect_success;
+ };
+
+ const SerializeCase serialize_cases[] = {
+ // Empty modules and samples.
+ {
+ CreateProfile(std::vector<Module>(), std::vector<Sample>(),
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(2)),
+ true
+ },
+ // Non-empty modules and empty samples.
+ {
+ CreateProfile({ Module(0x4000, "a", base::FilePath()) },
+ std::vector<Sample>(),
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(2)),
+ true
+ },
+ // Valid values for modules and samples.
+ {
+ CreateProfile({
+ Module(0x4000, "a", base::FilePath()),
+ Module(0x4100, "b", base::FilePath()),
+ },
+ {
+ {
+ Frame(0x4010, 0),
+ Frame(0x4110, 1),
+ Frame(0x4110, Frame::kUnknownModuleIndex),
+ }
+ },
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(2)),
+ true
+ },
+ // Valid values for modules, but an out of range module index in the second
+ // sample.
+ {
+ CreateProfile({
+ Module(0x4000, "a", base::FilePath()),
+ Module(0x4100, "b", base::FilePath()),
+ },
+ {
+ {
+ Frame(0x4010, 0),
+ Frame(0x4110, 1),
+ Frame(0x4110, Frame::kUnknownModuleIndex),
+ },
+ {
+ Frame(0x4010, 0),
+ Frame(0x4110, 2),
+ },
+ },
+ base::TimeDelta::FromSeconds(1),
+ base::TimeDelta::FromSeconds(2)),
+ false
+ },
+ };
+
+ for (const SerializeCase& input : serialize_cases) {
+ SCOPED_TRACE(&input - &serialize_cases[0]);
+
+ Profile output;
+ EXPECT_EQ(input.expect_success,
+ proxy_->BounceProfile(input.profile, &output));
+
+ if (!input.expect_success)
+ continue;
+
+ EXPECT_EQ(input.profile.modules, output.modules);
+ EXPECT_EQ(input.profile.samples, output.samples);
+ EXPECT_EQ(input.profile.profile_duration, output.profile_duration);
+ EXPECT_EQ(input.profile.sampling_period, output.sampling_period);
+ }
+}
+
+// Checks serialization/deserialization of the process, including validation.
+TEST_F(CallStackProfileStructTraitsTest, Process) {
+ using Process = CallStackProfileParams::Process;
+
+ Process out;
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::UNKNOWN_PROCESS, &out));
+ EXPECT_EQ(Process::UNKNOWN_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::BROWSER_PROCESS, &out));
+ EXPECT_EQ(Process::BROWSER_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::RENDERER_PROCESS, &out));
+ EXPECT_EQ(Process::RENDERER_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::GPU_PROCESS, &out));
+ EXPECT_EQ(Process::GPU_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::UTILITY_PROCESS, &out));
+ EXPECT_EQ(Process::UTILITY_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::ZYGOTE_PROCESS, &out));
+ EXPECT_EQ(Process::ZYGOTE_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::SANDBOX_HELPER_PROCESS, &out));
+ EXPECT_EQ(Process::SANDBOX_HELPER_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::PPAPI_PLUGIN_PROCESS, &out));
+ EXPECT_EQ(Process::PPAPI_PLUGIN_PROCESS, out);
+
+ EXPECT_TRUE(proxy_->BounceProcess(Process::PPAPI_BROKER_PROCESS, &out));
+ EXPECT_EQ(Process::PPAPI_BROKER_PROCESS, out);
+}
+
+// Checks serialization/deserialization of the thread, including validation.
+TEST_F(CallStackProfileStructTraitsTest, Thread) {
+ using Thread = CallStackProfileParams::Thread;
+
+ Thread out;
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::UI_THREAD, &out));
+ EXPECT_EQ(Thread::UI_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::FILE_THREAD, &out));
+ EXPECT_EQ(Thread::FILE_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::FILE_USER_BLOCKING_THREAD, &out));
+ EXPECT_EQ(Thread::FILE_USER_BLOCKING_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::PROCESS_LAUNCHER_THREAD, &out));
+ EXPECT_EQ(Thread::PROCESS_LAUNCHER_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::CACHE_THREAD, &out));
+ EXPECT_EQ(Thread::CACHE_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::IO_THREAD, &out));
+ EXPECT_EQ(Thread::IO_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::DB_THREAD, &out));
+ EXPECT_EQ(Thread::DB_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::GPU_MAIN_THREAD, &out));
+ EXPECT_EQ(Thread::GPU_MAIN_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::RENDER_THREAD, &out));
+ EXPECT_EQ(Thread::RENDER_THREAD, out);
+
+ EXPECT_TRUE(proxy_->BounceThread(Thread::UTILITY_THREAD, &out));
+ EXPECT_EQ(Thread::UTILITY_THREAD, out);
+}
+
+// Checks serialization/deserialization of the trigger, including validation.
+TEST_F(CallStackProfileStructTraitsTest, Trigger) {
+ using Trigger = CallStackProfileParams::Trigger;
+
+ Trigger out;
+
+ EXPECT_TRUE(proxy_->BounceTrigger(Trigger::UNKNOWN, &out));
+ EXPECT_EQ(Trigger::UNKNOWN, out);
+
+ EXPECT_TRUE(proxy_->BounceTrigger(Trigger::PROCESS_STARTUP, &out));
+ EXPECT_EQ(Trigger::PROCESS_STARTUP, out);
+
+ EXPECT_TRUE(proxy_->BounceTrigger(Trigger::JANKY_TASK, &out));
+ EXPECT_EQ(Trigger::JANKY_TASK, out);
+
+ EXPECT_TRUE(proxy_->BounceTrigger(Trigger::THREAD_HUNG, &out));
+ EXPECT_EQ(Trigger::THREAD_HUNG, out);
+}
+
+// Checks serialization/deserialization of the SampleOrderingSpec, including
+// validation.
+TEST_F(CallStackProfileStructTraitsTest, SampleOrderingSpec) {
+ using SampleOrderingSpec = CallStackProfileParams::SampleOrderingSpec;
+
+ SampleOrderingSpec out;
+
+ EXPECT_TRUE(proxy_->BounceSampleOrderingSpec(SampleOrderingSpec::MAY_SHUFFLE,
+ &out));
+ EXPECT_EQ(SampleOrderingSpec::MAY_SHUFFLE, out);
+
+ EXPECT_TRUE(proxy_->BounceSampleOrderingSpec(
+ SampleOrderingSpec::PRESERVE_ORDER,
+ &out));
+ EXPECT_EQ(SampleOrderingSpec::PRESERVE_ORDER, out);
+}
+
+// Checks serialization/deserialization of the CallStackProfileParams.
+TEST_F(CallStackProfileStructTraitsTest, CallStackProfileParams) {
+ CallStackProfileParams out;
+
+ EXPECT_TRUE(proxy_->BounceCallStackProfileParams(
+ CallStackProfileParams(CallStackProfileParams::BROWSER_PROCESS,
+ CallStackProfileParams::UI_THREAD,
+ CallStackProfileParams::PROCESS_STARTUP,
+ CallStackProfileParams::PRESERVE_ORDER),
+ &out));
+
+ EXPECT_EQ(CallStackProfileParams::BROWSER_PROCESS, out.process);
+ EXPECT_EQ(CallStackProfileParams::UI_THREAD, out.thread);
+ EXPECT_EQ(CallStackProfileParams::PROCESS_STARTUP, out.trigger);
+ EXPECT_EQ(CallStackProfileParams::PRESERVE_ORDER, out.ordering_spec);
+}
+
+} // namespace metrics
diff --git a/chromium/components/metrics/public/cpp/typemaps.gni b/chromium/components/metrics/public/cpp/typemaps.gni
new file mode 100644
index 00000000000..079917f788c
--- /dev/null
+++ b/chromium/components/metrics/public/cpp/typemaps.gni
@@ -0,0 +1,5 @@
+# Copyright 2016 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.
+
+typemaps = [ "//components/metrics/public/cpp/call_stack_profile.typemap" ]
diff --git a/chromium/components/metrics/public/interfaces/BUILD.gn b/chromium/components/metrics/public/interfaces/BUILD.gn
new file mode 100644
index 00000000000..c6db51a6cf5
--- /dev/null
+++ b/chromium/components/metrics/public/interfaces/BUILD.gn
@@ -0,0 +1,26 @@
+# Copyright 2016 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.
+
+import("//mojo/public/tools/bindings/mojom.gni")
+
+mojom("call_stack_mojo_bindings") {
+ sources = [
+ "call_stack_profile_collector.mojom",
+ ]
+
+ deps = [
+ "//mojo/common:common_custom_types",
+ ]
+}
+
+mojom("call_stack_mojo_test_bindings") {
+ sources = [
+ "call_stack_profile_collector_test.mojom",
+ ]
+
+ deps = [
+ ":call_stack_mojo_bindings",
+ "//mojo/common:common_custom_types",
+ ]
+}
diff --git a/chromium/components/metrics/public/interfaces/OWNERS b/chromium/components/metrics/public/interfaces/OWNERS
new file mode 100644
index 00000000000..154435234ea
--- /dev/null
+++ b/chromium/components/metrics/public/interfaces/OWNERS
@@ -0,0 +1,4 @@
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+per-file *_struct_traits*.*=set noparent
+per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom b/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom
new file mode 100644
index 00000000000..6c8f04216c6
--- /dev/null
+++ b/chromium/components/metrics/public/interfaces/call_stack_profile_collector.mojom
@@ -0,0 +1,81 @@
+// Copyright 2016 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.
+
+module metrics.mojom;
+
+import "mojo/common/common_custom_types.mojom";
+
+// These structs mirror the corresponding types in base::StackSamplingProfiler.
+
+struct CallStackModule {
+ uint64 base_address;
+ string id;
+ mojo.common.mojom.FilePath filename;
+};
+
+struct CallStackFrame {
+ uint64 instruction_pointer;
+ uint64 module_index;
+};
+
+struct CallStackProfile {
+ array<CallStackModule> modules;
+ array<array<CallStackFrame>> samples;
+ mojo.common.mojom.TimeDelta profile_duration;
+ mojo.common.mojom.TimeDelta sampling_period;
+};
+
+enum Process {
+ UNKNOWN_PROCESS,
+ BROWSER_PROCESS,
+ RENDERER_PROCESS,
+ GPU_PROCESS,
+ UTILITY_PROCESS,
+ ZYGOTE_PROCESS,
+ SANDBOX_HELPER_PROCESS,
+ PPAPI_PLUGIN_PROCESS,
+ PPAPI_BROKER_PROCESS,
+};
+
+enum Thread {
+ UNKNOWN_THREAD,
+
+ UI_THREAD,
+ FILE_THREAD,
+ FILE_USER_BLOCKING_THREAD,
+ PROCESS_LAUNCHER_THREAD,
+ CACHE_THREAD,
+ IO_THREAD,
+ DB_THREAD,
+
+ GPU_MAIN_THREAD,
+
+ RENDER_THREAD,
+ UTILITY_THREAD,
+};
+
+enum Trigger {
+ UNKNOWN,
+ PROCESS_STARTUP,
+ JANKY_TASK,
+ THREAD_HUNG,
+};
+
+enum SampleOrderingSpec {
+ MAY_SHUFFLE,
+ PRESERVE_ORDER,
+};
+
+struct CallStackProfileParams {
+ Process process;
+ Thread thread;
+ Trigger trigger;
+ SampleOrderingSpec ordering_spec;
+};
+
+interface CallStackProfileCollector {
+ Collect(CallStackProfileParams params,
+ mojo.common.mojom.TimeTicks start_timestamp,
+ array<CallStackProfile> profiles);
+};
diff --git a/chromium/components/metrics/public/interfaces/call_stack_profile_collector_test.mojom b/chromium/components/metrics/public/interfaces/call_stack_profile_collector_test.mojom
new file mode 100644
index 00000000000..2c7f1c1471a
--- /dev/null
+++ b/chromium/components/metrics/public/interfaces/call_stack_profile_collector_test.mojom
@@ -0,0 +1,33 @@
+// Copyright 2016 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.
+
+module metrics.mojom;
+
+import "components/metrics/public/interfaces/call_stack_profile_collector.mojom";
+
+interface CallStackProfileCollectorTest {
+ [Sync]
+ BounceFrame(CallStackFrame in) => (CallStackFrame out);
+
+ [Sync]
+ BounceModule(CallStackModule in) => (CallStackModule out);
+
+ [Sync]
+ BounceProfile(CallStackProfile in) => (CallStackProfile out);
+
+ [Sync]
+ BounceProcess(Process in) => (Process out);
+
+ [Sync]
+ BounceThread(Thread in) => (Thread out);
+
+ [Sync]
+ BounceTrigger(Trigger in) => (Trigger out);
+
+ [Sync]
+ BounceSampleOrderingSpec(SampleOrderingSpec in) => (SampleOrderingSpec out);
+
+ [Sync]
+ BounceCallStackProfileParams(CallStackProfileParams in) => (CallStackProfileParams out);
+};
diff --git a/chromium/components/metrics/serialization/serialization_utils_unittest.cc b/chromium/components/metrics/serialization/serialization_utils_unittest.cc
index f3110166670..9d1e3602e34 100644
--- a/chromium/components/metrics/serialization/serialization_utils_unittest.cc
+++ b/chromium/components/metrics/serialization/serialization_utils_unittest.cc
@@ -22,7 +22,7 @@ class SerializationUtilsTest : public testing::Test {
SerializationUtilsTest() {
bool success = temporary_dir.CreateUniqueTempDir();
if (success) {
- base::FilePath dir_path = temporary_dir.path();
+ base::FilePath dir_path = temporary_dir.GetPath();
filename = dir_path.value() + "chromeossampletest";
filepath = base::FilePath(filename);
}
@@ -154,8 +154,8 @@ TEST_F(SerializationUtilsTest, WriteReadTest) {
ScopedVector<MetricSample> vect;
SerializationUtils::ReadAndTruncateMetricsFromFile(filename, &vect);
ASSERT_EQ(vect.size(), size_t(5));
- for (int i = 0; i < 5; i++) {
- ASSERT_TRUE(vect[0] != NULL);
+ for (MetricSample* sample : vect) {
+ ASSERT_NE(nullptr, sample);
}
EXPECT_TRUE(hist->IsEqual(*vect[0]));
EXPECT_TRUE(crash->IsEqual(*vect[1]));
diff --git a/chromium/components/metrics/stability_metrics_helper.cc b/chromium/components/metrics/stability_metrics_helper.cc
index 7b771f9f4d5..8c33f7773e5 100644
--- a/chromium/components/metrics/stability_metrics_helper.cc
+++ b/chromium/components/metrics/stability_metrics_helper.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "base/logging.h"
-#include "base/metrics/histogram.h"
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/sparse_histogram.h"
#include "build/build_config.h"
#include "components/metrics/metrics_pref_names.h"
@@ -95,6 +95,12 @@ void StabilityMetricsHelper::ProvideStabilityMetrics(
local_state_->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0);
}
+ count = local_state_->GetInteger(prefs::kStabilityRendererLaunchCount);
+ if (count) {
+ stability_proto->set_renderer_launch_count(count);
+ local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
+ }
+
count =
local_state_->GetInteger(prefs::kStabilityExtensionRendererCrashCount);
if (count) {
@@ -115,6 +121,13 @@ void StabilityMetricsHelper::ProvideStabilityMetrics(
stability_proto->set_renderer_hang_count(count);
local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
}
+
+ count =
+ local_state_->GetInteger(prefs::kStabilityExtensionRendererLaunchCount);
+ if (count) {
+ stability_proto->set_extension_renderer_launch_count(count);
+ local_state_->SetInteger(prefs::kStabilityExtensionRendererLaunchCount, 0);
+ }
}
void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
@@ -124,10 +137,12 @@ void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityExtensionRendererFailedLaunchCount,
0);
+ local_state_->SetInteger(prefs::kStabilityExtensionRendererLaunchCount, 0);
local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
+ local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
}
// static
@@ -137,10 +152,13 @@ void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
0);
registry->RegisterIntegerPref(
prefs::kStabilityExtensionRendererFailedLaunchCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererLaunchCount,
+ 0);
registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererFailedLaunchCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0);
+ registry->RegisterIntegerPref(prefs::kStabilityRendererLaunchCount, 0);
registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0);
}
@@ -164,48 +182,73 @@ void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
int exit_code) {
int histogram_type =
was_extension_process ? RENDERER_TYPE_EXTENSION : RENDERER_TYPE_RENDERER;
- if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
- status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
- if (was_extension_process) {
- IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
-
- UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
- MapCrashExitCodeForHistogram(exit_code));
- } else {
- IncrementPrefValue(prefs::kStabilityRendererCrashCount);
-
- UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
- MapCrashExitCodeForHistogram(exit_code));
- }
-
- UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes",
- histogram_type, RENDERER_TYPE_COUNT);
- } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
- RecordChildKills(histogram_type);
+
+ switch (status) {
+ case base::TERMINATION_STATUS_NORMAL_TERMINATION:
+ break;
+ case base::TERMINATION_STATUS_PROCESS_CRASHED:
+ case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
+ case base::TERMINATION_STATUS_OOM:
+ if (was_extension_process) {
+ IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
+
+ UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
+ MapCrashExitCodeForHistogram(exit_code));
+ } else {
+ IncrementPrefValue(prefs::kStabilityRendererCrashCount);
+
+ UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
+ MapCrashExitCodeForHistogram(exit_code));
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes",
+ histogram_type, RENDERER_TYPE_COUNT);
+ break;
+ case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
+ RecordChildKills(histogram_type);
+ break;
+#if defined(OS_ANDROID)
+ case base::TERMINATION_STATUS_OOM_PROTECTED:
+ // TODO(wfh): Check if this should be a Kill or a Crash on Android.
+ break;
+#endif
#if defined(OS_CHROMEOS)
- } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
- RecordChildKills(histogram_type);
- UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
- was_extension_process ? 2 : 1, 3);
- RecordMemoryStats(was_extension_process
- ? RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
- : RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
+ case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
+ RecordChildKills(histogram_type);
+ UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
+ was_extension_process ? 2 : 1, 3);
+ RecordMemoryStats(was_extension_process
+ ? RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
+ : RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
+ break;
#endif
- } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
- UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive",
- histogram_type, RENDERER_TYPE_COUNT);
- } else if (status == base::TERMINATION_STATUS_LAUNCH_FAILED) {
- UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildLaunchFailures",
- histogram_type, RENDERER_TYPE_COUNT);
- UMA_HISTOGRAM_SPARSE_SLOWLY(
- "BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
- if (was_extension_process)
- IncrementPrefValue(prefs::kStabilityExtensionRendererFailedLaunchCount);
- else
- IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount);
+ case base::TERMINATION_STATUS_STILL_RUNNING:
+ UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive",
+ histogram_type, RENDERER_TYPE_COUNT);
+ break;
+ case base::TERMINATION_STATUS_LAUNCH_FAILED:
+ UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildLaunchFailures",
+ histogram_type, RENDERER_TYPE_COUNT);
+ UMA_HISTOGRAM_SPARSE_SLOWLY(
+ "BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
+ if (was_extension_process)
+ IncrementPrefValue(prefs::kStabilityExtensionRendererFailedLaunchCount);
+ else
+ IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount);
+ break;
+ case base::TERMINATION_STATUS_MAX_ENUM:
+ NOTREACHED();
+ break;
}
}
+void StabilityMetricsHelper::LogRendererLaunched(bool was_extension_process) {
+ if (was_extension_process)
+ IncrementPrefValue(prefs::kStabilityExtensionRendererLaunchCount);
+ else
+ IncrementPrefValue(prefs::kStabilityRendererLaunchCount);
+}
+
void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
int value = local_state_->GetInteger(path);
local_state_->SetInteger(path, value + 1);
diff --git a/chromium/components/metrics/stability_metrics_helper.h b/chromium/components/metrics/stability_metrics_helper.h
index 42a9ca20217..87f8f400f19 100644
--- a/chromium/components/metrics/stability_metrics_helper.h
+++ b/chromium/components/metrics/stability_metrics_helper.h
@@ -36,10 +36,13 @@ class StabilityMetricsHelper {
void LogLoadStarted();
// Records a renderer process crash.
- void LogRendererCrash(bool was_exception_process,
+ void LogRendererCrash(bool was_extension_process,
base::TerminationStatus status,
int exit_code);
+ // Records that a new renderer process was successfully launched.
+ void LogRendererLaunched(bool was_extension_process);
+
// Records a renderer process hang.
void LogRendererHang();
diff --git a/chromium/components/metrics/stability_metrics_helper_unittest.cc b/chromium/components/metrics/stability_metrics_helper_unittest.cc
index d5aa9291a0c..018906d8a1c 100644
--- a/chromium/components/metrics/stability_metrics_helper_unittest.cc
+++ b/chromium/components/metrics/stability_metrics_helper_unittest.cc
@@ -5,6 +5,7 @@
#include "components/metrics/stability_metrics_helper.h"
#include "base/macros.h"
+#include "base/test/histogram_tester.h"
#include "components/metrics/proto/system_profile.pb.h"
#include "components/prefs/pref_service.h"
#include "components/prefs/scoped_user_pref_update.h"
@@ -15,6 +16,15 @@ namespace metrics {
namespace {
+enum RendererType {
+ RENDERER_TYPE_RENDERER = 1,
+ RENDERER_TYPE_EXTENSION,
+ // NOTE: Add new action types only immediately above this line. Also,
+ // make sure the enum list in tools/metrics/histograms/histograms.xml is
+ // updated with any change in here.
+ RENDERER_TYPE_COUNT
+};
+
class StabilityMetricsHelperTest : public testing::Test {
protected:
StabilityMetricsHelperTest() : prefs_(new TestingPrefServiceSimple) {
@@ -52,6 +62,7 @@ TEST_F(StabilityMetricsHelperTest, BrowserChildProcessCrashed) {
TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
StabilityMetricsHelper helper(prefs());
+ base::HistogramTester histogram_tester;
// Crash and abnormal termination should increment renderer crash count.
helper.LogRendererCrash(false, base::TERMINATION_STATUS_PROCESS_CRASHED, 1);
@@ -59,6 +70,9 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
helper.LogRendererCrash(false, base::TERMINATION_STATUS_ABNORMAL_TERMINATION,
1);
+ // OOM should increment renderer crash count.
+ helper.LogRendererCrash(false, base::TERMINATION_STATUS_OOM, 1);
+
// Kill does not increment renderer crash count.
helper.LogRendererCrash(false, base::TERMINATION_STATUS_PROCESS_WAS_KILLED,
1);
@@ -72,7 +86,7 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
// be executed immediately.
helper.ProvideStabilityMetrics(&system_profile);
- EXPECT_EQ(2, system_profile.stability().renderer_crash_count());
+ EXPECT_EQ(3, system_profile.stability().renderer_crash_count());
EXPECT_EQ(1, system_profile.stability().renderer_failed_launch_count());
EXPECT_EQ(0, system_profile.stability().extension_renderer_crash_count());
@@ -81,6 +95,9 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
// Crash and abnormal termination should increment extension crash count.
helper.LogRendererCrash(true, base::TERMINATION_STATUS_PROCESS_CRASHED, 1);
+ // OOM should increment extension renderer crash count.
+ helper.LogRendererCrash(true, base::TERMINATION_STATUS_OOM, 1);
+
// Failed launch increments extension failed launch count.
helper.LogRendererCrash(true, base::TERMINATION_STATUS_LAUNCH_FAILED, 1);
@@ -88,9 +105,36 @@ TEST_F(StabilityMetricsHelperTest, LogRendererCrash) {
helper.ProvideStabilityMetrics(&system_profile);
EXPECT_EQ(0, system_profile.stability().renderer_crash_count());
- EXPECT_EQ(1, system_profile.stability().extension_renderer_crash_count());
+ EXPECT_EQ(2, system_profile.stability().extension_renderer_crash_count());
EXPECT_EQ(
1, system_profile.stability().extension_renderer_failed_launch_count());
+
+ // TERMINATION_STATUS_PROCESS_CRASHED, TERMINATION_STATUS_ABNORMAL_TERMINATION
+ // and TERMINATION_STATUS_OOM = 3.
+ histogram_tester.ExpectUniqueSample("CrashExitCodes.Renderer", 1, 3);
+ histogram_tester.ExpectBucketCount("BrowserRenderProcessHost.ChildCrashes",
+ RENDERER_TYPE_RENDERER, 3);
+
+ // TERMINATION_STATUS_PROCESS_CRASHED and TERMINATION_STATUS_OOM = 2.
+ histogram_tester.ExpectUniqueSample("CrashExitCodes.Extension", 1, 2);
+ histogram_tester.ExpectBucketCount("BrowserRenderProcessHost.ChildCrashes",
+ RENDERER_TYPE_EXTENSION, 2);
+
+ // One launch failure each.
+ histogram_tester.ExpectBucketCount(
+ "BrowserRenderProcessHost.ChildLaunchFailures", RENDERER_TYPE_RENDERER,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "BrowserRenderProcessHost.ChildLaunchFailures", RENDERER_TYPE_EXTENSION,
+ 1);
+ histogram_tester.ExpectBucketCount(
+ "BrowserRenderProcessHost.ChildLaunchFailureCodes", 1, 2);
+
+ // TERMINATION_STATUS_PROCESS_WAS_KILLED for a renderer.
+ histogram_tester.ExpectBucketCount("BrowserRenderProcessHost.ChildKills",
+ RENDERER_TYPE_RENDERER, 1);
+ histogram_tester.ExpectBucketCount("BrowserRenderProcessHost.ChildKills",
+ RENDERER_TYPE_EXTENSION, 0);
}
} // namespace metrics
diff --git a/chromium/components/metrics/system_memory_stats_recorder_win.cc b/chromium/components/metrics/system_memory_stats_recorder_win.cc
index 539d80ffb1b..7d011821a4d 100644
--- a/chromium/components/metrics/system_memory_stats_recorder_win.cc
+++ b/chromium/components/metrics/system_memory_stats_recorder_win.cc
@@ -23,7 +23,7 @@ void RecordMemoryStats(RecordMemoryStatsType type) {
switch (type) {
case RECORD_MEMORY_STATS_TAB_DISCARDED: {
UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.Stats.Win.MemoryLoad",
- mem_status.dwMemoryLoad, 0, 100, 101);
+ mem_status.dwMemoryLoad, 1, 100, 101);
UMA_HISTOGRAM_LARGE_MEMORY_MB("Memory.Stats.Win.TotalPhys2",
mem_status.ullTotalPhys / kMBytes);
UMA_HISTOGRAM_LARGE_MEMORY_MB("Memory.Stats.Win.AvailPhys2",
diff --git a/chromium/components/metrics/test_metrics_service_client.cc b/chromium/components/metrics/test_metrics_service_client.cc
index 643880b6582..7c7ccc68e07 100644
--- a/chromium/components/metrics/test_metrics_service_client.cc
+++ b/chromium/components/metrics/test_metrics_service_client.cc
@@ -31,13 +31,6 @@ void TestMetricsServiceClient::SetMetricsClientId(
client_id_ = client_id;
}
-void TestMetricsServiceClient::OnRecordingDisabled() {
-}
-
-bool TestMetricsServiceClient::IsOffTheRecordSessionActive() {
- return false;
-}
-
int32_t TestMetricsServiceClient::GetProduct() {
return product_;
}
diff --git a/chromium/components/metrics/test_metrics_service_client.h b/chromium/components/metrics/test_metrics_service_client.h
index e935f4a8792..355e7c7c5ae 100644
--- a/chromium/components/metrics/test_metrics_service_client.h
+++ b/chromium/components/metrics/test_metrics_service_client.h
@@ -26,8 +26,6 @@ class TestMetricsServiceClient : public MetricsServiceClient {
// MetricsServiceClient:
metrics::MetricsService* GetMetricsService() override;
void SetMetricsClientId(const std::string& client_id) override;
- void OnRecordingDisabled() override;
- bool IsOffTheRecordSessionActive() override;
int32_t GetProduct() override;
std::string GetApplicationLocale() override;
bool GetBrand(std::string* brand_code) override;
diff --git a/chromium/components/metrics/url_constants.cc b/chromium/components/metrics/url_constants.cc
index 87e721e85e7..4a744d56aff 100644
--- a/chromium/components/metrics/url_constants.cc
+++ b/chromium/components/metrics/url_constants.cc
@@ -8,7 +8,7 @@
namespace metrics {
-#if defined(OS_ANDROID)
+#if defined(OS_ANDROID) || defined(OS_IOS)
const char kDefaultMetricsServerUrl[] =
"https://clientservices.googleapis.com/uma/v2";
#else