| // Copyright 2017 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_provider.h" |
| |
| #include "base/metrics/histogram_macros.h" |
| #include "build/build_config.h" |
| #include "components/metrics/metrics_pref_names.h" |
| #include "components/prefs/pref_registry_simple.h" |
| #include "components/prefs/pref_service.h" |
| #include "third_party/metrics_proto/system_profile.pb.h" |
| |
| #if defined(OS_ANDROID) |
| #include "base/android/build_info.h" |
| #endif |
| |
| namespace metrics { |
| |
| namespace { |
| |
| #if defined(OS_ANDROID) |
| bool UpdateGmsCoreVersionPref(PrefService* local_state) { |
| std::string previous_version = |
| local_state->GetString(prefs::kStabilityGmsCoreVersion); |
| std::string current_version = |
| base::android::BuildInfo::GetInstance()->gms_version_code(); |
| |
| // If the last version is empty, treat it as consistent. |
| if (previous_version.empty()) { |
| local_state->SetString(prefs::kStabilityGmsCoreVersion, current_version); |
| return true; |
| } |
| |
| if (previous_version == current_version) |
| return true; |
| |
| local_state->SetString(prefs::kStabilityGmsCoreVersion, current_version); |
| return false; |
| } |
| #endif |
| |
| } // namespace |
| |
| StabilityMetricsProvider::StabilityMetricsProvider(PrefService* local_state) |
| : local_state_(local_state) {} |
| |
| StabilityMetricsProvider::~StabilityMetricsProvider() = default; |
| |
| // static |
| void StabilityMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) { |
| registry->RegisterIntegerPref(prefs::kStabilityCrashCount, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityIncompleteSessionEndCount, 0); |
| registry->RegisterBooleanPref(prefs::kStabilitySessionEndCompleted, true); |
| registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationFail, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityBreakpadRegistrationSuccess, |
| 0); |
| registry->RegisterIntegerPref(prefs::kStabilityDebuggerPresent, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityDebuggerNotPresent, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityDeferredCount, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityDiscardCount, 0); |
| registry->RegisterIntegerPref(prefs::kStabilityVersionMismatchCount, 0); |
| #if defined(OS_ANDROID) |
| registry->RegisterStringPref(prefs::kStabilityGmsCoreVersion, ""); |
| registry->RegisterIntegerPref(prefs::kStabilityCrashCountWithoutGmsCoreUpdate, |
| 0); |
| #endif |
| } |
| |
| void StabilityMetricsProvider::ClearSavedStabilityMetrics() { |
| local_state_->SetInteger(prefs::kStabilityCrashCount, 0); |
| local_state_->SetInteger(prefs::kStabilityIncompleteSessionEndCount, 0); |
| local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationSuccess, 0); |
| local_state_->SetInteger(prefs::kStabilityBreakpadRegistrationFail, 0); |
| local_state_->SetInteger(prefs::kStabilityDebuggerPresent, 0); |
| local_state_->SetInteger(prefs::kStabilityDebuggerNotPresent, 0); |
| local_state_->SetInteger(prefs::kStabilityLaunchCount, 0); |
| local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, true); |
| local_state_->SetInteger(prefs::kStabilityDeferredCount, 0); |
| // Note: kStabilityDiscardCount is not cleared as its intent is to measure |
| // the number of times data is discarded, even across versions. |
| local_state_->SetInteger(prefs::kStabilityVersionMismatchCount, 0); |
| } |
| |
| void StabilityMetricsProvider::ProvideStabilityMetrics( |
| SystemProfileProto* system_profile) { |
| SystemProfileProto::Stability* stability = |
| system_profile->mutable_stability(); |
| |
| int pref_value = 0; |
| |
| if (GetPrefValue(prefs::kStabilityLaunchCount, &pref_value)) |
| stability->set_launch_count(pref_value); |
| |
| if (GetPrefValue(prefs::kStabilityCrashCount, &pref_value)) |
| stability->set_crash_count(pref_value); |
| |
| #if defined(OS_ANDROID) |
| if (GetPrefValue(prefs::kStabilityCrashCountWithoutGmsCoreUpdate, |
| &pref_value)) { |
| stability->set_crash_count_without_gms_core_update(pref_value); |
| } |
| #endif |
| |
| if (GetPrefValue(prefs::kStabilityIncompleteSessionEndCount, &pref_value)) |
| stability->set_incomplete_shutdown_count(pref_value); |
| |
| if (GetPrefValue(prefs::kStabilityBreakpadRegistrationSuccess, &pref_value)) |
| stability->set_breakpad_registration_success_count(pref_value); |
| |
| if (GetPrefValue(prefs::kStabilityBreakpadRegistrationFail, &pref_value)) |
| stability->set_breakpad_registration_failure_count(pref_value); |
| |
| if (GetPrefValue(prefs::kStabilityDebuggerPresent, &pref_value)) |
| stability->set_debugger_present_count(pref_value); |
| |
| if (GetPrefValue(prefs::kStabilityDebuggerNotPresent, &pref_value)) |
| stability->set_debugger_not_present_count(pref_value); |
| |
| // Note: only logging the following histograms for non-zero values. |
| if (GetPrefValue(prefs::kStabilityDeferredCount, &pref_value)) { |
| UMA_STABILITY_HISTOGRAM_COUNTS_100( |
| "Stability.Internals.InitialStabilityLogDeferredCount", pref_value); |
| } |
| |
| // Note: only logging the following histograms for non-zero values. |
| if (GetPrefValue(prefs::kStabilityDiscardCount, &pref_value)) { |
| UMA_STABILITY_HISTOGRAM_COUNTS_100("Stability.Internals.DataDiscardCount", |
| pref_value); |
| } |
| |
| // Note: only logging the following histograms for non-zero values. |
| if (GetPrefValue(prefs::kStabilityVersionMismatchCount, &pref_value)) { |
| UMA_STABILITY_HISTOGRAM_COUNTS_100( |
| "Stability.Internals.VersionMismatchCount", pref_value); |
| } |
| } |
| |
| void StabilityMetricsProvider::RecordBreakpadRegistration(bool success) { |
| if (!success) |
| IncrementPrefValue(prefs::kStabilityBreakpadRegistrationFail); |
| else |
| IncrementPrefValue(prefs::kStabilityBreakpadRegistrationSuccess); |
| } |
| |
| void StabilityMetricsProvider::RecordBreakpadHasDebugger(bool has_debugger) { |
| if (!has_debugger) |
| IncrementPrefValue(prefs::kStabilityDebuggerNotPresent); |
| else |
| IncrementPrefValue(prefs::kStabilityDebuggerPresent); |
| } |
| |
| void StabilityMetricsProvider::CheckLastSessionEndCompleted() { |
| if (!local_state_->GetBoolean(prefs::kStabilitySessionEndCompleted)) { |
| IncrementPrefValue(prefs::kStabilityIncompleteSessionEndCount); |
| // This is marked false when we get a WM_ENDSESSION. |
| MarkSessionEndCompleted(true); |
| } |
| } |
| |
| void StabilityMetricsProvider::MarkSessionEndCompleted(bool end_completed) { |
| local_state_->SetBoolean(prefs::kStabilitySessionEndCompleted, end_completed); |
| } |
| |
| void StabilityMetricsProvider::LogCrash() { |
| IncrementPrefValue(prefs::kStabilityCrashCount); |
| |
| #if defined(OS_ANDROID) |
| // On Android, if there is an update for GMS core when Chrome is running, |
| // Chrome will be killed and restart. This is expected and we should only |
| // report crash if the GMS core version has not been changed. |
| if (UpdateGmsCoreVersionPref(local_state_)) |
| IncrementPrefValue(prefs::kStabilityCrashCountWithoutGmsCoreUpdate); |
| #endif |
| } |
| |
| void StabilityMetricsProvider::LogStabilityLogDeferred() { |
| IncrementPrefValue(prefs::kStabilityDeferredCount); |
| } |
| |
| void StabilityMetricsProvider::LogStabilityDataDiscarded() { |
| IncrementPrefValue(prefs::kStabilityDiscardCount); |
| } |
| |
| void StabilityMetricsProvider::LogLaunch() { |
| IncrementPrefValue(prefs::kStabilityLaunchCount); |
| } |
| |
| void StabilityMetricsProvider::LogStabilityVersionMismatch() { |
| IncrementPrefValue(prefs::kStabilityVersionMismatchCount); |
| } |
| |
| void StabilityMetricsProvider::IncrementPrefValue(const char* path) { |
| int value = local_state_->GetInteger(path); |
| local_state_->SetInteger(path, value + 1); |
| } |
| |
| int StabilityMetricsProvider::GetPrefValue(const char* path, int* value) { |
| *value = local_state_->GetInteger(path); |
| if (*value != 0) |
| local_state_->SetInteger(path, 0); |
| return *value; |
| } |
| |
| } // namespace metrics |