1// Copyright (c) 2012 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/extensions/api/metrics_private/metrics_private_api.h"
6
7#include <algorithm>
8
9#include "base/metrics/field_trial.h"
10#include "base/metrics/histogram.h"
11#include "base/prefs/pref_service.h"
12#include "chrome/browser/browser_process.h"
13#include "chrome/common/extensions/api/metrics_private.h"
14#include "chrome/common/extensions/extension.h"
15#include "chrome/common/metrics/variations/variations_associated_data.h"
16#include "chrome/common/pref_names.h"
17#include "content/public/browser/user_metrics.h"
18
19#if defined(OS_CHROMEOS)
20#include "chrome/browser/chromeos/settings/cros_settings.h"
21#endif  // OS_CHROMEOS
22
23namespace extensions {
24
25namespace GetIsCrashReportingEnabled =
26    api::metrics_private::GetIsCrashReportingEnabled;
27namespace GetVariationParams = api::metrics_private::GetVariationParams;
28namespace GetFieldTrial = api::metrics_private::GetFieldTrial;
29namespace RecordUserAction = api::metrics_private::RecordUserAction;
30namespace RecordValue = api::metrics_private::RecordValue;
31namespace RecordPercentage = api::metrics_private::RecordPercentage;
32namespace RecordCount = api::metrics_private::RecordCount;
33namespace RecordSmallCount = api::metrics_private::RecordSmallCount;
34namespace RecordMediumCount = api::metrics_private::RecordMediumCount;
35namespace RecordTime = api::metrics_private::RecordTime;
36namespace RecordMediumTime = api::metrics_private::RecordMediumTime;
37namespace RecordLongTime = api::metrics_private::RecordLongTime;
38
39namespace {
40
41const size_t kMaxBuckets = 10000; // We don't ever want more than these many
42                                  // buckets; there is no real need for them
43                                  // and would cause crazy memory usage
44} // namespace
45
46// Returns true if the user opted in to sending crash reports.
47// TODO(vadimt): Unify with CrashesUI::CrashReportingUIEnabled
48static bool IsCrashReportingEnabled() {
49#if defined(GOOGLE_CHROME_BUILD)
50#if defined(OS_CHROMEOS)
51  bool reporting_enabled = false;
52  chromeos::CrosSettings::Get()->GetBoolean(chromeos::kStatsReportingPref,
53                                            &reporting_enabled);
54  return reporting_enabled;
55#elif defined(OS_ANDROID)
56  // Android has its own settings for metrics / crash uploading.
57  PrefService* prefs = g_browser_process->local_state();
58  return prefs->GetBoolean(prefs::kCrashReportingEnabled);
59#else
60  PrefService* prefs = g_browser_process->local_state();
61  return prefs->GetBoolean(prefs::kMetricsReportingEnabled);
62#endif
63#else
64  return false;
65#endif
66}
67
68bool MetricsPrivateGetIsCrashReportingEnabledFunction::RunImpl() {
69  SetResult(new base::FundamentalValue(IsCrashReportingEnabled()));
70  return true;
71}
72
73bool MetricsPrivateGetFieldTrialFunction::RunImpl() {
74  std::string name;
75  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &name));
76
77  SetResult(new base::StringValue(base::FieldTrialList::FindFullName(name)));
78  return true;
79}
80
81bool MetricsPrivateGetVariationParamsFunction::RunImpl() {
82  scoped_ptr<GetVariationParams::Params> params(
83      GetVariationParams::Params::Create(*args_));
84  EXTENSION_FUNCTION_VALIDATE(params.get());
85
86  GetVariationParams::Results::Params result;
87  if (!chrome_variations::GetVariationParams(
88      params->name, &result.additional_properties)) {
89    SetError("Variation parameters are unavailable.");
90    return false;
91  }
92
93  SetResult(result.ToValue().release());
94  return true;
95}
96
97bool MetricsPrivateRecordUserActionFunction::RunImpl() {
98  scoped_ptr<RecordUserAction::Params> params(
99      RecordUserAction::Params::Create(*args_));
100  EXTENSION_FUNCTION_VALIDATE(params.get());
101
102  content::RecordComputedAction(params->name);
103  return true;
104}
105
106bool MetricsHistogramHelperFunction::GetNameAndSample(std::string* name,
107                                                      int* sample) {
108  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, name));
109  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(1, sample));
110  return true;
111}
112
113bool MetricsHistogramHelperFunction::RecordValue(
114    const std::string& name,
115    base::HistogramType type,
116    int min, int max, size_t buckets,
117    int sample) {
118  // Make sure toxic values don't get to internal code.
119  // Fix for maximums
120  min = std::min(min, INT_MAX - 3);
121  max = std::min(max, INT_MAX - 3);
122  buckets = std::min(buckets, kMaxBuckets);
123  // Fix for minimums.
124  min = std::max(min, 1);
125  max = std::max(max, min + 1);
126  buckets = std::max(buckets, static_cast<size_t>(3));
127  // Trim buckets down to a maximum of the given range + over/underflow buckets
128  if (buckets > static_cast<size_t>(max - min + 2))
129    buckets = max - min + 2;
130
131  base::HistogramBase* counter;
132  if (type == base::LINEAR_HISTOGRAM) {
133    counter = base::LinearHistogram::FactoryGet(
134        name, min, max, buckets,
135        base::HistogramBase::kUmaTargetedHistogramFlag);
136  } else {
137    counter = base::Histogram::FactoryGet(
138        name, min, max, buckets,
139        base::HistogramBase::kUmaTargetedHistogramFlag);
140  }
141
142  counter->Add(sample);
143  return true;
144}
145
146bool MetricsPrivateRecordValueFunction::RunImpl() {
147  scoped_ptr<RecordValue::Params> params(RecordValue::Params::Create(*args_));
148  EXTENSION_FUNCTION_VALIDATE(params.get());
149
150  // Get the histogram parameters from the metric type object.
151  std::string type = api::metrics_private::MetricType::ToString(
152      params->metric.type);
153
154  base::HistogramType histogram_type(type == "histogram-linear" ?
155      base::LINEAR_HISTOGRAM : base::HISTOGRAM);
156  return RecordValue(params->metric.metric_name, histogram_type,
157                     params->metric.min, params->metric.max,
158                     params->metric.buckets, params->value);
159}
160
161bool MetricsPrivateRecordPercentageFunction::RunImpl() {
162  scoped_ptr<RecordPercentage::Params> params(
163      RecordPercentage::Params::Create(*args_));
164  EXTENSION_FUNCTION_VALIDATE(params.get());
165  return RecordValue(params->metric_name, base::LINEAR_HISTOGRAM,
166                     1, 101, 102, params->value);
167}
168
169bool MetricsPrivateRecordCountFunction::RunImpl() {
170  scoped_ptr<RecordCount::Params> params(RecordCount::Params::Create(*args_));
171  EXTENSION_FUNCTION_VALIDATE(params.get());
172  return RecordValue(params->metric_name, base::HISTOGRAM,
173                     1, 1000000, 50, params->value);
174}
175
176bool MetricsPrivateRecordSmallCountFunction::RunImpl() {
177  scoped_ptr<RecordSmallCount::Params> params(
178      RecordSmallCount::Params::Create(*args_));
179  EXTENSION_FUNCTION_VALIDATE(params.get());
180  return RecordValue(params->metric_name, base::HISTOGRAM,
181                     1, 100, 50, params->value);
182}
183
184bool MetricsPrivateRecordMediumCountFunction::RunImpl() {
185  scoped_ptr<RecordMediumCount::Params> params(
186      RecordMediumCount::Params::Create(*args_));
187  EXTENSION_FUNCTION_VALIDATE(params.get());
188  return RecordValue(params->metric_name, base::HISTOGRAM,
189                     1, 10000, 50, params->value);
190}
191
192bool MetricsPrivateRecordTimeFunction::RunImpl() {
193  scoped_ptr<RecordTime::Params> params(RecordTime::Params::Create(*args_));
194  EXTENSION_FUNCTION_VALIDATE(params.get());
195  static const int kTenSecMs = 10 * 1000;
196  return RecordValue(params->metric_name, base::HISTOGRAM,
197                     1, kTenSecMs, 50, params->value);
198}
199
200bool MetricsPrivateRecordMediumTimeFunction::RunImpl() {
201  scoped_ptr<RecordMediumTime::Params> params(
202      RecordMediumTime::Params::Create(*args_));
203  EXTENSION_FUNCTION_VALIDATE(params.get());
204  static const int kThreeMinMs = 3 * 60 * 1000;
205  return RecordValue(params->metric_name, base::HISTOGRAM,
206                     1, kThreeMinMs, 50, params->value);
207}
208
209bool MetricsPrivateRecordLongTimeFunction::RunImpl() {
210  scoped_ptr<RecordLongTime::Params> params(
211      RecordLongTime::Params::Create(*args_));
212  EXTENSION_FUNCTION_VALIDATE(params.get());
213  static const int kOneHourMs = 60 * 60 * 1000;
214  return RecordValue(params->metric_name, base::HISTOGRAM,
215                     1, kOneHourMs, 50, params->value);
216}
217
218} // namespace extensions
219