blob: 0222e88c93b242f2e4ed3f35e641579bc426ba01 [file] [log] [blame]
// Copyright 2015 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 "components/metrics/stability_metrics_helper.h"
#include <stdint.h>
#include <string>
#include "base/check.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/system/sys_info.h"
#include "build/build_config.h"
#include "build/buildflag.h"
#include "components/metrics/metrics_pref_names.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/variations/hashing.h"
#include "extensions/buildflags/buildflags.h"
#include "third_party/metrics_proto/system_profile.pb.h"
#if BUILDFLAG(IS_WIN)
#include <windows.h> // Needed for STATUS_* codes
#endif
#if BUILDFLAG(IS_CHROMEOS)
#include "components/metrics/system_memory_stats_recorder.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "base/android/application_status_listener.h"
#endif
namespace metrics {
namespace {
enum RendererType {
RENDERER_TYPE_RENDERER = 1,
RENDERER_TYPE_EXTENSION,
// 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
};
#if !BUILDFLAG(IS_ANDROID)
// 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) {
#if BUILDFLAG(IS_WIN)
// Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
// histograms.cc. Solve this by remapping it to a smaller value, which
// hopefully doesn't conflict with other codes.
if (static_cast<DWORD>(exit_code) == STATUS_GUARD_PAGE_VIOLATION)
return 0x1FCF7EC3; // Randomly picked number.
#endif
return std::abs(exit_code);
}
void RecordChildKills(RendererType histogram_type) {
base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildKills",
histogram_type, RENDERER_TYPE_COUNT);
}
#endif // !BUILDFLAG(IS_ANDROID)
} // namespace
StabilityMetricsHelper::StabilityMetricsHelper(PrefService* local_state)
: local_state_(local_state) {
DCHECK(local_state_);
}
StabilityMetricsHelper::~StabilityMetricsHelper() {}
void StabilityMetricsHelper::ProvideStabilityMetrics(
SystemProfileProto* system_profile_proto) {
SystemProfileProto_Stability* stability_proto =
system_profile_proto->mutable_stability();
int count = local_state_->GetInteger(prefs::kStabilityPageLoadCount);
if (count) {
stability_proto->set_page_load_count(count);
local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
}
count = local_state_->GetInteger(prefs::kStabilityGpuCrashCount);
if (count) {
stability_proto->set_gpu_crash_count(count);
local_state_->SetInteger(prefs::kStabilityGpuCrashCount, 0);
}
count = local_state_->GetInteger(prefs::kStabilityRendererCrashCount);
if (count) {
stability_proto->set_renderer_crash_count(count);
local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
}
#if BUILDFLAG(IS_ANDROID)
count = local_state_->GetInteger(prefs::kStabilityRendererLaunchCount);
if (count) {
stability_proto->set_renderer_launch_count(count);
local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
}
#endif // BUILDFLAG(IS_ANDROID)
count =
local_state_->GetInteger(prefs::kStabilityExtensionRendererCrashCount);
if (count) {
stability_proto->set_extension_renderer_crash_count(count);
local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
}
}
void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
// Clear all the prefs used in this class in UMA reports.
local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityGpuCrashCount, 0);
local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
#if BUILDFLAG(IS_ANDROID)
local_state_->SetInteger(prefs::kStabilityRendererLaunchCount, 0);
#endif // BUILDFLAG(IS_ANDROID)
}
// static
void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount,
0);
registry->RegisterIntegerPref(prefs::kStabilityGpuCrashCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
#if BUILDFLAG(IS_ANDROID)
registry->RegisterIntegerPref(prefs::kStabilityRendererLaunchCount, 0);
#endif // BUILDFLAG(IS_ANDROID)
}
void StabilityMetricsHelper::IncreaseRendererCrashCount() {
IncrementPrefValue(prefs::kStabilityRendererCrashCount);
RecordStabilityEvent(StabilityEventType::kRendererCrash);
}
void StabilityMetricsHelper::IncreaseGpuCrashCount() {
IncrementPrefValue(prefs::kStabilityGpuCrashCount);
RecordStabilityEvent(StabilityEventType::kGpuCrash);
}
void StabilityMetricsHelper::BrowserUtilityProcessLaunched(
const std::string& metrics_name) {
uint32_t hash = variations::HashName(metrics_name);
base::UmaHistogramSparse("ChildProcess.Launched.UtilityProcessHash", hash);
RecordStabilityEvent(StabilityEventType::kUtilityLaunch);
}
void StabilityMetricsHelper::BrowserUtilityProcessCrashed(
const std::string& metrics_name,
int exit_code) {
uint32_t hash = variations::HashName(metrics_name);
base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessHash", hash);
base::UmaHistogramSparse("ChildProcess.Crashed.UtilityProcessExitCode",
exit_code);
RecordStabilityEvent(StabilityEventType::kUtilityCrash);
}
void StabilityMetricsHelper::BrowserUtilityProcessLaunchFailed(
const std::string& metrics_name,
int launch_error_code
#if BUILDFLAG(IS_WIN)
,
DWORD last_error
#endif
) {
uint32_t hash = variations::HashName(metrics_name);
base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessHash",
hash);
base::UmaHistogramSparse("ChildProcess.LaunchFailed.UtilityProcessErrorCode",
launch_error_code);
#if BUILDFLAG(IS_WIN)
base::UmaHistogramSparse("ChildProcess.LaunchFailed.WinLastError",
last_error);
#endif
// TODO(wfh): Decide if this utility process launch failure should also
// trigger a Stability Event.
}
void StabilityMetricsHelper::LogLoadStarted() {
IncrementPrefValue(prefs::kStabilityPageLoadCount);
RecordStabilityEvent(StabilityEventType::kPageLoad);
}
#if !BUILDFLAG(IS_ANDROID)
void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
base::TerminationStatus status,
int exit_code) {
RendererType histogram_type =
was_extension_process ? RENDERER_TYPE_EXTENSION : RENDERER_TYPE_RENDERER;
switch (status) {
case base::TERMINATION_STATUS_NORMAL_TERMINATION:
break;
case base::TERMINATION_STATUS_PROCESS_CRASHED:
case base::TERMINATION_STATUS_ABNORMAL_TERMINATION:
case base::TERMINATION_STATUS_OOM:
if (was_extension_process) {
#if !BUILDFLAG(ENABLE_EXTENSIONS)
NOTREACHED();
#endif
IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
RecordStabilityEvent(StabilityEventType::kExtensionCrash);
base::UmaHistogramSparse("CrashExitCodes.Extension",
MapCrashExitCodeForHistogram(exit_code));
} else {
IncreaseRendererCrashCount();
base::UmaHistogramSparse("CrashExitCodes.Renderer",
MapCrashExitCodeForHistogram(exit_code));
}
base::UmaHistogramEnumeration("BrowserRenderProcessHost.ChildCrashes",
histogram_type, RENDERER_TYPE_COUNT);
break;
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED:
RecordChildKills(histogram_type);
break;
#if BUILDFLAG(IS_CHROMEOS)
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
RecordChildKills(histogram_type);
base::UmaHistogramExactLinear("BrowserRenderProcessHost.ChildKills.OOM",
was_extension_process ? 2 : 1, 3);
RecordMemoryStats(was_extension_process
? RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
: RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
break;
#endif
case base::TERMINATION_STATUS_STILL_RUNNING:
base::UmaHistogramEnumeration(
"BrowserRenderProcessHost.DisconnectedAlive", histogram_type,
RENDERER_TYPE_COUNT);
break;
case base::TERMINATION_STATUS_LAUNCH_FAILED:
// TODO(rkaplow): See if we can remove this histogram as we have
// Stability.Counts2 which has the same metrics.
base::UmaHistogramEnumeration(
"BrowserRenderProcessHost.ChildLaunchFailures", histogram_type,
RENDERER_TYPE_COUNT);
base::UmaHistogramSparse(
"BrowserRenderProcessHost.ChildLaunchFailureCodes", exit_code);
LogRendererLaunchFailed(was_extension_process);
break;
#if BUILDFLAG(IS_WIN)
case base::TERMINATION_STATUS_INTEGRITY_FAILURE:
base::UmaHistogramEnumeration(
"BrowserRenderProcessHost.ChildCodeIntegrityFailures", histogram_type,
RENDERER_TYPE_COUNT);
break;
#endif
case base::TERMINATION_STATUS_MAX_ENUM:
NOTREACHED();
break;
}
}
#endif // !BUILDFLAG(IS_ANDROID)
void StabilityMetricsHelper::LogRendererLaunched(bool was_extension_process) {
auto metric = was_extension_process
? StabilityEventType::kExtensionRendererLaunch
: StabilityEventType::kRendererLaunch;
RecordStabilityEvent(metric);
#if BUILDFLAG(IS_ANDROID)
if (!was_extension_process)
IncrementPrefValue(prefs::kStabilityRendererLaunchCount);
#endif // BUILDFLAG(IS_ANDROID)
}
void StabilityMetricsHelper::LogRendererLaunchFailed(
bool was_extension_process) {
auto metric = was_extension_process
? StabilityEventType::kExtensionRendererFailedLaunch
: StabilityEventType::kRendererFailedLaunch;
RecordStabilityEvent(metric);
}
void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
int value = local_state_->GetInteger(path);
local_state_->SetInteger(path, value + 1);
}
void StabilityMetricsHelper::LogRendererHang() {
#if BUILDFLAG(IS_ANDROID)
base::android::ApplicationState app_state =
base::android::ApplicationStatusListener::GetState();
bool is_foreground =
app_state == base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES ||
app_state == base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES;
base::UmaHistogramBoolean("ChildProcess.HungRendererInForeground",
is_foreground);
#endif
base::UmaHistogramMemoryMB(
"ChildProcess.HungRendererAvailableMemoryMB",
base::SysInfo::AmountOfAvailablePhysicalMemory() / 1024 / 1024);
}
// static
void StabilityMetricsHelper::RecordStabilityEvent(
StabilityEventType stability_event_type) {
UMA_STABILITY_HISTOGRAM_ENUMERATION("Stability.Counts2",
stability_event_type);
}
} // namespace metrics