Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / components / metrics / metrics_reporting_scheduler.cc
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 "components/metrics/metrics_reporting_scheduler.h"
6
7 #include "base/compiler_specific.h"
8 #include "base/metrics/field_trial.h"
9 #include "base/metrics/histogram.h"
10 #include "base/strings/string_number_conversions.h"
11 #include "components/variations/variations_associated_data.h"
12
13 using base::TimeDelta;
14
15 namespace metrics {
16
17 namespace {
18
19 // The delay, in seconds, after startup before sending the first log message.
20 #if defined(OS_ANDROID) || defined(OS_IOS)
21 // Sessions are more likely to be short on a mobile device, so handle the
22 // initial log quickly.
23 const int kInitialUploadIntervalSeconds = 15;
24 #else
25 const int kInitialUploadIntervalSeconds = 60;
26 #endif
27
28 // The delay, in seconds, between uploading when there are queued logs from
29 // previous sessions to send.
30 #if defined(OS_ANDROID) || defined(OS_IOS)
31 // Sending in a burst is better on a mobile device, since keeping the radio on
32 // is very expensive.
33 const int kUnsentLogsIntervalSeconds = 3;
34 #else
35 const int kUnsentLogsIntervalSeconds = 15;
36 #endif
37
38 // Standard interval between log uploads, in seconds.
39 #if defined(OS_ANDROID) || defined(OS_IOS)
40 const int kStandardUploadIntervalSeconds = 5 * 60;  // Five minutes.
41 #else
42 const int kStandardUploadIntervalSeconds = 30 * 60;  // Thirty minutes.
43 #endif
44
45 // When uploading metrics to the server fails, we progressively wait longer and
46 // longer before sending the next log. This backoff process helps reduce load
47 // on a server that is having issues.
48 // The following is the multiplier we use to expand that inter-log duration.
49 const double kBackoffMultiplier = 1.1;
50
51 // The maximum backoff multiplier.
52 const int kMaxBackoffMultiplier = 10;
53
54 enum InitSequence {
55   TIMER_FIRED_FIRST,
56   INIT_TASK_COMPLETED_FIRST,
57   INIT_SEQUENCE_ENUM_SIZE,
58 };
59
60 void LogMetricsInitSequence(InitSequence sequence) {
61   UMA_HISTOGRAM_ENUMERATION("UMA.InitSequence", sequence,
62                             INIT_SEQUENCE_ENUM_SIZE);
63 }
64
65 void LogActualUploadInterval(TimeDelta interval) {
66   UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.ActualLogUploadInterval",
67                              interval.InMinutes(),
68                              1,
69                              base::TimeDelta::FromHours(12).InMinutes(),
70                              50);
71 }
72
73 // Returns upload interval specified for the current experiment running.
74 // TODO(gayane): Only for experimenting with upload interval for Android
75 // (bug: 17391128). Should be removed once the experiments are done.
76 base::TimeDelta GetUploadIntervalFromExperiment() {
77   std::string interval_str = variations::GetVariationParamValue(
78       "UMALogUploadInterval", "interval");
79   int interval;
80   if (interval_str.empty() || !base::StringToInt(interval_str, &interval))
81     return TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
82
83   return TimeDelta::FromMinutes(interval);
84 }
85
86 }  // anonymous namespace
87
88 MetricsReportingScheduler::MetricsReportingScheduler(
89     const base::Closure& upload_callback)
90     : upload_callback_(upload_callback),
91       upload_interval_(TimeDelta::FromSeconds(kInitialUploadIntervalSeconds)),
92       running_(false),
93       callback_pending_(false),
94       init_task_complete_(false),
95       waiting_for_init_task_complete_(false) {
96 }
97
98 MetricsReportingScheduler::~MetricsReportingScheduler() {}
99
100 void MetricsReportingScheduler::Start() {
101   GetUploadIntervalFromExperiment();
102   running_ = true;
103   ScheduleNextUpload();
104 }
105
106 void MetricsReportingScheduler::Stop() {
107   running_ = false;
108   if (upload_timer_.IsRunning())
109     upload_timer_.Stop();
110 }
111
112 // Callback from MetricsService when the startup init task has completed.
113 void MetricsReportingScheduler::InitTaskComplete() {
114   DCHECK(!init_task_complete_);
115   init_task_complete_ = true;
116   if (waiting_for_init_task_complete_) {
117     waiting_for_init_task_complete_ = false;
118     TriggerUpload();
119   } else {
120     LogMetricsInitSequence(INIT_TASK_COMPLETED_FIRST);
121   }
122 }
123
124 void MetricsReportingScheduler::UploadFinished(bool server_is_healthy,
125                                                bool more_logs_remaining) {
126   DCHECK(callback_pending_);
127   callback_pending_ = false;
128   // If the server is having issues, back off. Otherwise, reset to default
129   // (unless there are more logs to send, in which case the next upload should
130   // happen sooner).
131   if (!server_is_healthy) {
132     BackOffUploadInterval();
133   } else if (more_logs_remaining) {
134     upload_interval_ = TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds);
135   } else {
136     upload_interval_ = GetStandardUploadInterval();
137     last_upload_finish_time_ = base::TimeTicks::Now();
138   }
139
140   if (running_)
141     ScheduleNextUpload();
142 }
143
144 void MetricsReportingScheduler::UploadCancelled() {
145   DCHECK(callback_pending_);
146   callback_pending_ = false;
147   if (running_)
148     ScheduleNextUpload();
149 }
150
151 void MetricsReportingScheduler::SetUploadIntervalForTesting(
152     base::TimeDelta interval) {
153   upload_interval_ = interval;
154 }
155
156 void MetricsReportingScheduler::TriggerUpload() {
157   // If the timer fired before the init task has completed, don't trigger the
158   // upload yet - wait for the init task to complete and do it then.
159   if (!init_task_complete_) {
160     LogMetricsInitSequence(TIMER_FIRED_FIRST);
161     waiting_for_init_task_complete_ = true;
162     return;
163   }
164
165   if (!last_upload_finish_time_.is_null()) {
166     LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_);
167     last_upload_finish_time_ = base::TimeTicks();
168   }
169
170   callback_pending_ = true;
171   upload_callback_.Run();
172 }
173
174 void MetricsReportingScheduler::ScheduleNextUpload() {
175   DCHECK(running_);
176   if (upload_timer_.IsRunning() || callback_pending_)
177     return;
178
179   upload_timer_.Start(FROM_HERE, upload_interval_, this,
180                       &MetricsReportingScheduler::TriggerUpload);
181 }
182
183 void MetricsReportingScheduler::BackOffUploadInterval() {
184   DCHECK_GT(kBackoffMultiplier, 1.0);
185   upload_interval_ = TimeDelta::FromMicroseconds(
186       static_cast<int64>(kBackoffMultiplier *
187                          upload_interval_.InMicroseconds()));
188
189   TimeDelta max_interval = kMaxBackoffMultiplier * GetStandardUploadInterval();
190   if (upload_interval_ > max_interval || upload_interval_.InSeconds() < 0) {
191     upload_interval_ = max_interval;
192   }
193 }
194
195 base::TimeDelta MetricsReportingScheduler::GetStandardUploadInterval() {
196 #if defined(OS_ANDROID)
197   return GetUploadIntervalFromExperiment();
198 #else
199   return TimeDelta::FromSeconds(kStandardUploadIntervalSeconds);
200 #endif
201 }
202
203 }  // namespace metrics