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/metrics/sparse_histogram.h"
12#include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
13#include "chrome/common/extensions/api/metrics_private.h"
14#include "components/variations/variations_associated_data.h"
15#include "content/public/browser/user_metrics.h"
16#include "extensions/common/extension.h"
17
18namespace extensions {
19
20namespace GetIsCrashReportingEnabled =
21    api::metrics_private::GetIsCrashReportingEnabled;
22namespace GetVariationParams = api::metrics_private::GetVariationParams;
23namespace GetFieldTrial = api::metrics_private::GetFieldTrial;
24namespace RecordUserAction = api::metrics_private::RecordUserAction;
25namespace RecordValue = api::metrics_private::RecordValue;
26namespace RecordSparseValue = api::metrics_private::RecordSparseValue;
27namespace RecordPercentage = api::metrics_private::RecordPercentage;
28namespace RecordCount = api::metrics_private::RecordCount;
29namespace RecordSmallCount = api::metrics_private::RecordSmallCount;
30namespace RecordMediumCount = api::metrics_private::RecordMediumCount;
31namespace RecordTime = api::metrics_private::RecordTime;
32namespace RecordMediumTime = api::metrics_private::RecordMediumTime;
33namespace RecordLongTime = api::metrics_private::RecordLongTime;
34
35namespace {
36
37const size_t kMaxBuckets = 10000; // We don't ever want more than these many
38                                  // buckets; there is no real need for them
39                                  // and would cause crazy memory usage
40} // namespace
41
42bool MetricsPrivateGetIsCrashReportingEnabledFunction::RunSync() {
43  SetResult(new base::FundamentalValue(
44      ChromeMetricsServiceAccessor::IsCrashReportingEnabled()));
45  return true;
46}
47
48bool MetricsPrivateGetFieldTrialFunction::RunSync() {
49  std::string name;
50  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &name));
51
52  SetResult(new base::StringValue(base::FieldTrialList::FindFullName(name)));
53  return true;
54}
55
56bool MetricsPrivateGetVariationParamsFunction::RunSync() {
57  scoped_ptr<GetVariationParams::Params> params(
58      GetVariationParams::Params::Create(*args_));
59  EXTENSION_FUNCTION_VALIDATE(params.get());
60
61  GetVariationParams::Results::Params result;
62  if (variations::GetVariationParams(params->name,
63                                     &result.additional_properties)) {
64    SetResult(result.ToValue().release());
65  }
66  return true;
67}
68
69bool MetricsPrivateRecordUserActionFunction::RunSync() {
70  scoped_ptr<RecordUserAction::Params> params(
71      RecordUserAction::Params::Create(*args_));
72  EXTENSION_FUNCTION_VALIDATE(params.get());
73
74  content::RecordComputedAction(params->name);
75  return true;
76}
77
78bool MetricsHistogramHelperFunction::RecordValue(
79    const std::string& name,
80    base::HistogramType type,
81    int min, int max, size_t buckets,
82    int sample) {
83  // Make sure toxic values don't get to internal code.
84  // Fix for maximums
85  min = std::min(min, INT_MAX - 3);
86  max = std::min(max, INT_MAX - 3);
87  buckets = std::min(buckets, kMaxBuckets);
88  // Fix for minimums.
89  min = std::max(min, 1);
90  max = std::max(max, min + 1);
91  buckets = std::max(buckets, static_cast<size_t>(3));
92  // Trim buckets down to a maximum of the given range + over/underflow buckets
93  if (buckets > static_cast<size_t>(max - min + 2))
94    buckets = max - min + 2;
95
96  base::HistogramBase* counter;
97  if (type == base::LINEAR_HISTOGRAM) {
98    counter = base::LinearHistogram::FactoryGet(
99        name, min, max, buckets,
100        base::HistogramBase::kUmaTargetedHistogramFlag);
101  } else {
102    counter = base::Histogram::FactoryGet(
103        name, min, max, buckets,
104        base::HistogramBase::kUmaTargetedHistogramFlag);
105  }
106
107  // The histogram can be NULL if it is constructed with bad arguments.  Ignore
108  // that data for this API.  An error message will be logged.
109  if (counter)
110    counter->Add(sample);
111  return true;
112}
113
114bool MetricsPrivateRecordValueFunction::RunSync() {
115  scoped_ptr<RecordValue::Params> params(RecordValue::Params::Create(*args_));
116  EXTENSION_FUNCTION_VALIDATE(params.get());
117
118  // Get the histogram parameters from the metric type object.
119  std::string type = api::metrics_private::MetricType::ToString(
120      params->metric.type);
121
122  base::HistogramType histogram_type(type == "histogram-linear" ?
123      base::LINEAR_HISTOGRAM : base::HISTOGRAM);
124  return RecordValue(params->metric.metric_name, histogram_type,
125                     params->metric.min, params->metric.max,
126                     params->metric.buckets, params->value);
127}
128
129bool MetricsPrivateRecordSparseValueFunction::RunSync() {
130  scoped_ptr<RecordSparseValue::Params> params(
131      RecordSparseValue::Params::Create(*args_));
132  EXTENSION_FUNCTION_VALIDATE(params.get());
133  // This particular UMA_HISTOGRAM_ macro is okay for
134  // non-runtime-constant strings.
135  UMA_HISTOGRAM_SPARSE_SLOWLY(params->metric_name, params->value);
136  return true;
137}
138
139bool MetricsPrivateRecordPercentageFunction::RunSync() {
140  scoped_ptr<RecordPercentage::Params> params(
141      RecordPercentage::Params::Create(*args_));
142  EXTENSION_FUNCTION_VALIDATE(params.get());
143  return RecordValue(params->metric_name, base::LINEAR_HISTOGRAM,
144                     1, 101, 102, params->value);
145}
146
147bool MetricsPrivateRecordCountFunction::RunSync() {
148  scoped_ptr<RecordCount::Params> params(RecordCount::Params::Create(*args_));
149  EXTENSION_FUNCTION_VALIDATE(params.get());
150  return RecordValue(params->metric_name, base::HISTOGRAM,
151                     1, 1000000, 50, params->value);
152}
153
154bool MetricsPrivateRecordSmallCountFunction::RunSync() {
155  scoped_ptr<RecordSmallCount::Params> params(
156      RecordSmallCount::Params::Create(*args_));
157  EXTENSION_FUNCTION_VALIDATE(params.get());
158  return RecordValue(params->metric_name, base::HISTOGRAM,
159                     1, 100, 50, params->value);
160}
161
162bool MetricsPrivateRecordMediumCountFunction::RunSync() {
163  scoped_ptr<RecordMediumCount::Params> params(
164      RecordMediumCount::Params::Create(*args_));
165  EXTENSION_FUNCTION_VALIDATE(params.get());
166  return RecordValue(params->metric_name, base::HISTOGRAM,
167                     1, 10000, 50, params->value);
168}
169
170bool MetricsPrivateRecordTimeFunction::RunSync() {
171  scoped_ptr<RecordTime::Params> params(RecordTime::Params::Create(*args_));
172  EXTENSION_FUNCTION_VALIDATE(params.get());
173  static const int kTenSecMs = 10 * 1000;
174  return RecordValue(params->metric_name, base::HISTOGRAM,
175                     1, kTenSecMs, 50, params->value);
176}
177
178bool MetricsPrivateRecordMediumTimeFunction::RunSync() {
179  scoped_ptr<RecordMediumTime::Params> params(
180      RecordMediumTime::Params::Create(*args_));
181  EXTENSION_FUNCTION_VALIDATE(params.get());
182  static const int kThreeMinMs = 3 * 60 * 1000;
183  return RecordValue(params->metric_name, base::HISTOGRAM,
184                     1, kThreeMinMs, 50, params->value);
185}
186
187bool MetricsPrivateRecordLongTimeFunction::RunSync() {
188  scoped_ptr<RecordLongTime::Params> params(
189      RecordLongTime::Params::Create(*args_));
190  EXTENSION_FUNCTION_VALIDATE(params.get());
191  static const int kOneHourMs = 60 * 60 * 1000;
192  return RecordValue(params->metric_name, base::HISTOGRAM,
193                     1, kOneHourMs, 50, params->value);
194}
195
196} // namespace extensions
197