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/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"
28 #if defined(ENABLE_PLUGINS)
29 #include "chrome/browser/metrics/plugin_metrics_provider.h"
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"
38 #if defined(OS_CHROMEOS)
39 #include "chrome/browser/memory/system_memory_stats_recorder.h"
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.
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
) {
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.
64 return std::abs(exit_code
);
68 void CountBrowserCrashDumpAttempts() {
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
,
108 #endif // defined(OS_WIN)
110 void RecordChildKills(int histogram_type
) {
111 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills",
112 histogram_type
, RENDERER_TYPE_COUNT
);
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() {
130 content::NOTIFICATION_LOAD_START
,
131 content::NotificationService::AllSources());
133 content::NOTIFICATION_RENDERER_PROCESS_CLOSED
,
134 content::NotificationService::AllSources());
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
);
151 stability_proto
->set_page_load_count(count
);
152 local_state_
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
155 count
= local_state_
->GetInteger(prefs::kStabilityChildProcessCrashCount
);
157 stability_proto
->set_child_process_crash_count(count
);
158 local_state_
->SetInteger(prefs::kStabilityChildProcessCrashCount
, 0);
161 count
= local_state_
->GetInteger(prefs::kStabilityRendererCrashCount
);
163 stability_proto
->set_renderer_crash_count(count
);
164 local_state_
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
167 count
= local_state_
->GetInteger(prefs::kStabilityRendererFailedLaunchCount
);
169 stability_proto
->set_renderer_failed_launch_count(count
);
170 local_state_
->SetInteger(prefs::kStabilityRendererFailedLaunchCount
, 0);
174 local_state_
->GetInteger(prefs::kStabilityExtensionRendererCrashCount
);
176 stability_proto
->set_extension_renderer_crash_count(count
);
177 local_state_
->SetInteger(prefs::kStabilityExtensionRendererCrashCount
, 0);
180 count
= local_state_
->GetInteger(
181 prefs::kStabilityExtensionRendererFailedLaunchCount
);
183 stability_proto
->set_extension_renderer_failed_launch_count(count
);
184 local_state_
->SetInteger(
185 prefs::kStabilityExtensionRendererFailedLaunchCount
, 0);
188 count
= local_state_
->GetInteger(prefs::kStabilityRendererHangCount
);
190 stability_proto
->set_renderer_hang_count(count
);
191 local_state_
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
195 CountBrowserCrashDumpAttempts();
196 #endif // defined(OS_WIN)
199 void ChromeStabilityMetricsProvider::ClearSavedStabilityMetrics() {
200 // Clear all the prefs used in this class in UMA reports (which doesn't
201 // include |kUninstallMetricsPageLoadCount| as it's not sent up by UMA).
202 local_state_
->SetInteger(prefs::kStabilityChildProcessCrashCount
, 0);
203 local_state_
->SetInteger(prefs::kStabilityExtensionRendererCrashCount
, 0);
204 local_state_
->SetInteger(prefs::kStabilityExtensionRendererFailedLaunchCount
,
206 local_state_
->SetInteger(prefs::kStabilityPageLoadCount
, 0);
207 local_state_
->SetInteger(prefs::kStabilityRendererCrashCount
, 0);
208 local_state_
->SetInteger(prefs::kStabilityRendererFailedLaunchCount
, 0);
209 local_state_
->SetInteger(prefs::kStabilityRendererHangCount
, 0);
213 void ChromeStabilityMetricsProvider::RegisterPrefs(
214 PrefRegistrySimple
* registry
) {
215 registry
->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount
, 0);
216 registry
->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount
,
218 registry
->RegisterIntegerPref(
219 prefs::kStabilityExtensionRendererFailedLaunchCount
, 0);
220 registry
->RegisterIntegerPref(prefs::kStabilityPageLoadCount
, 0);
221 registry
->RegisterIntegerPref(prefs::kStabilityRendererCrashCount
, 0);
222 registry
->RegisterIntegerPref(prefs::kStabilityRendererFailedLaunchCount
, 0);
223 registry
->RegisterIntegerPref(prefs::kStabilityRendererHangCount
, 0);
225 registry
->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount
, 0);
228 void ChromeStabilityMetricsProvider::Observe(
230 const content::NotificationSource
& source
,
231 const content::NotificationDetails
& details
) {
233 case content::NOTIFICATION_LOAD_START
: {
234 content::NavigationController
* controller
=
235 content::Source
<content::NavigationController
>(source
).ptr();
236 content::WebContents
* web_contents
= controller
->GetWebContents();
237 LogLoadStarted(web_contents
);
241 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED
: {
242 content::RenderProcessHost::RendererClosedDetails
* process_details
=
243 content::Details
<content::RenderProcessHost::RendererClosedDetails
>(
245 content::RenderProcessHost
* host
=
246 content::Source
<content::RenderProcessHost
>(source
).ptr();
248 host
, process_details
->status
, process_details
->exit_code
);
252 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG
:
262 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed(
263 const content::ChildProcessData
& data
,
265 #if defined(ENABLE_PLUGINS)
266 // Exclude plugin crashes from the count below because we report them via
267 // a separate UMA metric.
268 if (PluginMetricsProvider::IsPluginProcess(data
.process_type
))
272 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount
);
275 void ChromeStabilityMetricsProvider::LogLoadStarted(
276 content::WebContents
* web_contents
) {
277 content::RecordAction(base::UserMetricsAction("PageLoad"));
278 // TODO(asvitkine): Check if this is used for anything and if not, remove.
279 LOCAL_HISTOGRAM_BOOLEAN("Chrome.UmaPageloadCounter", true);
280 IncrementPrefValue(prefs::kStabilityPageLoadCount
);
281 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount
);
282 // We need to save the prefs, as page load count is a critical stat, and it
283 // might be lost due to a crash :-(.
286 void ChromeStabilityMetricsProvider::LogRendererCrash(
287 content::RenderProcessHost
* host
,
288 base::TerminationStatus status
,
290 int histogram_type
= RENDERER_TYPE_RENDERER
;
291 bool was_extension_process
= false;
292 #if defined(ENABLE_EXTENSIONS)
293 if (extensions::ProcessMap::Get(host
->GetBrowserContext())
294 ->Contains(host
->GetID())) {
295 histogram_type
= RENDERER_TYPE_EXTENSION
;
296 was_extension_process
= true;
299 if (status
== base::TERMINATION_STATUS_PROCESS_CRASHED
||
300 status
== base::TERMINATION_STATUS_ABNORMAL_TERMINATION
) {
301 if (was_extension_process
) {
302 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount
);
304 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
305 MapCrashExitCodeForHistogram(exit_code
));
307 IncrementPrefValue(prefs::kStabilityRendererCrashCount
);
309 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
310 MapCrashExitCodeForHistogram(exit_code
));
313 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes",
314 histogram_type
, RENDERER_TYPE_COUNT
);
315 } else if (status
== base::TERMINATION_STATUS_PROCESS_WAS_KILLED
) {
316 RecordChildKills(histogram_type
);
317 #if defined(OS_CHROMEOS)
318 } else if (status
== base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM
) {
319 RecordChildKills(histogram_type
);
320 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
321 was_extension_process
? 2 : 1,
323 memory::RecordMemoryStats(
324 was_extension_process
325 ? memory::RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
326 : memory::RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED
);
328 } else if (status
== base::TERMINATION_STATUS_STILL_RUNNING
) {
329 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive",
330 histogram_type
, RENDERER_TYPE_COUNT
);
331 } else if (status
== base::TERMINATION_STATUS_LAUNCH_FAILED
) {
332 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildLaunchFailures",
333 histogram_type
, RENDERER_TYPE_COUNT
);
334 if (was_extension_process
)
335 IncrementPrefValue(prefs::kStabilityExtensionRendererFailedLaunchCount
);
337 IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount
);
341 void ChromeStabilityMetricsProvider::IncrementPrefValue(const char* path
) {
342 int value
= local_state_
->GetInteger(path
);
343 local_state_
->SetInteger(path
, value
+ 1);
346 void ChromeStabilityMetricsProvider::IncrementLongPrefsValue(const char* path
) {
347 int64 value
= local_state_
->GetInt64(path
);
348 local_state_
->SetInt64(path
, value
+ 1);
351 void ChromeStabilityMetricsProvider::LogRendererHang() {
352 IncrementPrefValue(prefs::kStabilityRendererHangCount
);