Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / external_metrics.cc
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/chromeos/external_metrics.h"
6
7 #include <map>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/metrics/field_trial.h"
14 #include "base/metrics/histogram.h"
15 #include "base/metrics/sparse_histogram.h"
16 #include "base/metrics/statistics_recorder.h"
17 #include "base/timer/elapsed_timer.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/metrics/chromeos_metrics_provider.h"
20 #include "components/metrics/metrics_service.h"
21 #include "components/metrics/serialization/metric_sample.h"
22 #include "components/metrics/serialization/serialization_utils.h"
23 #include "content/public/browser/browser_thread.h"
24 #include "content/public/browser/user_metrics.h"
25
26 using base::UserMetricsAction;
27 using content::BrowserThread;
28
29 namespace chromeos {
30
31 namespace {
32
33 bool CheckValues(const std::string& name,
34                  int minimum,
35                  int maximum,
36                  size_t bucket_count) {
37   if (!base::Histogram::InspectConstructionArguments(
38       name, &minimum, &maximum, &bucket_count))
39     return false;
40   base::HistogramBase* histogram =
41       base::StatisticsRecorder::FindHistogram(name);
42   if (!histogram)
43     return true;
44   return histogram->HasConstructionArguments(minimum, maximum, bucket_count);
45 }
46
47 bool CheckLinearValues(const std::string& name, int maximum) {
48   return CheckValues(name, 1, maximum, maximum + 1);
49 }
50
51 // Establishes field trial for wifi scanning in chromeos.  crbug.com/242733.
52 void SetupProgressiveScanFieldTrial() {
53   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
54   const char name_of_experiment[] = "ProgressiveScan";
55   const base::FilePath group_file_path(
56       "/home/chronos/.progressive_scan_variation");
57   const base::FieldTrial::Probability kDivisor = 1000;
58   scoped_refptr<base::FieldTrial> trial =
59       base::FieldTrialList::FactoryGetFieldTrial(
60           name_of_experiment, kDivisor, "Default", 2013, 12, 31,
61           base::FieldTrial::SESSION_RANDOMIZED, NULL);
62
63   // Announce the groups with 0 percentage; the actual percentages come from
64   // the server configuration.
65   std::map<int, std::string> group_to_char;
66   group_to_char[trial->AppendGroup("FullScan", 0)] = "c";
67   group_to_char[trial->AppendGroup("33Percent_4MinMax", 0)] = "1";
68   group_to_char[trial->AppendGroup("50Percent_4MinMax", 0)] = "2";
69   group_to_char[trial->AppendGroup("50Percent_8MinMax", 0)] = "3";
70   group_to_char[trial->AppendGroup("100Percent_8MinMax", 0)] = "4";
71   group_to_char[trial->AppendGroup("100Percent_1MinSeen_A", 0)] = "5";
72   group_to_char[trial->AppendGroup("100Percent_1MinSeen_B", 0)] = "6";
73   group_to_char[trial->AppendGroup("100Percent_1Min_4Max", 0)] = "7";
74
75   // Announce the experiment to any listeners (especially important is the UMA
76   // software, which will append the group names to UMA statistics).
77   const int group_num = trial->group();
78   std::string group_char = "x";
79   if (ContainsKey(group_to_char, group_num))
80     group_char = group_to_char[group_num];
81
82   // Write the group to the file to be read by ChromeOS.
83   int size = static_cast<int>(group_char.length());
84   if (base::WriteFile(group_file_path, group_char.c_str(), size) == size) {
85     VLOG(1) << "Configured in group '" << trial->group_name()
86             << "' ('" << group_char << "') for "
87             << name_of_experiment << " field trial";
88   } else {
89     VLOG(1) << "Couldn't write to " << group_file_path.value();
90   }
91 }
92
93 }  // namespace
94
95 // The interval between external metrics collections in seconds
96 static const int kExternalMetricsCollectionIntervalSeconds = 30;
97 const char kEventsFilePath[] = "/var/run/metrics/uma-events";
98
99 ExternalMetrics::ExternalMetrics() : uma_events_file_(kEventsFilePath) {
100 }
101
102 ExternalMetrics::~ExternalMetrics() {}
103
104 void ExternalMetrics::Start() {
105   // Register user actions external to the browser.
106   // tools/metrics/actions/extract_actions.py won't understand these lines, so
107   // all of these are explicitly added in that script.
108   // TODO(derat): We shouldn't need to verify actions before reporting them;
109   // remove all of this once http://crosbug.com/11125 is fixed.
110   valid_user_actions_.insert("Cryptohome.PKCS11InitFail");
111   valid_user_actions_.insert("Updater.ServerCertificateChanged");
112   valid_user_actions_.insert("Updater.ServerCertificateFailed");
113
114   // Initialize here field trials that don't need to read from files.
115   // (None for the moment.)
116
117   // Initialize any chromeos field trials that need to read from a file (e.g.,
118   // those that have an upstart script determine their experimental group for
119   // them) then schedule the data collection.  All of this is done on the file
120   // thread.
121   bool task_posted = BrowserThread::PostTask(
122       BrowserThread::FILE,
123       FROM_HERE,
124       base::Bind(&chromeos::ExternalMetrics::SetupFieldTrialsOnFileThread,
125                  this));
126   DCHECK(task_posted);
127 }
128
129 // static
130 scoped_refptr<ExternalMetrics> ExternalMetrics::CreateForTesting(
131     const std::string& filename) {
132   scoped_refptr<ExternalMetrics> external_metrics(new ExternalMetrics());
133   external_metrics->uma_events_file_ = filename;
134   return external_metrics;
135 }
136
137 void ExternalMetrics::RecordActionUI(std::string action_string) {
138   if (valid_user_actions_.count(action_string)) {
139     content::RecordComputedAction(action_string);
140   } else {
141     DLOG(ERROR) << "undefined UMA action: " << action_string;
142   }
143 }
144
145 void ExternalMetrics::RecordAction(const std::string& action) {
146   BrowserThread::PostTask(
147       BrowserThread::UI,
148       FROM_HERE,
149       base::Bind(&ExternalMetrics::RecordActionUI, this, action));
150 }
151
152 void ExternalMetrics::RecordCrashUI(const std::string& crash_kind) {
153   ChromeOSMetricsProvider::LogCrash(crash_kind);
154 }
155
156 void ExternalMetrics::RecordCrash(const std::string& crash_kind) {
157   BrowserThread::PostTask(
158       BrowserThread::UI, FROM_HERE,
159       base::Bind(&ExternalMetrics::RecordCrashUI, this, crash_kind));
160 }
161
162 void ExternalMetrics::RecordHistogram(const metrics::MetricSample& sample) {
163   CHECK_EQ(metrics::MetricSample::HISTOGRAM, sample.type());
164   if (!CheckValues(
165           sample.name(), sample.min(), sample.max(), sample.bucket_count())) {
166     DLOG(ERROR) << "Invalid histogram: " << sample.name();
167     return;
168   }
169
170   base::HistogramBase* counter =
171       base::Histogram::FactoryGet(sample.name(),
172                                   sample.min(),
173                                   sample.max(),
174                                   sample.bucket_count(),
175                                   base::Histogram::kUmaTargetedHistogramFlag);
176   counter->Add(sample.sample());
177 }
178
179 void ExternalMetrics::RecordLinearHistogram(
180     const metrics::MetricSample& sample) {
181   CHECK_EQ(metrics::MetricSample::LINEAR_HISTOGRAM, sample.type());
182   if (!CheckLinearValues(sample.name(), sample.max())) {
183     DLOG(ERROR) << "Invalid linear histogram: " << sample.name();
184     return;
185   }
186   base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
187       sample.name(),
188       1,
189       sample.max(),
190       sample.max() + 1,
191       base::Histogram::kUmaTargetedHistogramFlag);
192   counter->Add(sample.sample());
193 }
194
195 void ExternalMetrics::RecordSparseHistogram(
196     const metrics::MetricSample& sample) {
197   CHECK_EQ(metrics::MetricSample::SPARSE_HISTOGRAM, sample.type());
198   base::HistogramBase* counter = base::SparseHistogram::FactoryGet(
199       sample.name(), base::HistogramBase::kUmaTargetedHistogramFlag);
200   counter->Add(sample.sample());
201 }
202
203 int ExternalMetrics::CollectEvents() {
204   ScopedVector<metrics::MetricSample> samples;
205   metrics::SerializationUtils::ReadAndTruncateMetricsFromFile(uma_events_file_,
206                                                               &samples);
207
208   for (ScopedVector<metrics::MetricSample>::iterator it = samples.begin();
209        it != samples.end();
210        ++it) {
211     const metrics::MetricSample& sample = **it;
212
213     // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
214     // instance and thus only work if |sample.name()| is constant.
215     switch (sample.type()) {
216       case metrics::MetricSample::CRASH:
217         RecordCrash(sample.name());
218         break;
219       case metrics::MetricSample::USER_ACTION:
220         RecordAction(sample.name());
221         break;
222       case metrics::MetricSample::HISTOGRAM:
223         RecordHistogram(sample);
224         break;
225       case metrics::MetricSample::LINEAR_HISTOGRAM:
226         RecordLinearHistogram(sample);
227         break;
228       case metrics::MetricSample::SPARSE_HISTOGRAM:
229         RecordSparseHistogram(sample);
230         break;
231     }
232   }
233
234   return samples.size();
235 }
236
237 void ExternalMetrics::CollectEventsAndReschedule() {
238   base::ElapsedTimer timer;
239   CollectEvents();
240   UMA_HISTOGRAM_TIMES("UMA.CollectExternalEventsTime", timer.Elapsed());
241   ScheduleCollector();
242 }
243
244 void ExternalMetrics::ScheduleCollector() {
245   bool result;
246   result = BrowserThread::PostDelayedTask(
247       BrowserThread::FILE, FROM_HERE,
248       base::Bind(&chromeos::ExternalMetrics::CollectEventsAndReschedule, this),
249       base::TimeDelta::FromSeconds(kExternalMetricsCollectionIntervalSeconds));
250   DCHECK(result);
251 }
252
253 void ExternalMetrics::SetupFieldTrialsOnFileThread() {
254   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
255   // Field trials that do not read from files can be initialized in
256   // ExternalMetrics::Start() above.
257   SetupProgressiveScanFieldTrial();
258
259   ScheduleCollector();
260 }
261
262 }  // namespace chromeos