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/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"
23 #include "extensions/browser/process_map.h"
25 #if defined(ENABLE_PLUGINS)
26 #include "chrome/browser/metrics/plugin_metrics_provider.h"
30 #include <windows.h> // Needed for STATUS_* codes
35 void IncrementPrefValue(const char* path
) {
36 PrefService
* pref
= g_browser_process
->local_state();
38 int value
= pref
->GetInteger(path
);
39 pref
->SetInteger(path
, value
+ 1);
42 void IncrementLongPrefsValue(const char* path
) {
43 PrefService
* pref
= g_browser_process
->local_state();
45 int64 value
= pref
->GetInt64(path
);
46 pref
->SetInt64(path
, value
+ 1);
49 // Converts an exit code into something that can be inserted into our
50 // histograms (which expect non-negative numbers less than MAX_INT).
51 int MapCrashExitCodeForHistogram(int exit_code
) {
53 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
54 // histograms.cc. Solve this by remapping it to a smaller value, which
55 // hopefully doesn't conflict with other codes.
56 if (exit_code
== STATUS_GUARD_PAGE_VIOLATION
)
57 return 0x1FCF7EC3; // Randomly picked number.
60 return std::abs(exit_code
);
65 ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider() {
66 BrowserChildProcessObserver::Add(this);
69 ChromeStabilityMetricsProvider::~ChromeStabilityMetricsProvider() {
70 BrowserChildProcessObserver::Remove(this);
73 void ChromeStabilityMetricsProvider::OnRecordingEnabled() {
75 content::NOTIFICATION_LOAD_START
,
76 content::NotificationService::AllSources());
78 content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
79 content::NotificationService::AllSources());
81 content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
,
82 content::NotificationService::AllSources());
85 void ChromeStabilityMetricsProvider::OnRecordingDisabled() {
86 registrar_
.RemoveAll();
89 void ChromeStabilityMetricsProvider::ProvideStabilityMetrics(
90 metrics::SystemProfileProto
* system_profile_proto
) {
91 PrefService
* pref
= g_browser_process
->local_state();
92 metrics::SystemProfileProto_Stability
* stability_proto
=
93 system_profile_proto
->mutable_stability();
95 int count
= pref
->GetInteger(prefs::kStabilityPageLoadCount
);
97 stability_proto
->set_page_load_count(count
);
98 pref
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
101 count
= pref
->GetInteger(prefs::kStabilityChildProcessCrashCount
);
103 stability_proto
->set_child_process_crash_count(count
);
104 pref
->SetInteger(prefs::kStabilityChildProcessCrashCount
, 0);
107 count
= pref
->GetInteger(prefs::kStabilityRendererCrashCount
);
109 stability_proto
->set_renderer_crash_count(count
);
110 pref
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
113 count
= pref
->GetInteger(prefs::kStabilityExtensionRendererCrashCount
);
115 stability_proto
->set_extension_renderer_crash_count(count
);
116 pref
->SetInteger(prefs::kStabilityExtensionRendererCrashCount
, 0);
119 count
= pref
->GetInteger(prefs::kStabilityRendererHangCount
);
121 stability_proto
->set_renderer_hang_count(count
);
122 pref
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
127 void ChromeStabilityMetricsProvider::RegisterPrefs(
128 PrefRegistrySimple
* registry
) {
129 registry
->RegisterIntegerPref(prefs::kStabilityPageLoadCount
, 0);
130 registry
->RegisterIntegerPref(prefs::kStabilityRendererCrashCount
, 0);
131 registry
->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount
,
133 registry
->RegisterIntegerPref(prefs::kStabilityRendererHangCount
, 0);
134 registry
->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount
, 0);
135 registry
->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount
, 0);
138 void ChromeStabilityMetricsProvider::Observe(
140 const content::NotificationSource
& source
,
141 const content::NotificationDetails
& details
) {
143 case content::NOTIFICATION_LOAD_START
: {
144 content::NavigationController
* controller
=
145 content::Source
<content::NavigationController
>(source
).ptr();
146 content::WebContents
* web_contents
= controller
->GetWebContents();
147 LogLoadStarted(web_contents
);
151 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
152 content::RenderProcessHost::RendererClosedDetails
* process_details
=
153 content::Details
<content::RenderProcessHost::RendererClosedDetails
>(
155 content::RenderProcessHost
* host
=
156 content::Source
<content::RenderProcessHost
>(source
).ptr();
158 host
, process_details
->status
, process_details
->exit_code
);
162 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
:
172 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed(
173 const content::ChildProcessData
& data
) {
174 #if defined(ENABLE_PLUGINS)
175 // Exclude plugin crashes from the count below because we report them via
176 // a separate UMA metric.
177 if (PluginMetricsProvider::IsPluginProcess(data
.process_type
))
181 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount
);
184 void ChromeStabilityMetricsProvider::LogLoadStarted(
185 content::WebContents
* web_contents
) {
186 content::RecordAction(base::UserMetricsAction("PageLoad"));
187 HISTOGRAM_ENUMERATION("Chrome.UmaPageloadCounter", 1, 2);
188 IncrementPrefValue(prefs::kStabilityPageLoadCount
);
189 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount
);
190 // We need to save the prefs, as page load count is a critical stat, and it
191 // might be lost due to a crash :-(.
194 void ChromeStabilityMetricsProvider::LogRendererCrash(
195 content::RenderProcessHost
* host
,
196 base::TerminationStatus status
,
198 bool was_extension_process
=
199 extensions::ProcessMap::Get(host
->GetBrowserContext())
200 ->Contains(host
->GetID());
201 if (status
== base::TERMINATION_STATUS_PROCESS_CRASHED
||
202 status
== base::TERMINATION_STATUS_ABNORMAL_TERMINATION
) {
203 if (was_extension_process
) {
204 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount
);
206 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
207 MapCrashExitCodeForHistogram(exit_code
));
209 IncrementPrefValue(prefs::kStabilityRendererCrashCount
);
211 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
212 MapCrashExitCodeForHistogram(exit_code
));
215 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildCrashes",
216 was_extension_process
? 2 : 1);
217 } else if (status
== base::TERMINATION_STATUS_PROCESS_WAS_KILLED
) {
218 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.ChildKills",
219 was_extension_process
? 2 : 1);
220 } else if (status
== base::TERMINATION_STATUS_STILL_RUNNING
) {
221 UMA_HISTOGRAM_PERCENTAGE("BrowserRenderProcessHost.DisconnectedAlive",
222 was_extension_process
? 2 : 1);
226 void ChromeStabilityMetricsProvider::LogRendererHang() {
227 IncrementPrefValue(prefs::kStabilityRendererHangCount
);