// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/metrics/chrome_stability_metrics_provider.h" #include #include "base/logging.h" #include "base/metrics/histogram.h" #include "base/metrics/sparse_histogram.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/common/chrome_constants.h" #include "content/public/browser/child_process_data.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_process_host.h" #if defined(ENABLE_EXTENSIONS) #include "extensions/browser/process_map.h" #endif #if defined(ENABLE_PLUGINS) #include "chrome/browser/metrics/plugin_metrics_provider.h" #endif #if defined(OS_WIN) #include // Needed for STATUS_* codes #include "chrome/installer/util/install_util.h" #include "components/browser_watcher/crash_reporting_metrics_win.h" #endif namespace { #if defined(OS_WIN) void CountBrowserCrashDumpAttempts() { enum Outcome { OUTCOME_SUCCESS, OUTCOME_FAILURE, OUTCOME_UNKNOWN, OUTCOME_MAX_VALUE }; browser_watcher::CrashReportingMetrics::Values metrics = browser_watcher::CrashReportingMetrics( InstallUtil::IsChromeSxSProcess() ? chrome::kBrowserCrashDumpAttemptsRegistryPathSxS : chrome::kBrowserCrashDumpAttemptsRegistryPath) .RetrieveAndResetMetrics(); for (int i = 0; i < metrics.crash_dump_attempts; ++i) { Outcome outcome = OUTCOME_UNKNOWN; if (i < metrics.successful_crash_dumps) outcome = OUTCOME_SUCCESS; else if (i < metrics.successful_crash_dumps + metrics.failed_crash_dumps) outcome = OUTCOME_FAILURE; UMA_STABILITY_HISTOGRAM_ENUMERATION("CrashReport.BreakpadCrashDumpOutcome", outcome, OUTCOME_MAX_VALUE); } for (int i = 0; i < metrics.dump_without_crash_attempts; ++i) { Outcome outcome = OUTCOME_UNKNOWN; if (i < metrics.successful_dumps_without_crash) { outcome = OUTCOME_SUCCESS; } else if (i < metrics.successful_dumps_without_crash + metrics.failed_dumps_without_crash) { outcome = OUTCOME_FAILURE; } UMA_STABILITY_HISTOGRAM_ENUMERATION( "CrashReport.BreakpadDumpWithoutCrashOutcome", outcome, OUTCOME_MAX_VALUE); } } #endif // defined(OS_WIN) } // namespace ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider( PrefService* local_state) : helper_(local_state) { BrowserChildProcessObserver::Add(this); } ChromeStabilityMetricsProvider::~ChromeStabilityMetricsProvider() { BrowserChildProcessObserver::Remove(this); } void ChromeStabilityMetricsProvider::OnRecordingEnabled() { registrar_.Add(this, content::NOTIFICATION_LOAD_START, content::NotificationService::AllSources()); registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, content::NotificationService::AllSources()); registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, content::NotificationService::AllSources()); } void ChromeStabilityMetricsProvider::OnRecordingDisabled() { registrar_.RemoveAll(); } void ChromeStabilityMetricsProvider::ProvideStabilityMetrics( metrics::SystemProfileProto* system_profile_proto) { helper_.ProvideStabilityMetrics(system_profile_proto); #if defined(OS_WIN) CountBrowserCrashDumpAttempts(); #endif // defined(OS_WIN) } void ChromeStabilityMetricsProvider::ClearSavedStabilityMetrics() { helper_.ClearSavedStabilityMetrics(); } void ChromeStabilityMetricsProvider::Observe( int type, const content::NotificationSource& source, const content::NotificationDetails& details) { switch (type) { case content::NOTIFICATION_LOAD_START: { helper_.LogLoadStarted(); break; } case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { content::RenderProcessHost::RendererClosedDetails* process_details = content::Details( details).ptr(); bool was_extension_process = false; #if defined(ENABLE_EXTENSIONS) content::RenderProcessHost* host = content::Source(source).ptr(); if (extensions::ProcessMap::Get(host->GetBrowserContext()) ->Contains(host->GetID())) { was_extension_process = true; } #endif helper_.LogRendererCrash(was_extension_process, process_details->status, process_details->exit_code); break; } case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: helper_.LogRendererHang(); break; default: NOTREACHED(); break; } } void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed( const content::ChildProcessData& data, int exit_code) { #if defined(ENABLE_PLUGINS) // Exclude plugin crashes from the count below because we report them via // a separate UMA metric. if (PluginMetricsProvider::IsPluginProcess(data.process_type)) return; #endif helper_.BrowserChildProcessCrashed(); }