Chromium Code Reviews| 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())) |
|
Alexei Svitkine (slow)
2015/09/24 15:42:38
Nit: {}'s
blundell
2015/09/24 16:15:31
Done.
| |
| 138 was_extension_process = true; | |
| 139 #endif | |
| 140 helper_.LogRendererCrash(was_extension_process, process_details->status, | |
| 141 process_details->exit_code); | |
| 249 break; | 142 break; |
| 250 } | 143 } |
| 251 | 144 |
| 252 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: | 145 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: |
| 253 LogRendererHang(); | 146 helper_.LogRendererHang(); |
| 254 break; | 147 break; |
| 255 | 148 |
| 256 default: | 149 default: |
| 257 NOTREACHED(); | 150 NOTREACHED(); |
| 258 break; | 151 break; |
| 259 } | 152 } |
| 260 } | 153 } |
| 261 | 154 |
| 262 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed( | 155 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed( |
| 263 const content::ChildProcessData& data, | 156 const content::ChildProcessData& data, |
| 264 int exit_code) { | 157 int exit_code) { |
| 265 #if defined(ENABLE_PLUGINS) | 158 #if defined(ENABLE_PLUGINS) |
| 266 // Exclude plugin crashes from the count below because we report them via | 159 // Exclude plugin crashes from the count below because we report them via |
| 267 // a separate UMA metric. | 160 // a separate UMA metric. |
| 268 if (PluginMetricsProvider::IsPluginProcess(data.process_type)) | 161 if (PluginMetricsProvider::IsPluginProcess(data.process_type)) |
| 269 return; | 162 return; |
| 270 #endif | 163 #endif |
| 271 | 164 |
| 272 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount); | 165 helper_.BrowserChildProcessCrashed(); |
| 273 } | 166 } |
| 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 |