chromium/chromecast/browser/metrics/cast_stability_metrics_provider.cc

// Copyright 2014 The Chromium Authors
// 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/check.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "chromecast/base/pref_names.h"
#include "chromecast/metrics/cast_metrics_service_client.h"
#include "components/metrics/metrics_service.h"
#include "components/metrics/stability_metrics_helper.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/child_process_termination_info.h"
#include "content/public/browser/navigation_controller.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
};

// 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

CastStabilityMetricsProvider::CastStabilityMetricsProvider(
    ::metrics::MetricsService* metrics_service,
    PrefService* pref_service)
    : metrics_service_(metrics_service), pref_service_(pref_service) {
  DCHECK(pref_service_);
}

CastStabilityMetricsProvider::~CastStabilityMetricsProvider() {}

void CastStabilityMetricsProvider::OnRecordingEnabled() {
  logging_enabled_ = true;
}

void CastStabilityMetricsProvider::OnRecordingDisabled() {
  logging_enabled_ = false;
}

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_IN_MIGRATION() << "Unexpected crash type " << crash_type;

  // Wake up metrics logs sending if necessary now that new
  // log data is available.
  metrics_service_->OnApplicationNotIdle();
}

void CastStabilityMetricsProvider::OnRenderProcessHostCreated(
    content::RenderProcessHost* host) {
  if (!scoped_observations_.IsObservingSource(host))
    scoped_observations_.AddObservation(host);
}

void CastStabilityMetricsProvider::RenderProcessExited(
    content::RenderProcessHost* host,
    const content::ChildProcessTerminationInfo& info) {
  LogRendererCrash(host, info.status, info.exit_code);
}

void CastStabilityMetricsProvider::RenderProcessHostDestroyed(
    content::RenderProcessHost* host) {
  scoped_observations_.RemoveObservation(host);
}

void CastStabilityMetricsProvider::LogRendererCrash(
    content::RenderProcessHost* host,
    base::TerminationStatus status,
    int exit_code) {
  if (!logging_enabled_)
    return;

  if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
      status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
    ::metrics::StabilityMetricsHelper::RecordStabilityEvent(
        ::metrics::StabilityEventType::kRendererCrash);

    base::UmaHistogramSparse("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) {
    ::metrics::StabilityMetricsHelper::RecordStabilityEvent(
        ::metrics::StabilityEventType::kRendererFailedLaunch);
  }
}

void CastStabilityMetricsProvider::IncrementPrefValue(const char* path) {
  int value = pref_service_->GetInteger(path);
  pref_service_->SetInteger(path, value + 1);
}

}  // namespace metrics
}  // namespace chromecast