OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/metrics/chrome_stability_metrics_provider.h" | 5 #include "chrome/browser/metrics/chrome_stability_metrics_provider.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/logging.h" | 9 #include "base/logging.h" |
10 #include "base/metrics/histogram.h" | 10 #include "base/metrics/histogram.h" |
11 #include "base/metrics/sparse_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" | 12 #include "chrome/browser/chrome_notification_types.h" |
15 #include "chrome/common/chrome_constants.h" | 13 #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" | 14 #include "content/public/browser/child_process_data.h" |
19 #include "content/public/browser/notification_service.h" | 15 #include "content/public/browser/notification_service.h" |
20 #include "content/public/browser/render_process_host.h" | 16 #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 | 17 |
24 #if defined(ENABLE_EXTENSIONS) | 18 #if defined(ENABLE_EXTENSIONS) |
25 #include "extensions/browser/process_map.h" | 19 #include "extensions/browser/process_map.h" |
26 #endif | 20 #endif |
27 | 21 |
28 #if defined(ENABLE_PLUGINS) | 22 #if defined(ENABLE_PLUGINS) |
29 #include "chrome/browser/metrics/plugin_metrics_provider.h" | 23 #include "chrome/browser/metrics/plugin_metrics_provider.h" |
30 #endif | 24 #endif |
31 | 25 |
32 #if defined(OS_WIN) | 26 #if defined(OS_WIN) |
33 #include <windows.h> // Needed for STATUS_* codes | 27 #include <windows.h> // Needed for STATUS_* codes |
34 #include "chrome/installer/util/install_util.h" | 28 #include "chrome/installer/util/install_util.h" |
35 #include "components/browser_watcher/crash_reporting_metrics_win.h" | 29 #include "components/browser_watcher/crash_reporting_metrics_win.h" |
36 #endif | 30 #endif |
37 | 31 |
38 #if defined(OS_CHROMEOS) | |
39 #include "chrome/browser/memory/system_memory_stats_recorder.h" | |
40 #endif | |
41 | |
42 namespace { | 32 namespace { |
43 | 33 |
44 enum RendererType { | |
45 RENDERER_TYPE_RENDERER = 1, | |
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 | |
51 }; | |
52 | |
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 | |
63 | |
64 return std::abs(exit_code); | |
65 } | |
66 | |
67 #if defined(OS_WIN) | 34 #if defined(OS_WIN) |
68 void CountBrowserCrashDumpAttempts() { | 35 void CountBrowserCrashDumpAttempts() { |
69 enum Outcome { | 36 enum Outcome { |
70 OUTCOME_SUCCESS, | 37 OUTCOME_SUCCESS, |
71 OUTCOME_FAILURE, | 38 OUTCOME_FAILURE, |
72 OUTCOME_UNKNOWN, | 39 OUTCOME_UNKNOWN, |
73 OUTCOME_MAX_VALUE | 40 OUTCOME_MAX_VALUE |
74 }; | 41 }; |
75 | 42 |
76 browser_watcher::CrashReportingMetrics::Values metrics = | 43 browser_watcher::CrashReportingMetrics::Values metrics = |
(...skipping 23 matching lines...) Expand all Loading... |
100 outcome = OUTCOME_FAILURE; | 67 outcome = OUTCOME_FAILURE; |
101 } | 68 } |
102 | 69 |
103 UMA_STABILITY_HISTOGRAM_ENUMERATION( | 70 UMA_STABILITY_HISTOGRAM_ENUMERATION( |
104 "CrashReport.BreakpadDumpWithoutCrashOutcome", outcome, | 71 "CrashReport.BreakpadDumpWithoutCrashOutcome", outcome, |
105 OUTCOME_MAX_VALUE); | 72 OUTCOME_MAX_VALUE); |
106 } | 73 } |
107 } | 74 } |
108 #endif // defined(OS_WIN) | 75 #endif // defined(OS_WIN) |
109 | 76 |
110 void RecordChildKills(int histogram_type) { | |
111 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills", | |
112 histogram_type, RENDERER_TYPE_COUNT); | |
113 } | |
114 | |
115 } // namespace | 77 } // namespace |
116 | 78 |
117 ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider( | 79 ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider( |
118 PrefService* local_state) | 80 PrefService* local_state) |
119 : local_state_(local_state) { | 81 : helper_(local_state) { |
120 DCHECK(local_state_); | |
121 BrowserChildProcessObserver::Add(this); | 82 BrowserChildProcessObserver::Add(this); |
122 } | 83 } |
123 | 84 |
124 ChromeStabilityMetricsProvider::~ChromeStabilityMetricsProvider() { | 85 ChromeStabilityMetricsProvider::~ChromeStabilityMetricsProvider() { |
125 BrowserChildProcessObserver::Remove(this); | 86 BrowserChildProcessObserver::Remove(this); |
126 } | 87 } |
127 | 88 |
128 void ChromeStabilityMetricsProvider::OnRecordingEnabled() { | 89 void ChromeStabilityMetricsProvider::OnRecordingEnabled() { |
129 registrar_.Add(this, | 90 registrar_.Add(this, |
130 content::NOTIFICATION_LOAD_START, | 91 content::NOTIFICATION_LOAD_START, |
131 content::NotificationService::AllSources()); | 92 content::NotificationService::AllSources()); |
132 registrar_.Add(this, | 93 registrar_.Add(this, |
133 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | 94 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
134 content::NotificationService::AllSources()); | 95 content::NotificationService::AllSources()); |
135 registrar_.Add(this, | 96 registrar_.Add(this, |
136 content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, | 97 content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, |
137 content::NotificationService::AllSources()); | 98 content::NotificationService::AllSources()); |
138 } | 99 } |
139 | 100 |
140 void ChromeStabilityMetricsProvider::OnRecordingDisabled() { | 101 void ChromeStabilityMetricsProvider::OnRecordingDisabled() { |
141 registrar_.RemoveAll(); | 102 registrar_.RemoveAll(); |
142 } | 103 } |
143 | 104 |
144 void ChromeStabilityMetricsProvider::ProvideStabilityMetrics( | 105 void ChromeStabilityMetricsProvider::ProvideStabilityMetrics( |
145 metrics::SystemProfileProto* system_profile_proto) { | 106 metrics::SystemProfileProto* system_profile_proto) { |
146 metrics::SystemProfileProto_Stability* stability_proto = | 107 helper_.ProvideStabilityMetrics(system_profile_proto); |
147 system_profile_proto->mutable_stability(); | |
148 | |
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); | |
153 } | |
154 | |
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); | |
159 } | |
160 | |
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); | |
165 } | |
166 | |
167 count = local_state_->GetInteger(prefs::kStabilityRendererFailedLaunchCount); | |
168 if (count) { | |
169 stability_proto->set_renderer_failed_launch_count(count); | |
170 local_state_->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0); | |
171 } | |
172 | |
173 count = | |
174 local_state_->GetInteger(prefs::kStabilityExtensionRendererCrashCount); | |
175 if (count) { | |
176 stability_proto->set_extension_renderer_crash_count(count); | |
177 local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0); | |
178 } | |
179 | |
180 count = local_state_->GetInteger( | |
181 prefs::kStabilityExtensionRendererFailedLaunchCount); | |
182 if (count) { | |
183 stability_proto->set_extension_renderer_failed_launch_count(count); | |
184 local_state_->SetInteger( | |
185 prefs::kStabilityExtensionRendererFailedLaunchCount, 0); | |
186 } | |
187 | |
188 count = local_state_->GetInteger(prefs::kStabilityRendererHangCount); | |
189 if (count) { | |
190 stability_proto->set_renderer_hang_count(count); | |
191 local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0); | |
192 } | |
193 | 108 |
194 #if defined(OS_WIN) | 109 #if defined(OS_WIN) |
195 CountBrowserCrashDumpAttempts(); | 110 CountBrowserCrashDumpAttempts(); |
196 #endif // defined(OS_WIN) | 111 #endif // defined(OS_WIN) |
197 } | 112 } |
198 | 113 |
199 void ChromeStabilityMetricsProvider::ClearSavedStabilityMetrics() { | 114 void ChromeStabilityMetricsProvider::ClearSavedStabilityMetrics() { |
200 // Clear all the prefs used in this class in UMA reports (which doesn't | 115 helper_.ClearSavedStabilityMetrics(); |
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, | |
205 0); | |
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); | |
210 } | |
211 | |
212 // static | |
213 void ChromeStabilityMetricsProvider::RegisterPrefs( | |
214 PrefRegistrySimple* registry) { | |
215 registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0); | |
216 registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount, | |
217 0); | |
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); | |
224 | |
225 registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0); | |
226 } | 116 } |
227 | 117 |
228 void ChromeStabilityMetricsProvider::Observe( | 118 void ChromeStabilityMetricsProvider::Observe( |
229 int type, | 119 int type, |
230 const content::NotificationSource& source, | 120 const content::NotificationSource& source, |
231 const content::NotificationDetails& details) { | 121 const content::NotificationDetails& details) { |
232 switch (type) { | 122 switch (type) { |
233 case content::NOTIFICATION_LOAD_START: { | 123 case content::NOTIFICATION_LOAD_START: { |
234 content::NavigationController* controller = | 124 helper_.LogLoadStarted(); |
235 content::Source<content::NavigationController>(source).ptr(); | |
236 content::WebContents* web_contents = controller->GetWebContents(); | |
237 LogLoadStarted(web_contents); | |
238 break; | 125 break; |
239 } | 126 } |
240 | 127 |
241 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { | 128 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { |
242 content::RenderProcessHost::RendererClosedDetails* process_details = | 129 content::RenderProcessHost::RendererClosedDetails* process_details = |
243 content::Details<content::RenderProcessHost::RendererClosedDetails>( | 130 content::Details<content::RenderProcessHost::RendererClosedDetails>( |
244 details).ptr(); | 131 details).ptr(); |
| 132 bool was_extension_process = false; |
| 133 #if defined(ENABLE_EXTENSIONS) |
245 content::RenderProcessHost* host = | 134 content::RenderProcessHost* host = |
246 content::Source<content::RenderProcessHost>(source).ptr(); | 135 content::Source<content::RenderProcessHost>(source).ptr(); |
247 LogRendererCrash( | 136 if (extensions::ProcessMap::Get(host->GetBrowserContext()) |
248 host, process_details->status, process_details->exit_code); | 137 ->Contains(host->GetID())) { |
| 138 was_extension_process = true; |
| 139 } |
| 140 #endif |
| 141 helper_.LogRendererCrash(was_extension_process, process_details->status, |
| 142 process_details->exit_code); |
249 break; | 143 break; |
250 } | 144 } |
251 | 145 |
252 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: | 146 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: |
253 LogRendererHang(); | 147 helper_.LogRendererHang(); |
254 break; | 148 break; |
255 | 149 |
256 default: | 150 default: |
257 NOTREACHED(); | 151 NOTREACHED(); |
258 break; | 152 break; |
259 } | 153 } |
260 } | 154 } |
261 | 155 |
262 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed( | 156 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed( |
263 const content::ChildProcessData& data, | 157 const content::ChildProcessData& data, |
264 int exit_code) { | 158 int exit_code) { |
265 #if defined(ENABLE_PLUGINS) | 159 #if defined(ENABLE_PLUGINS) |
266 // Exclude plugin crashes from the count below because we report them via | 160 // Exclude plugin crashes from the count below because we report them via |
267 // a separate UMA metric. | 161 // a separate UMA metric. |
268 if (PluginMetricsProvider::IsPluginProcess(data.process_type)) | 162 if (PluginMetricsProvider::IsPluginProcess(data.process_type)) |
269 return; | 163 return; |
270 #endif | 164 #endif |
271 | 165 |
272 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount); | 166 helper_.BrowserChildProcessCrashed(); |
273 } | 167 } |
274 | |
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 :-(. | |
284 } | |
285 | |
286 void ChromeStabilityMetricsProvider::LogRendererCrash( | |
287 content::RenderProcessHost* host, | |
288 base::TerminationStatus status, | |
289 int exit_code) { | |
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; | |
297 } | |
298 #endif | |
299 if (status == base::TERMINATION_STATUS_PROCESS_CRASHED || | |
300 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { | |
301 if (was_extension_process) { | |
302 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount); | |
303 | |
304 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension", | |
305 MapCrashExitCodeForHistogram(exit_code)); | |
306 } else { | |
307 IncrementPrefValue(prefs::kStabilityRendererCrashCount); | |
308 | |
309 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer", | |
310 MapCrashExitCodeForHistogram(exit_code)); | |
311 } | |
312 | |
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, | |
322 3); | |
323 memory::RecordMemoryStats( | |
324 was_extension_process | |
325 ? memory::RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED | |
326 : memory::RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED); | |
327 #endif | |
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); | |
336 else | |
337 IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount); | |
338 } | |
339 } | |
340 | |
341 void ChromeStabilityMetricsProvider::IncrementPrefValue(const char* path) { | |
342 int value = local_state_->GetInteger(path); | |
343 local_state_->SetInteger(path, value + 1); | |
344 } | |
345 | |
346 void ChromeStabilityMetricsProvider::IncrementLongPrefsValue(const char* path) { | |
347 int64 value = local_state_->GetInt64(path); | |
348 local_state_->SetInt64(path, value + 1); | |
349 } | |
350 | |
351 void ChromeStabilityMetricsProvider::LogRendererHang() { | |
352 IncrementPrefValue(prefs::kStabilityRendererHangCount); | |
353 } | |
OLD | NEW |