|  | // 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 "chrome/browser/metrics/android_metrics_provider.h" | 
|  |  | 
|  | #include "base/metrics/histogram.h" | 
|  | #include "base/prefs/pref_registry_simple.h" | 
|  | #include "base/prefs/pref_service.h" | 
|  | #include "base/prefs/scoped_user_pref_update.h" | 
|  | #include "base/sys_info.h" | 
|  | #include "base/values.h" | 
|  | #include "chrome/browser/android/feature_utilities.h" | 
|  | #include "chrome/common/pref_names.h" | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | // Increments a particular entry in the ListValue. | 
|  | void IncrementListValue(base::ListValue* counts, int index) { | 
|  | int current_count = 0; | 
|  | counts->GetInteger(index, ¤t_count); | 
|  | counts->Set(index, new base::FundamentalValue(current_count + 1)); | 
|  | } | 
|  |  | 
|  | // Takes an int corresponding to a Type and returns the corresponding flag. | 
|  | int GetActivityFlag(int type_id) { | 
|  | ActivityTypeIds::Type type = ActivityTypeIds::GetActivityType(type_id); | 
|  | DCHECK_LT(type, ActivityTypeIds::ACTIVITY_MAX_VALUE); | 
|  | return (1 << type); | 
|  | } | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | AndroidMetricsProvider::AndroidMetricsProvider(PrefService* local_state) | 
|  | : local_state_(local_state) { | 
|  | LogStabilityToPrefs(); | 
|  | } | 
|  |  | 
|  | AndroidMetricsProvider::~AndroidMetricsProvider() { | 
|  | } | 
|  |  | 
|  | void AndroidMetricsProvider::ProvideStabilityMetrics( | 
|  | metrics::SystemProfileProto* system_profile_proto) { | 
|  | ConvertStabilityPrefsToHistograms(); | 
|  | } | 
|  |  | 
|  | void AndroidMetricsProvider::ProvideGeneralMetrics( | 
|  | metrics::ChromeUserMetricsExtension* uma_proto) { | 
|  | UMA_HISTOGRAM_ENUMERATION( | 
|  | "DocumentActivity.Enabled", | 
|  | chrome::android::GetDocumentModeValue(), | 
|  | chrome::android::RUNNING_MODE_MAX); | 
|  | UMA_HISTOGRAM_ENUMERATION( | 
|  | "CustomTabs.Visible", | 
|  | chrome::android::GetCustomTabsVisibleValue(), | 
|  | chrome::android::CUSTOM_TABS_VISIBILITY_MAX); | 
|  | UMA_HISTOGRAM_BOOLEAN( | 
|  | "MemoryAndroid.LowRamDevice", | 
|  | base::SysInfo::IsLowEndDevice()); | 
|  | } | 
|  |  | 
|  | void AndroidMetricsProvider::OnForegroundActivityChanged( | 
|  | ActivityTypeIds::Type type) { | 
|  | DCHECK_LT(type, ActivityTypeIds::ACTIVITY_MAX_VALUE); | 
|  |  | 
|  | if (type == local_state_->GetInteger(prefs::kStabilityForegroundActivityType)) | 
|  | return; | 
|  |  | 
|  | // Record that the Activity is now in the foreground. | 
|  | local_state_->SetInteger(prefs::kStabilityForegroundActivityType, type); | 
|  |  | 
|  | // Record that the Activity was launched this sesaion. | 
|  | // The pref stores a set of flags ORed together, where each set flag | 
|  | // corresponds to a launched Activity type. | 
|  | int launched = | 
|  | local_state_->GetInteger(prefs::kStabilityLaunchedActivityFlags); | 
|  | if (type != ActivityTypeIds::ACTIVITY_NONE) { | 
|  | launched |= GetActivityFlag(type); | 
|  | local_state_->SetInteger(prefs::kStabilityLaunchedActivityFlags, launched); | 
|  | } | 
|  |  | 
|  | local_state_->CommitPendingWrite(); | 
|  | } | 
|  |  | 
|  | // static | 
|  | void AndroidMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) { | 
|  | registry->RegisterIntegerPref(prefs::kStabilityForegroundActivityType, | 
|  | ActivityTypeIds::ACTIVITY_NONE); | 
|  | registry->RegisterIntegerPref(prefs::kStabilityLaunchedActivityFlags, 0); | 
|  | registry->RegisterListPref(prefs::kStabilityLaunchedActivityCounts); | 
|  | registry->RegisterListPref(prefs::kStabilityCrashedActivityCounts); | 
|  | } | 
|  |  | 
|  | void AndroidMetricsProvider::LogStabilityToPrefs() { | 
|  | // Track which Activities were launched by the user. | 
|  | // A 'launch' is defined as starting the Activity at least once during a | 
|  | // UMA session.  Multiple launches are counted only once since it is possible | 
|  | // for users to hop between Activities (e.g. entering and leaving Settings). | 
|  | const int launched = | 
|  | local_state_->GetInteger(prefs::kStabilityLaunchedActivityFlags); | 
|  | ListPrefUpdate update_launches(local_state_, | 
|  | prefs::kStabilityLaunchedActivityCounts); | 
|  | base::ListValue* launch_counts = update_launches.Get(); | 
|  | for (int activity_type = ActivityTypeIds::ACTIVITY_NONE; | 
|  | activity_type < ActivityTypeIds::ACTIVITY_MAX_VALUE; | 
|  | ++activity_type) { | 
|  | if (launched & GetActivityFlag(activity_type)) | 
|  | IncrementListValue(launch_counts, activity_type); | 
|  | } | 
|  | local_state_->SetInteger(prefs::kStabilityLaunchedActivityFlags, 0); | 
|  |  | 
|  | // Track any Activities that were in the foreground when Chrome died. | 
|  | // These Activities failed to be recorded as leaving the foreground, so Chrome | 
|  | // couldn't have ended the UMA session cleanly.  Record them as crashing. | 
|  | const int foreground = | 
|  | local_state_->GetInteger(prefs::kStabilityForegroundActivityType); | 
|  | if (foreground != ActivityTypeIds::ACTIVITY_NONE) { | 
|  | ListPrefUpdate update_crashes(local_state_, | 
|  | prefs::kStabilityCrashedActivityCounts); | 
|  | base::ListValue* crash_counts = update_crashes.Get(); | 
|  | IncrementListValue(crash_counts, foreground); | 
|  | local_state_->SetInteger(prefs::kStabilityForegroundActivityType, | 
|  | ActivityTypeIds::ACTIVITY_NONE); | 
|  | } | 
|  |  | 
|  | local_state_->CommitPendingWrite(); | 
|  | } | 
|  |  | 
|  | void AndroidMetricsProvider::ConvertStabilityPrefsToHistograms() { | 
|  | ListPrefUpdate launch_updater(local_state_, | 
|  | prefs::kStabilityLaunchedActivityCounts); | 
|  | ListPrefUpdate crash_updater(local_state_, | 
|  | prefs::kStabilityCrashedActivityCounts); | 
|  |  | 
|  | base::ListValue* launch_counts = launch_updater.Get(); | 
|  | base::ListValue* crash_counts = crash_updater.Get(); | 
|  |  | 
|  | for (int activity_type = ActivityTypeIds::ACTIVITY_NONE; | 
|  | activity_type < ActivityTypeIds::ACTIVITY_MAX_VALUE; | 
|  | ++activity_type) { | 
|  | int launch_count = 0; | 
|  | int crash_count = 0; | 
|  |  | 
|  | launch_counts->GetInteger(activity_type, &launch_count); | 
|  | crash_counts->GetInteger(activity_type, &crash_count); | 
|  |  | 
|  | for (int count = 0; count < launch_count; ++count) { | 
|  | UMA_STABILITY_HISTOGRAM_ENUMERATION( | 
|  | "Chrome.Android.Activity.LaunchCounts", | 
|  | activity_type, | 
|  | ActivityTypeIds::ACTIVITY_MAX_VALUE); | 
|  | } | 
|  |  | 
|  | for (int count = 0; count < crash_count; ++count) { | 
|  | UMA_STABILITY_HISTOGRAM_ENUMERATION("Chrome.Android.Activity.CrashCounts", | 
|  | activity_type, | 
|  | ActivityTypeIds::ACTIVITY_MAX_VALUE); | 
|  | } | 
|  | } | 
|  |  | 
|  | launch_counts->Clear(); | 
|  | crash_counts->Clear(); | 
|  | } |