ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / chromeos / external_metrics.cc
blobfe248a717b4d25679275c1aed13e509306906767
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.
5 #include "chrome/browser/chromeos/external_metrics.h"
7 #include <map>
8 #include <string>
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"
26 using base::UserMetricsAction;
27 using content::BrowserThread;
29 namespace chromeos {
31 namespace {
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);
47 bool CheckLinearValues(const std::string& name, int maximum) {
48 return CheckValues(name, 1, maximum, maximum + 1);
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);
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";
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];
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();
93 } // namespace
95 // The interval between external metrics collections in seconds
96 static const int kExternalMetricsCollectionIntervalSeconds = 30;
97 const char kEventsFilePath[] = "/var/run/metrics/uma-events";
99 ExternalMetrics::ExternalMetrics() : uma_events_file_(kEventsFilePath) {
102 ExternalMetrics::~ExternalMetrics() {}
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");
114 // Initialize here field trials that don't need to read from files.
115 // (None for the moment.)
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);
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;
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;
145 void ExternalMetrics::RecordAction(const std::string& action) {
146 BrowserThread::PostTask(
147 BrowserThread::UI,
148 FROM_HERE,
149 base::Bind(&ExternalMetrics::RecordActionUI, this, action));
152 void ExternalMetrics::RecordCrashUI(const std::string& crash_kind) {
153 ChromeOSMetricsProvider::LogCrash(crash_kind);
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));
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;
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());
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;
186 base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
187 sample.name(),
189 sample.max(),
190 sample.max() + 1,
191 base::Histogram::kUmaTargetedHistogramFlag);
192 counter->Add(sample.sample());
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());
203 int ExternalMetrics::CollectEvents() {
204 ScopedVector<metrics::MetricSample> samples;
205 metrics::SerializationUtils::ReadAndTruncateMetricsFromFile(uma_events_file_,
206 &samples);
208 for (ScopedVector<metrics::MetricSample>::iterator it = samples.begin();
209 it != samples.end();
210 ++it) {
211 const metrics::MetricSample& sample = **it;
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;
234 return samples.size();
237 void ExternalMetrics::CollectEventsAndReschedule() {
238 base::ElapsedTimer timer;
239 CollectEvents();
240 UMA_HISTOGRAM_TIMES("UMA.CollectExternalEventsTime", timer.Elapsed());
241 ScheduleCollector();
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);
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();
259 ScheduleCollector();
262 } // namespace chromeos