| // 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 "chromecast/browser/metrics/cast_stability_metrics_provider.h" |
| |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "base/metrics/histogram.h" |
| #include "base/metrics/sparse_histogram.h" |
| #include "chromecast/base/pref_names.h" |
| #include "chromecast/browser/cast_browser_process.h" |
| #include "chromecast/browser/metrics/cast_metrics_service_client.h" |
| #include "components/metrics/metrics_service.h" |
| #include "components/metrics/proto/system_profile.pb.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/pref_service.h" |
| #include "content/public/browser/child_process_data.h" |
| #include "content/public/browser/navigation_controller.h" |
| #include "content/public/browser/notification_service.h" |
| #include "content/public/browser/notification_types.h" |
| #include "content/public/browser/render_process_host.h" |
| |
| namespace chromecast { |
| namespace metrics { |
| |
| namespace { |
| |
| enum RendererType { |
| RENDERER_TYPE_RENDERER = 1, |
| RENDERER_TYPE_EXTENSION, // Not used, but needed for correct histogram count. |
| // NOTE: Add new action types only immediately above this line. Also, |
| // make sure the enum list in tools/metrics/histograms/histograms.xml is |
| // updated with any change in here. |
| RENDERER_TYPE_COUNT |
| }; |
| |
| void IncrementPrefValue(const char* path) { |
| PrefService* pref = shell::CastBrowserProcess::GetInstance()->pref_service(); |
| DCHECK(pref); |
| int value = pref->GetInteger(path); |
| pref->SetInteger(path, value + 1); |
| } |
| |
| // Converts an exit code into something that can be inserted into our |
| // histograms (which expect non-negative numbers less than MAX_INT). |
| int MapCrashExitCodeForHistogram(int exit_code) { |
| return std::abs(exit_code); |
| } |
| |
| } // namespace |
| |
| // static |
| void CastStabilityMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) { |
| registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityRendererFailedLaunchCount, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0); |
| } |
| |
| CastStabilityMetricsProvider::CastStabilityMetricsProvider( |
| ::metrics::MetricsService* metrics_service) |
| : metrics_service_(metrics_service) { |
| BrowserChildProcessObserver::Add(this); |
| } |
| |
| CastStabilityMetricsProvider::~CastStabilityMetricsProvider() { |
| BrowserChildProcessObserver::Remove(this); |
| } |
| |
| void CastStabilityMetricsProvider::OnRecordingEnabled() { |
| registrar_.Add(this, |
| content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| content::NotificationService::AllSources()); |
| registrar_.Add(this, |
| content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, |
| content::NotificationService::AllSources()); |
| } |
| |
| void CastStabilityMetricsProvider::OnRecordingDisabled() { |
| registrar_.RemoveAll(); |
| } |
| |
| void CastStabilityMetricsProvider::ProvideStabilityMetrics( |
| ::metrics::SystemProfileProto* system_profile_proto) { |
| PrefService* pref = shell::CastBrowserProcess::GetInstance()->pref_service(); |
| ::metrics::SystemProfileProto_Stability* stability_proto = |
| system_profile_proto->mutable_stability(); |
| |
| int count = pref->GetInteger(prefs::kStabilityChildProcessCrashCount); |
| if (count) { |
| stability_proto->set_child_process_crash_count(count); |
| pref->SetInteger(prefs::kStabilityChildProcessCrashCount, 0); |
| } |
| |
| count = pref->GetInteger(prefs::kStabilityRendererCrashCount); |
| if (count) { |
| stability_proto->set_renderer_crash_count(count); |
| pref->SetInteger(prefs::kStabilityRendererCrashCount, 0); |
| } |
| |
| count = pref->GetInteger(prefs::kStabilityRendererFailedLaunchCount); |
| if (count) { |
| stability_proto->set_renderer_failed_launch_count(count); |
| pref->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0); |
| } |
| |
| count = pref->GetInteger(prefs::kStabilityRendererHangCount); |
| if (count) { |
| stability_proto->set_renderer_hang_count(count); |
| pref->SetInteger(prefs::kStabilityRendererHangCount, 0); |
| } |
| } |
| |
| void CastStabilityMetricsProvider::LogExternalCrash( |
| const std::string& crash_type) { |
| if (crash_type == "user") |
| IncrementPrefValue(prefs::kStabilityOtherUserCrashCount); |
| else if (crash_type == "kernel") |
| IncrementPrefValue(prefs::kStabilityKernelCrashCount); |
| else if (crash_type == "uncleanshutdown") |
| IncrementPrefValue(prefs::kStabilitySystemUncleanShutdownCount); |
| else |
| NOTREACHED() << "Unexpected crash type " << crash_type; |
| |
| // Wake up metrics logs sending if necessary now that new |
| // log data is available. |
| metrics_service_->OnApplicationNotIdle(); |
| } |
| |
| void CastStabilityMetricsProvider::Observe( |
| int type, |
| const content::NotificationSource& source, |
| const content::NotificationDetails& details) { |
| switch (type) { |
| case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { |
| content::RenderProcessHost::RendererClosedDetails* process_details = |
| content::Details<content::RenderProcessHost::RendererClosedDetails>( |
| details).ptr(); |
| content::RenderProcessHost* host = |
| content::Source<content::RenderProcessHost>(source).ptr(); |
| LogRendererCrash( |
| host, process_details->status, process_details->exit_code); |
| break; |
| } |
| |
| case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: |
| LogRendererHang(); |
| break; |
| |
| default: |
| NOTREACHED(); |
| break; |
| } |
| } |
| |
| void CastStabilityMetricsProvider::BrowserChildProcessCrashed( |
| const content::ChildProcessData& data, |
| int exit_code) { |
| IncrementPrefValue(prefs::kStabilityChildProcessCrashCount); |
| } |
| |
| void CastStabilityMetricsProvider::LogRendererCrash( |
| content::RenderProcessHost* host, |
| base::TerminationStatus status, |
| int exit_code) { |
| if (status == base::TERMINATION_STATUS_PROCESS_CRASHED || |
| status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { |
| IncrementPrefValue(prefs::kStabilityRendererCrashCount); |
| |
| UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer", |
| MapCrashExitCodeForHistogram(exit_code)); |
| UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes", |
| RENDERER_TYPE_RENDERER, RENDERER_TYPE_COUNT); |
| } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { |
| UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills", |
| RENDERER_TYPE_RENDERER, RENDERER_TYPE_COUNT); |
| } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) { |
| UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive", |
| RENDERER_TYPE_RENDERER, RENDERER_TYPE_COUNT); |
| } else if (status == base::TERMINATION_STATUS_LAUNCH_FAILED) { |
| IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount); |
| } |
| } |
| |
| void CastStabilityMetricsProvider::LogRendererHang() { |
| IncrementPrefValue(prefs::kStabilityRendererHangCount); |
| } |
| |
| } // namespace metrics |
| } // namespace chromecast |