1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/metrics/android_metrics_provider.h"
6
7#include "base/metrics/histogram.h"
8#include "base/prefs/pref_registry_simple.h"
9#include "base/prefs/pref_service.h"
10#include "base/prefs/scoped_user_pref_update.h"
11#include "base/values.h"
12#include "chrome/browser/android/feature_utilities.h"
13#include "chrome/common/pref_names.h"
14
15namespace {
16
17// Increments a particular entry in the ListValue.
18void IncrementListValue(base::ListValue* counts, int index) {
19  int current_count = 0;
20  counts->GetInteger(index, &current_count);
21  counts->Set(index, new base::FundamentalValue(current_count + 1));
22}
23
24// Takes an int corresponding to a Type and returns the corresponding flag.
25int GetActivityFlag(int type_id) {
26  ActivityTypeIds::Type type = ActivityTypeIds::GetActivityType(type_id);
27  DCHECK_LT(type, ActivityTypeIds::ACTIVITY_MAX_VALUE);
28  return (1 << type);
29}
30
31}  // namespace
32
33AndroidMetricsProvider::AndroidMetricsProvider(PrefService* local_state)
34    : local_state_(local_state) {
35  LogStabilityToPrefs();
36}
37
38AndroidMetricsProvider::~AndroidMetricsProvider() {
39}
40
41void AndroidMetricsProvider::ProvideGeneralMetrics(
42    metrics::ChromeUserMetricsExtension* uma_proto) {
43  UMA_HISTOGRAM_ENUMERATION(
44      "DocumentActivity.Enabled",
45      chrome::android::GetDocumentModeValue(),
46      chrome::android::RUNNING_MODE_MAX);
47}
48
49void AndroidMetricsProvider::ProvideStabilityMetrics(
50    metrics::SystemProfileProto* system_profile_proto) {
51  ConvertStabilityPrefsToHistograms();
52}
53
54void AndroidMetricsProvider::LogStabilityToPrefs() {
55  // Track which Activities were launched by the user.
56  // A 'launch' is defined as starting the Activity at least once during a
57  // UMA session.  Multiple launches are counted only once since it is possible
58  // for users to hop between Activities (e.g. entering and leaving Settings).
59  const int launched =
60      local_state_->GetInteger(prefs::kStabilityLaunchedActivityFlags);
61  ListPrefUpdate update_launches(local_state_,
62                                 prefs::kStabilityLaunchedActivityCounts);
63  base::ListValue* launch_counts = update_launches.Get();
64  for (int activity_type = ActivityTypeIds::ACTIVITY_NONE;
65       activity_type < ActivityTypeIds::ACTIVITY_MAX_VALUE;
66       ++activity_type) {
67    if (launched & GetActivityFlag(activity_type))
68      IncrementListValue(launch_counts, activity_type);
69  }
70  local_state_->SetInteger(prefs::kStabilityLaunchedActivityFlags, 0);
71
72  // Track any Activities that were in the foreground when Chrome died.
73  // These Activities failed to be recorded as leaving the foreground, so Chrome
74  // couldn't have ended the UMA session cleanly.  Record them as crashing.
75  const int foreground =
76      local_state_->GetInteger(prefs::kStabilityForegroundActivityType);
77  if (foreground != ActivityTypeIds::ACTIVITY_NONE) {
78    ListPrefUpdate update_crashes(local_state_,
79                                  prefs::kStabilityCrashedActivityCounts);
80    base::ListValue* crash_counts = update_crashes.Get();
81    IncrementListValue(crash_counts, foreground);
82    local_state_->SetInteger(prefs::kStabilityForegroundActivityType,
83                             ActivityTypeIds::ACTIVITY_NONE);
84  }
85
86  local_state_->CommitPendingWrite();
87}
88
89void AndroidMetricsProvider::ConvertStabilityPrefsToHistograms() {
90  ListPrefUpdate launch_updater(local_state_,
91                                prefs::kStabilityLaunchedActivityCounts);
92  ListPrefUpdate crash_updater(local_state_,
93                               prefs::kStabilityCrashedActivityCounts);
94
95  base::ListValue* launch_counts = launch_updater.Get();
96  base::ListValue* crash_counts = crash_updater.Get();
97
98  for (int activity_type = ActivityTypeIds::ACTIVITY_NONE;
99       activity_type < ActivityTypeIds::ACTIVITY_MAX_VALUE;
100       ++activity_type) {
101    int launch_count = 0;
102    int crash_count = 0;
103
104    launch_counts->GetInteger(activity_type, &launch_count);
105    crash_counts->GetInteger(activity_type, &crash_count);
106
107    for (int count = 0; count < launch_count; ++count) {
108      UMA_STABILITY_HISTOGRAM_ENUMERATION(
109          "Chrome.Android.Activity.LaunchCounts",
110          activity_type,
111          ActivityTypeIds::ACTIVITY_MAX_VALUE);
112    }
113
114    for (int count = 0; count < crash_count; ++count) {
115      UMA_STABILITY_HISTOGRAM_ENUMERATION("Chrome.Android.Activity.CrashCounts",
116                                          activity_type,
117                                          ActivityTypeIds::ACTIVITY_MAX_VALUE);
118    }
119  }
120
121  launch_counts->Clear();
122  crash_counts->Clear();
123}
124
125void AndroidMetricsProvider::OnForegroundActivityChanged(
126    ActivityTypeIds::Type type) {
127  DCHECK_LT(type, ActivityTypeIds::ACTIVITY_MAX_VALUE);
128
129  if (type == local_state_->GetInteger(prefs::kStabilityForegroundActivityType))
130    return;
131
132  // Record that the Activity is now in the foreground.
133  local_state_->SetInteger(prefs::kStabilityForegroundActivityType, type);
134
135  // Record that the Activity was launched this sesaion.
136  // The pref stores a set of flags ORed together, where each set flag
137  // corresponds to a launched Activity type.
138  int launched =
139      local_state_->GetInteger(prefs::kStabilityLaunchedActivityFlags);
140  if (type != ActivityTypeIds::ACTIVITY_NONE) {
141    launched |= GetActivityFlag(type);
142    local_state_->SetInteger(prefs::kStabilityLaunchedActivityFlags, launched);
143  }
144
145  local_state_->CommitPendingWrite();
146}
147
148// static
149void AndroidMetricsProvider::RegisterPrefs(PrefRegistrySimple* registry) {
150  registry->RegisterIntegerPref(prefs::kStabilityForegroundActivityType,
151                                ActivityTypeIds::ACTIVITY_NONE);
152  registry->RegisterIntegerPref(prefs::kStabilityLaunchedActivityFlags, 0);
153  registry->RegisterListPref(prefs::kStabilityLaunchedActivityCounts);
154  registry->RegisterListPref(prefs::kStabilityCrashedActivityCounts);
155}
156