// Copyright 2017 The Chromium Authors // 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 #include "base/logging.h" #include "base/metrics/histogram_macros.h" #include "build/build_config.h" #include "components/metrics/metrics_pref_names.h" #include "components/metrics/stability_metrics_helper.h" #include "components/prefs/pref_registry_simple.h" #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "third_party/metrics_proto/system_profile.pb.h" #if BUILDFLAG(IS_ANDROID) #include "base/android/build_info.h" #endif #if BUILDFLAG(IS_WIN) #include "components/metrics/system_session_analyzer/system_session_analyzer_win.h" #endif namespace metrics { namespace { #if BUILDFLAG(IS_ANDROID) bool HasGmsCoreVersionChanged(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()) return false; return previous_version != current_version; } void UpdateGmsCoreVersionPref(PrefService* local_state) { std::string current_version = base::android::BuildInfo::GetInstance()->gms_version_code(); local_state->SetString(prefs::kStabilityGmsCoreVersion, current_version); } #endif } // namespace StabilityMetricsProvider::StabilityMetricsProvider(PrefService* local_state) : local_state_(local_state) {} StabilityMetricsProvider::~StabilityMetricsProvider() = default; // static void StabilityMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) { registry->RegisterIntegerPref(prefs::kStabilityFileMetricsUnsentFilesCount, 0); registry->RegisterIntegerPref(prefs::kStabilityFileMetricsUnsentSamplesCount, 0); #if BUILDFLAG(IS_ANDROID) registry->RegisterIntegerPref(prefs::kStabilityLaunchCount, 0); registry->RegisterStringPref(prefs::kStabilityGmsCoreVersion, ""); registry->RegisterIntegerPref(prefs::kStabilityCrashCountDueToGmsCoreUpdate, 0); #endif #if BUILDFLAG(IS_WIN) registry->RegisterIntegerPref(prefs::kStabilitySystemCrashCount, 0); #endif } void StabilityMetricsProvider::Init() { #if BUILDFLAG(IS_ANDROID) // This method has to be called after HasGmsCoreVersionChanged() to avoid // overwriting thie result. UpdateGmsCoreVersionPref(local_state_); #endif } void StabilityMetricsProvider::ClearSavedStabilityMetrics() { // The 0 is a valid value for the below prefs, clears pref instead // of setting to default value. local_state_->ClearPref(prefs::kStabilityFileMetricsUnsentFilesCount); local_state_->ClearPref(prefs::kStabilityFileMetricsUnsentSamplesCount); #if BUILDFLAG(IS_ANDROID) local_state_->SetInteger(prefs::kStabilityLaunchCount, 0); #endif #if BUILDFLAG(IS_WIN) local_state_->SetInteger(prefs::kStabilitySystemCrashCount, 0); #endif } void StabilityMetricsProvider::ProvideStabilityMetrics( SystemProfileProto* system_profile) { #if BUILDFLAG(IS_ANDROID) SystemProfileProto::Stability* stability = system_profile->mutable_stability(); int pref_value = 0; if (GetAndClearPrefValue(prefs::kStabilityLaunchCount, &pref_value)) stability->set_launch_count(pref_value); if (GetAndClearPrefValue(prefs::kStabilityCrashCountDueToGmsCoreUpdate, &pref_value)) { stability->set_crash_count_due_to_gms_core_update(pref_value); } #endif if (local_state_->HasPrefPath(prefs::kStabilityFileMetricsUnsentFilesCount)) { UMA_STABILITY_HISTOGRAM_COUNTS_100( "Stability.Internals.FileMetricsProvider.BrowserMetrics." "UnsentFilesCount", local_state_->GetInteger(prefs::kStabilityFileMetricsUnsentFilesCount)); local_state_->ClearPref(prefs::kStabilityFileMetricsUnsentFilesCount); } if (local_state_->HasPrefPath( prefs::kStabilityFileMetricsUnsentSamplesCount)) { UMA_STABILITY_HISTOGRAM_CUSTOM_COUNTS( "Stability.Internals.FileMetricsProvider.BrowserMetrics." "UnsentSamplesCount", local_state_->GetInteger( prefs::kStabilityFileMetricsUnsentSamplesCount), 0, 1000000, 50); local_state_->ClearPref(prefs::kStabilityFileMetricsUnsentSamplesCount); } #if BUILDFLAG(IS_WIN) int pref_value = 0; if (GetAndClearPrefValue(prefs::kStabilitySystemCrashCount, &pref_value)) { UMA_STABILITY_HISTOGRAM_COUNTS_100("Stability.Internals.SystemCrashCount", pref_value); } #endif } void StabilityMetricsProvider::LogCrash(base::Time last_live_timestamp) { #if BUILDFLAG(IS_ANDROID) // On Android, if there is an update for GMS Core when Chrome is running, // Chrome will be killed, counting as a crash. This is expected and should not // be counted in stability crash counts. Thus these crashes are added to a // specific bucket for crashes caused by GMS Core updates. if (HasGmsCoreVersionChanged(local_state_)) { IncrementPrefValue(prefs::kStabilityCrashCountDueToGmsCoreUpdate); return; } #endif StabilityMetricsHelper::RecordStabilityEvent( StabilityEventType::kBrowserCrash); #if BUILDFLAG(IS_WIN) MaybeLogSystemCrash(last_live_timestamp); #endif } void StabilityMetricsProvider::LogLaunch() { #if BUILDFLAG(IS_ANDROID) IncrementPrefValue(prefs::kStabilityLaunchCount); #endif StabilityMetricsHelper::RecordStabilityEvent(StabilityEventType::kLaunch); } #if BUILDFLAG(IS_WIN) bool StabilityMetricsProvider::IsUncleanSystemSession( base::Time last_live_timestamp) { DCHECK_NE(base::Time(), last_live_timestamp); // There's a non-null last live timestamp, see if this occurred in // a Windows system session that ended uncleanly. The expectation is that // |last_live_timestamp| will have occurred in the immediately previous system // session, but if the system has been restarted many times since Chrome last // ran, that's not necessarily true. Log traversal can be expensive, so we // limit the analyzer to reaching back three previous system sessions to bound // the cost of the traversal. SystemSessionAnalyzer analyzer(3); SystemSessionAnalyzer::Status status = analyzer.IsSessionUnclean(last_live_timestamp); return status == SystemSessionAnalyzer::UNCLEAN; } void StabilityMetricsProvider::MaybeLogSystemCrash( base::Time last_live_timestamp) { if (last_live_timestamp != base::Time() && IsUncleanSystemSession(last_live_timestamp)) { IncrementPrefValue(prefs::kStabilitySystemCrashCount); } } #endif void StabilityMetricsProvider::IncrementPrefValue(const char* path) { int value = local_state_->GetInteger(path); local_state_->SetInteger(path, value + 1); } int StabilityMetricsProvider::GetAndClearPrefValue(const char* path, int* value) { *value = local_state_->GetInteger(path); if (*value != 0) local_state_->SetInteger(path, 0); return *value; } } // namespace metrics