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"
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/browser_process.h"
15 #include "chrome/browser/chrome_notification_types.h"
16 #include "chrome/common/chrome_constants.h"
17 #include "chrome/common/pref_names.h"
18 #include "components/metrics/proto/system_profile.pb.h"
19 #include "content/public/browser/child_process_data.h"
20 #include "content/public/browser/notification_service.h"
21 #include "content/public/browser/render_process_host.h"
22 #include "content/public/browser/user_metrics.h"
23 #include "content/public/browser/web_contents.h"
25 #if defined(ENABLE_EXTENSIONS)
26 #include "extensions/browser/process_map.h"
29 #if defined(ENABLE_PLUGINS)
30 #include "chrome/browser/metrics/plugin_metrics_provider.h"
34 #include <windows.h> // Needed for STATUS_* codes
35 #include "chrome/installer/util/install_util.h"
36 #include "components/browser_watcher/crash_reporting_metrics_win.h"
41 void IncrementPrefValue(const char* path
) {
42 PrefService
* pref
= g_browser_process
->local_state();
44 int value
= pref
->GetInteger(path
);
45 pref
->SetInteger(path
, value
+ 1);
48 void IncrementLongPrefsValue(const char* path
) {
49 PrefService
* pref
= g_browser_process
->local_state();
51 int64 value
= pref
->GetInt64(path
);
52 pref
->SetInt64(path
, value
+ 1);
55 // Converts an exit code into something that can be inserted into our
56 // histograms (which expect non-negative numbers less than MAX_INT).
57 int MapCrashExitCodeForHistogram(int exit_code
) {
59 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
60 // histograms.cc. Solve this by remapping it to a smaller value, which
61 // hopefully doesn't conflict with other codes.
62 if (exit_code
== STATUS_GUARD_PAGE_VIOLATION
)
63 return 0x1FCF7EC3; // Randomly picked number.
66 return std::abs(exit_code
);
70 void CountBrowserCrashDumpAttempts() {
78 browser_watcher::CrashReportingMetrics::Values metrics
=
79 browser_watcher::CrashReportingMetrics(
80 InstallUtil::IsChromeSxSProcess()
81 ? chrome::kBrowserCrashDumpAttemptsRegistryPathSxS
82 : chrome::kBrowserCrashDumpAttemptsRegistryPath
)
83 .RetrieveAndResetMetrics();
85 for (int i
= 0; i
< metrics
.crash_dump_attempts
; ++i
) {
86 Outcome outcome
= OUTCOME_UNKNOWN
;
87 if (i
< metrics
.successful_crash_dumps
)
88 outcome
= OUTCOME_SUCCESS
;
89 else if (i
< metrics
.successful_crash_dumps
+ metrics
.failed_crash_dumps
)
90 outcome
= OUTCOME_FAILURE
;
92 UMA_STABILITY_HISTOGRAM_ENUMERATION("CrashReport.BreakpadCrashDumpOutcome",
93 outcome
, OUTCOME_MAX_VALUE
);
96 for (int i
= 0; i
< metrics
.dump_without_crash_attempts
; ++i
) {
97 Outcome outcome
= OUTCOME_UNKNOWN
;
98 if (i
< metrics
.successful_dumps_without_crash
) {
99 outcome
= OUTCOME_SUCCESS
;
100 } else if (i
< metrics
.successful_dumps_without_crash
+
101 metrics
.failed_dumps_without_crash
) {
102 outcome
= OUTCOME_FAILURE
;
105 UMA_STABILITY_HISTOGRAM_ENUMERATION(
106 "CrashReport.BreakpadDumpWithoutCrashOutcome", outcome
,
110 #endif // defined(OS_WIN)
114 ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider() {
115 BrowserChildProcessObserver::Add(this);
118 ChromeStabilityMetricsProvider::~ChromeStabilityMetricsProvider() {
119 BrowserChildProcessObserver::Remove(this);
122 void ChromeStabilityMetricsProvider::OnRecordingEnabled() {
124 content::NOTIFICATION_LOAD_START
,
125 content::NotificationService::AllSources());
127 content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
128 content::NotificationService::AllSources());
130 content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
,
131 content::NotificationService::AllSources());
134 void ChromeStabilityMetricsProvider::OnRecordingDisabled() {
135 registrar_
.RemoveAll();
138 void ChromeStabilityMetricsProvider::ProvideStabilityMetrics(
139 metrics::SystemProfileProto
* system_profile_proto
) {
140 PrefService
* pref
= g_browser_process
->local_state();
141 metrics::SystemProfileProto_Stability
* stability_proto
=
142 system_profile_proto
->mutable_stability();
144 int count
= pref
->GetInteger(prefs::kStabilityPageLoadCount
);
146 stability_proto
->set_page_load_count(count
);
147 pref
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
150 count
= pref
->GetInteger(prefs::kStabilityChildProcessCrashCount
);
152 stability_proto
->set_child_process_crash_count(count
);
153 pref
->SetInteger(prefs::kStabilityChildProcessCrashCount
, 0);
156 count
= pref
->GetInteger(prefs::kStabilityRendererCrashCount
);
158 stability_proto
->set_renderer_crash_count(count
);
159 pref
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
162 count
= pref
->GetInteger(prefs::kStabilityExtensionRendererCrashCount
);
164 stability_proto
->set_extension_renderer_crash_count(count
);
165 pref
->SetInteger(prefs::kStabilityExtensionRendererCrashCount
, 0);
168 count
= pref
->GetInteger(prefs::kStabilityRendererHangCount
);
170 stability_proto
->set_renderer_hang_count(count
);
171 pref
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
175 CountBrowserCrashDumpAttempts();
176 #endif // defined(OS_WIN)
179 void ChromeStabilityMetricsProvider::ClearSavedStabilityMetrics() {
180 PrefService
* local_state
= g_browser_process
->local_state();
182 // Clear all the prefs used in this class in UMA reports (which doesn't
183 // include |kUninstallMetricsPageLoadCount| as it's not sent up by UMA).
184 local_state
->SetInteger(prefs::kStabilityChildProcessCrashCount
, 0);
185 local_state
->SetInteger(prefs::kStabilityExtensionRendererCrashCount
, 0);
186 local_state
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
187 local_state
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
188 local_state
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
192 void ChromeStabilityMetricsProvider::RegisterPrefs(
193 PrefRegistrySimple
* registry
) {
194 registry
->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount
, 0);
195 registry
->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount
,
197 registry
->RegisterIntegerPref(prefs::kStabilityPageLoadCount
, 0);
198 registry
->RegisterIntegerPref(prefs::kStabilityRendererCrashCount
, 0);
199 registry
->RegisterIntegerPref(prefs::kStabilityRendererHangCount
, 0);
201 registry
->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount
, 0);
204 void ChromeStabilityMetricsProvider::Observe(
206 const content::NotificationSource
& source
,
207 const content::NotificationDetails
& details
) {
209 case content::NOTIFICATION_LOAD_START
: {
210 content::NavigationController
* controller
=
211 content::Source
<content::NavigationController
>(source
).ptr();
212 content::WebContents
* web_contents
= controller
->GetWebContents();
213 LogLoadStarted(web_contents
);
217 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
218 content::RenderProcessHost::RendererClosedDetails
* process_details
=
219 content::Details
<content::RenderProcessHost::RendererClosedDetails
>(
221 content::RenderProcessHost
* host
=
222 content::Source
<content::RenderProcessHost
>(source
).ptr();
224 host
, process_details
->status
, process_details
->exit_code
);
228 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
:
238 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed(
239 const content::ChildProcessData
& data
) {
240 #if defined(ENABLE_PLUGINS)
241 // Exclude plugin crashes from the count below because we report them via
242 // a separate UMA metric.
243 if (PluginMetricsProvider::IsPluginProcess(data
.process_type
))
247 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount
);
250 void ChromeStabilityMetricsProvider::LogLoadStarted(
251 content::WebContents
* web_contents
) {
252 content::RecordAction(base::UserMetricsAction("PageLoad"));
253 // TODO(asvitkine): Check if this is used for anything and if not, remove.
254 LOCAL_HISTOGRAM_BOOLEAN("Chrome.UmaPageloadCounter", true);
255 IncrementPrefValue(prefs::kStabilityPageLoadCount
);
256 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount
);
257 // We need to save the prefs, as page load count is a critical stat, and it
258 // might be lost due to a crash :-(.
261 void ChromeStabilityMetricsProvider::LogRendererCrash(
262 content::RenderProcessHost
* host
,
263 base::TerminationStatus status
,
265 bool was_extension_process
= false;
266 #if defined(ENABLE_EXTENSIONS)
267 was_extension_process
=
268 extensions::ProcessMap::Get(host
->GetBrowserContext())->Contains(
271 if (status
== base::TERMINATION_STATUS_PROCESS_CRASHED
||
272 status
== base::TERMINATION_STATUS_ABNORMAL_TERMINATION
) {
273 if (was_extension_process
) {
274 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount
);
276 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
277 MapCrashExitCodeForHistogram(exit_code
));
279 IncrementPrefValue(prefs::kStabilityRendererCrashCount
);
281 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
282 MapCrashExitCodeForHistogram(exit_code
));
285 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
286 was_extension_process
? 2 : 1);
287 } else if (status
== base::TERMINATION_STATUS_PROCESS_WAS_KILLED
) {
288 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
289 was_extension_process
? 2 : 1);
290 } else if (status
== base::TERMINATION_STATUS_STILL_RUNNING
) {
291 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
292 was_extension_process
? 2 : 1);
296 void ChromeStabilityMetricsProvider::LogRendererHang() {
297 IncrementPrefValue(prefs::kStabilityRendererHangCount
);