Switch global error menu icon to vectorized MD asset
[chromium-blink-merge.git] / chrome / browser / metrics / chrome_stability_metrics_provider.cc
blob69135f7dd0047236965564094cb64fbd32d74a19
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/metrics/chrome_stability_metrics_provider.h"
7 #include <vector>
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "base/metrics/sparse_histogram.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/pref_service.h"
14 #include "chrome/browser/chrome_notification_types.h"
15 #include "chrome/common/chrome_constants.h"
16 #include "chrome/common/pref_names.h"
17 #include "components/metrics/proto/system_profile.pb.h"
18 #include "content/public/browser/child_process_data.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/user_metrics.h"
22 #include "content/public/browser/web_contents.h"
24 #if defined(ENABLE_EXTENSIONS)
25 #include "extensions/browser/process_map.h"
26 #endif
28 #if defined(ENABLE_PLUGINS)
29 #include "chrome/browser/metrics/plugin_metrics_provider.h"
30 #endif
32 #if defined(OS_WIN)
33 #include <windows.h> // Needed for STATUS_* codes
34 #include "chrome/installer/util/install_util.h"
35 #include "components/browser_watcher/crash_reporting_metrics_win.h"
36 #endif
38 #if defined(OS_CHROMEOS)
39 #include "chrome/browser/memory/system_memory_stats_recorder.h"
40 #endif
42 namespace {
44 enum RendererType {
45 RENDERER_TYPE_RENDERER,
46 RENDERER_TYPE_EXTENSION,
47 // NOTE: Add new action types only immediately above this line. Also,
48 // make sure the enum list in tools/metrics/histograms/histograms.xml is
49 // updated with any change in here.
50 RENDERER_TYPE_COUNT
53 // Converts an exit code into something that can be inserted into our
54 // histograms (which expect non-negative numbers less than MAX_INT).
55 int MapCrashExitCodeForHistogram(int exit_code) {
56 #if defined(OS_WIN)
57 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
58 // histograms.cc. Solve this by remapping it to a smaller value, which
59 // hopefully doesn't conflict with other codes.
60 if (exit_code == STATUS_GUARD_PAGE_VIOLATION)
61 return 0x1FCF7EC3; // Randomly picked number.
62 #endif
64 return std::abs(exit_code);
67 #if defined(OS_WIN)
68 void CountBrowserCrashDumpAttempts() {
69 enum Outcome {
70 OUTCOME_SUCCESS,
71 OUTCOME_FAILURE,
72 OUTCOME_UNKNOWN,
73 OUTCOME_MAX_VALUE
76 browser_watcher::CrashReportingMetrics::Values metrics =
77 browser_watcher::CrashReportingMetrics(
78 InstallUtil::IsChromeSxSProcess()
79 ? chrome::kBrowserCrashDumpAttemptsRegistryPathSxS
80 : chrome::kBrowserCrashDumpAttemptsRegistryPath)
81 .RetrieveAndResetMetrics();
83 for (int i = 0; i < metrics.crash_dump_attempts; ++i) {
84 Outcome outcome = OUTCOME_UNKNOWN;
85 if (i < metrics.successful_crash_dumps)
86 outcome = OUTCOME_SUCCESS;
87 else if (i < metrics.successful_crash_dumps + metrics.failed_crash_dumps)
88 outcome = OUTCOME_FAILURE;
90 UMA_STABILITY_HISTOGRAM_ENUMERATION("CrashReport.BreakpadCrashDumpOutcome",
91 outcome, OUTCOME_MAX_VALUE);
94 for (int i = 0; i < metrics.dump_without_crash_attempts; ++i) {
95 Outcome outcome = OUTCOME_UNKNOWN;
96 if (i < metrics.successful_dumps_without_crash) {
97 outcome = OUTCOME_SUCCESS;
98 } else if (i < metrics.successful_dumps_without_crash +
99 metrics.failed_dumps_without_crash) {
100 outcome = OUTCOME_FAILURE;
103 UMA_STABILITY_HISTOGRAM_ENUMERATION(
104 "CrashReport.BreakpadDumpWithoutCrashOutcome", outcome,
105 OUTCOME_MAX_VALUE);
108 #endif // defined(OS_WIN)
110 void RecordChildKills(int histogram_type) {
111 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills",
112 histogram_type, RENDERER_TYPE_COUNT);
115 } // namespace
117 ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider(
118 PrefService* local_state)
119 : local_state_(local_state) {
120 DCHECK(local_state_);
121 BrowserChildProcessObserver::Add(this);
124 ChromeStabilityMetricsProvider::~ChromeStabilityMetricsProvider() {
125 BrowserChildProcessObserver::Remove(this);
128 void ChromeStabilityMetricsProvider::OnRecordingEnabled() {
129 registrar_.Add(this,
130 content::NOTIFICATION_LOAD_START,
131 content::NotificationService::AllSources());
132 registrar_.Add(this,
133 content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
134 content::NotificationService::AllSources());
135 registrar_.Add(this,
136 content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
137 content::NotificationService::AllSources());
140 void ChromeStabilityMetricsProvider::OnRecordingDisabled() {
141 registrar_.RemoveAll();
144 void ChromeStabilityMetricsProvider::ProvideStabilityMetrics(
145 metrics::SystemProfileProto* system_profile_proto) {
146 metrics::SystemProfileProto_Stability* stability_proto =
147 system_profile_proto->mutable_stability();
149 int count = local_state_->GetInteger(prefs::kStabilityPageLoadCount);
150 if (count) {
151 stability_proto->set_page_load_count(count);
152 local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
155 count = local_state_->GetInteger(prefs::kStabilityChildProcessCrashCount);
156 if (count) {
157 stability_proto->set_child_process_crash_count(count);
158 local_state_->SetInteger(prefs::kStabilityChildProcessCrashCount, 0);
161 count = local_state_->GetInteger(prefs::kStabilityRendererCrashCount);
162 if (count) {
163 stability_proto->set_renderer_crash_count(count);
164 local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
167 count =
168 local_state_->GetInteger(prefs::kStabilityExtensionRendererCrashCount);
169 if (count) {
170 stability_proto->set_extension_renderer_crash_count(count);
171 local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
174 count = local_state_->GetInteger(prefs::kStabilityRendererHangCount);
175 if (count) {
176 stability_proto->set_renderer_hang_count(count);
177 local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
180 #if defined(OS_WIN)
181 CountBrowserCrashDumpAttempts();
182 #endif // defined(OS_WIN)
185 void ChromeStabilityMetricsProvider::ClearSavedStabilityMetrics() {
186 // Clear all the prefs used in this class in UMA reports (which doesn't
187 // include |kUninstallMetricsPageLoadCount| as it's not sent up by UMA).
188 local_state_->SetInteger(prefs::kStabilityChildProcessCrashCount, 0);
189 local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
190 local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
191 local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
192 local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
195 // static
196 void ChromeStabilityMetricsProvider::RegisterPrefs(
197 PrefRegistrySimple* registry) {
198 registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0);
199 registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount,
201 registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
202 registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
203 registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0);
205 registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0);
208 void ChromeStabilityMetricsProvider::Observe(
209 int type,
210 const content::NotificationSource& source,
211 const content::NotificationDetails& details) {
212 switch (type) {
213 case content::NOTIFICATION_LOAD_START: {
214 content::NavigationController* controller =
215 content::Source<content::NavigationController>(source).ptr();
216 content::WebContents* web_contents = controller->GetWebContents();
217 LogLoadStarted(web_contents);
218 break;
221 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
222 content::RenderProcessHost::RendererClosedDetails* process_details =
223 content::Details<content::RenderProcessHost::RendererClosedDetails>(
224 details).ptr();
225 content::RenderProcessHost* host =
226 content::Source<content::RenderProcessHost>(source).ptr();
227 LogRendererCrash(
228 host, process_details->status, process_details->exit_code);
229 break;
232 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
233 LogRendererHang();
234 break;
236 default:
237 NOTREACHED();
238 break;
242 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed(
243 const content::ChildProcessData& data,
244 int exit_code) {
245 #if defined(ENABLE_PLUGINS)
246 // Exclude plugin crashes from the count below because we report them via
247 // a separate UMA metric.
248 if (PluginMetricsProvider::IsPluginProcess(data.process_type))
249 return;
250 #endif
252 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
255 void ChromeStabilityMetricsProvider::LogLoadStarted(
256 content::WebContents* web_contents) {
257 content::RecordAction(base::UserMetricsAction("PageLoad"));
258 // TODO(asvitkine): Check if this is used for anything and if not, remove.
259 LOCAL_HISTOGRAM_BOOLEAN("Chrome.UmaPageloadCounter", true);
260 IncrementPrefValue(prefs::kStabilityPageLoadCount);
261 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
262 // We need to save the prefs, as page load count is a critical stat, and it
263 // might be lost due to a crash :-(.
266 void ChromeStabilityMetricsProvider::LogRendererCrash(
267 content::RenderProcessHost* host,
268 base::TerminationStatus status,
269 int exit_code) {
270 int histogram_type = RENDERER_TYPE_RENDERER;
271 bool was_extension_process = false;
272 #if defined(ENABLE_EXTENSIONS)
273 if (extensions::ProcessMap::Get(host->GetBrowserContext())
274 ->Contains(host->GetID())) {
275 histogram_type = RENDERER_TYPE_EXTENSION;
276 was_extension_process = true;
278 #endif
279 if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
280 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
281 if (was_extension_process) {
282 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
284 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
285 MapCrashExitCodeForHistogram(exit_code));
286 } else {
287 IncrementPrefValue(prefs::kStabilityRendererCrashCount);
289 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
290 MapCrashExitCodeForHistogram(exit_code));
293 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes",
294 histogram_type, RENDERER_TYPE_COUNT);
295 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
296 RecordChildKills(histogram_type);
297 #if defined(OS_CHROMEOS)
298 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
299 RecordChildKills(histogram_type);
300 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
301 was_extension_process ? 2 : 1,
303 memory::RecordMemoryStats(
304 was_extension_process
305 ? memory::RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
306 : memory::RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
307 #endif
308 } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
309 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive",
310 histogram_type, RENDERER_TYPE_COUNT);
311 } else if (status == base::TERMINATION_STATUS_LAUNCH_FAILED) {
312 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildLaunchFailures",
313 histogram_type, RENDERER_TYPE_COUNT);
314 // Treat child process launch as a crash for now.
315 if (was_extension_process)
316 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
317 else
318 IncrementPrefValue(prefs::kStabilityRendererCrashCount);
322 void ChromeStabilityMetricsProvider::IncrementPrefValue(const char* path) {
323 int value = local_state_->GetInteger(path);
324 local_state_->SetInteger(path, value + 1);
327 void ChromeStabilityMetricsProvider::IncrementLongPrefsValue(const char* path) {
328 int64 value = local_state_->GetInt64(path);
329 local_state_->SetInt64(path, value + 1);
332 void ChromeStabilityMetricsProvider::LogRendererHang() {
333 IncrementPrefValue(prefs::kStabilityRendererHangCount);