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"
39 #if defined(OS_CHROMEOS)
40 #include "chrome/browser/memory/system_memory_stats_recorder.h"
45 void IncrementPrefValue(const char* path
) {
46 PrefService
* pref
= g_browser_process
->local_state();
48 int value
= pref
->GetInteger(path
);
49 pref
->SetInteger(path
, value
+ 1);
52 void IncrementLongPrefsValue(const char* path
) {
53 PrefService
* pref
= g_browser_process
->local_state();
55 int64 value
= pref
->GetInt64(path
);
56 pref
->SetInt64(path
, value
+ 1);
59 // Converts an exit code into something that can be inserted into our
60 // histograms (which expect non-negative numbers less than MAX_INT).
61 int MapCrashExitCodeForHistogram(int exit_code
) {
63 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
64 // histograms.cc. Solve this by remapping it to a smaller value, which
65 // hopefully doesn't conflict with other codes.
66 if (exit_code
== STATUS_GUARD_PAGE_VIOLATION
)
67 return 0x1FCF7EC3; // Randomly picked number.
70 return std::abs(exit_code
);
74 void CountBrowserCrashDumpAttempts() {
82 browser_watcher::CrashReportingMetrics::Values metrics
=
83 browser_watcher::CrashReportingMetrics(
84 InstallUtil::IsChromeSxSProcess()
85 ? chrome::kBrowserCrashDumpAttemptsRegistryPathSxS
86 : chrome::kBrowserCrashDumpAttemptsRegistryPath
)
87 .RetrieveAndResetMetrics();
89 for (int i
= 0; i
< metrics
.crash_dump_attempts
; ++i
) {
90 Outcome outcome
= OUTCOME_UNKNOWN
;
91 if (i
< metrics
.successful_crash_dumps
)
92 outcome
= OUTCOME_SUCCESS
;
93 else if (i
< metrics
.successful_crash_dumps
+ metrics
.failed_crash_dumps
)
94 outcome
= OUTCOME_FAILURE
;
96 UMA_STABILITY_HISTOGRAM_ENUMERATION("CrashReport.BreakpadCrashDumpOutcome",
97 outcome
, OUTCOME_MAX_VALUE
);
100 for (int i
= 0; i
< metrics
.dump_without_crash_attempts
; ++i
) {
101 Outcome outcome
= OUTCOME_UNKNOWN
;
102 if (i
< metrics
.successful_dumps_without_crash
) {
103 outcome
= OUTCOME_SUCCESS
;
104 } else if (i
< metrics
.successful_dumps_without_crash
+
105 metrics
.failed_dumps_without_crash
) {
106 outcome
= OUTCOME_FAILURE
;
109 UMA_STABILITY_HISTOGRAM_ENUMERATION(
110 "CrashReport.BreakpadDumpWithoutCrashOutcome", outcome
,
114 #endif // defined(OS_WIN)
116 void RecordChildKills(bool was_extension_process
) {
117 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
118 was_extension_process
? 2 : 1);
123 ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider() {
124 BrowserChildProcessObserver::Add(this);
127 ChromeStabilityMetricsProvider::~ChromeStabilityMetricsProvider() {
128 BrowserChildProcessObserver::Remove(this);
131 void ChromeStabilityMetricsProvider::OnRecordingEnabled() {
133 content::NOTIFICATION_LOAD_START
,
134 content::NotificationService::AllSources());
136 content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
137 content::NotificationService::AllSources());
139 content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
,
140 content::NotificationService::AllSources());
143 void ChromeStabilityMetricsProvider::OnRecordingDisabled() {
144 registrar_
.RemoveAll();
147 void ChromeStabilityMetricsProvider::ProvideStabilityMetrics(
148 metrics::SystemProfileProto
* system_profile_proto
) {
149 PrefService
* pref
= g_browser_process
->local_state();
150 metrics::SystemProfileProto_Stability
* stability_proto
=
151 system_profile_proto
->mutable_stability();
153 int count
= pref
->GetInteger(prefs::kStabilityPageLoadCount
);
155 stability_proto
->set_page_load_count(count
);
156 pref
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
159 count
= pref
->GetInteger(prefs::kStabilityChildProcessCrashCount
);
161 stability_proto
->set_child_process_crash_count(count
);
162 pref
->SetInteger(prefs::kStabilityChildProcessCrashCount
, 0);
165 count
= pref
->GetInteger(prefs::kStabilityRendererCrashCount
);
167 stability_proto
->set_renderer_crash_count(count
);
168 pref
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
171 count
= pref
->GetInteger(prefs::kStabilityExtensionRendererCrashCount
);
173 stability_proto
->set_extension_renderer_crash_count(count
);
174 pref
->SetInteger(prefs::kStabilityExtensionRendererCrashCount
, 0);
177 count
= pref
->GetInteger(prefs::kStabilityRendererHangCount
);
179 stability_proto
->set_renderer_hang_count(count
);
180 pref
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
184 CountBrowserCrashDumpAttempts();
185 #endif // defined(OS_WIN)
188 void ChromeStabilityMetricsProvider::ClearSavedStabilityMetrics() {
189 PrefService
* local_state
= g_browser_process
->local_state();
191 // Clear all the prefs used in this class in UMA reports (which doesn't
192 // include |kUninstallMetricsPageLoadCount| as it's not sent up by UMA).
193 local_state
->SetInteger(prefs::kStabilityChildProcessCrashCount
, 0);
194 local_state
->SetInteger(prefs::kStabilityExtensionRendererCrashCount
, 0);
195 local_state
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
196 local_state
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
197 local_state
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
201 void ChromeStabilityMetricsProvider::RegisterPrefs(
202 PrefRegistrySimple
* registry
) {
203 registry
->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount
, 0);
204 registry
->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount
,
206 registry
->RegisterIntegerPref(prefs::kStabilityPageLoadCount
, 0);
207 registry
->RegisterIntegerPref(prefs::kStabilityRendererCrashCount
, 0);
208 registry
->RegisterIntegerPref(prefs::kStabilityRendererHangCount
, 0);
210 registry
->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount
, 0);
213 void ChromeStabilityMetricsProvider::Observe(
215 const content::NotificationSource
& source
,
216 const content::NotificationDetails
& details
) {
218 case content::NOTIFICATION_LOAD_START
: {
219 content::NavigationController
* controller
=
220 content::Source
<content::NavigationController
>(source
).ptr();
221 content::WebContents
* web_contents
= controller
->GetWebContents();
222 LogLoadStarted(web_contents
);
226 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
227 content::RenderProcessHost::RendererClosedDetails
* process_details
=
228 content::Details
<content::RenderProcessHost::RendererClosedDetails
>(
230 content::RenderProcessHost
* host
=
231 content::Source
<content::RenderProcessHost
>(source
).ptr();
233 host
, process_details
->status
, process_details
->exit_code
);
237 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
:
247 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed(
248 const content::ChildProcessData
& data
,
250 #if defined(ENABLE_PLUGINS)
251 // Exclude plugin crashes from the count below because we report them via
252 // a separate UMA metric.
253 if (PluginMetricsProvider::IsPluginProcess(data
.process_type
))
257 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount
);
260 void ChromeStabilityMetricsProvider::LogLoadStarted(
261 content::WebContents
* web_contents
) {
262 content::RecordAction(base::UserMetricsAction("PageLoad"));
263 // TODO(asvitkine): Check if this is used for anything and if not, remove.
264 LOCAL_HISTOGRAM_BOOLEAN("Chrome.UmaPageloadCounter", true);
265 IncrementPrefValue(prefs::kStabilityPageLoadCount
);
266 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount
);
267 // We need to save the prefs, as page load count is a critical stat, and it
268 // might be lost due to a crash :-(.
271 void ChromeStabilityMetricsProvider::LogRendererCrash(
272 content::RenderProcessHost
* host
,
273 base::TerminationStatus status
,
275 bool was_extension_process
= false;
276 #if defined(ENABLE_EXTENSIONS)
277 was_extension_process
=
278 extensions::ProcessMap::Get(host
->GetBrowserContext())->Contains(
281 if (status
== base::TERMINATION_STATUS_PROCESS_CRASHED
||
282 status
== base::TERMINATION_STATUS_ABNORMAL_TERMINATION
) {
283 if (was_extension_process
) {
284 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount
);
286 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
287 MapCrashExitCodeForHistogram(exit_code
));
289 IncrementPrefValue(prefs::kStabilityRendererCrashCount
);
291 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
292 MapCrashExitCodeForHistogram(exit_code
));
295 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
296 was_extension_process
? 2 : 1);
297 } else if (status
== base::TERMINATION_STATUS_PROCESS_WAS_KILLED
) {
298 RecordChildKills(was_extension_process
);
299 #if defined(OS_CHROMEOS)
300 } else if (status
== base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM
) {
301 RecordChildKills(was_extension_process
);
302 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
303 was_extension_process
? 2 : 1,
305 memory::RecordMemoryStats(
306 was_extension_process
307 ? memory::RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
308 : memory::RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED
);
310 } else if (status
== base::TERMINATION_STATUS_STILL_RUNNING
) {
311 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
312 was_extension_process
? 2 : 1);
316 void ChromeStabilityMetricsProvider::LogRendererHang() {
317 IncrementPrefValue(prefs::kStabilityRendererHangCount
);