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.
5 #include "components/metrics/metrics_reporting_scheduler.h"
7 #include "base/compiler_specific.h"
8 #include "base/metrics/histogram.h"
10 using base::TimeDelta
;
16 // The delay, in seconds, after startup before sending the first log message.
17 #if defined(OS_ANDROID) || defined(OS_IOS)
18 // Sessions are more likely to be short on a mobile device, so handle the
19 // initial log quickly.
20 const int kInitialUploadIntervalSeconds
= 15;
22 const int kInitialUploadIntervalSeconds
= 60;
25 // The delay, in seconds, between uploading when there are queued logs from
26 // previous sessions to send.
27 #if defined(OS_ANDROID) || defined(OS_IOS)
28 // Sending in a burst is better on a mobile device, since keeping the radio on
30 const int kUnsentLogsIntervalSeconds
= 3;
32 const int kUnsentLogsIntervalSeconds
= 15;
35 // Standard interval between log uploads, in seconds.
36 #if defined(OS_ANDROID) || defined(OS_IOS)
37 const int kStandardUploadIntervalSeconds
= 5 * 60; // Five minutes.
39 const int kStandardUploadIntervalSeconds
= 30 * 60; // Thirty minutes.
42 // When uploading metrics to the server fails, we progressively wait longer and
43 // longer before sending the next log. This backoff process helps reduce load
44 // on a server that is having issues.
45 // The following is the multiplier we use to expand that inter-log duration.
46 const double kBackoffMultiplier
= 1.1;
48 // The maximum backoff multiplier.
49 const int kMaxBackoffMultiplier
= 10;
53 INIT_TASK_COMPLETED_FIRST
,
54 INIT_SEQUENCE_ENUM_SIZE
,
57 void LogMetricsInitSequence(InitSequence sequence
) {
58 UMA_HISTOGRAM_ENUMERATION("UMA.InitSequence", sequence
,
59 INIT_SEQUENCE_ENUM_SIZE
);
62 } // anonymous namespace
64 MetricsReportingScheduler::MetricsReportingScheduler(
65 const base::Closure
& upload_callback
)
66 : upload_callback_(upload_callback
),
67 upload_interval_(TimeDelta::FromSeconds(kInitialUploadIntervalSeconds
)),
69 callback_pending_(false),
70 init_task_complete_(false),
71 waiting_for_init_task_complete_(false) {
74 MetricsReportingScheduler::~MetricsReportingScheduler() {}
76 void MetricsReportingScheduler::Start() {
81 void MetricsReportingScheduler::Stop() {
83 if (upload_timer_
.IsRunning())
87 // Callback from MetricsService when the startup init task has completed.
88 void MetricsReportingScheduler::InitTaskComplete() {
89 DCHECK(!init_task_complete_
);
90 init_task_complete_
= true;
91 if (waiting_for_init_task_complete_
) {
92 waiting_for_init_task_complete_
= false;
95 LogMetricsInitSequence(INIT_TASK_COMPLETED_FIRST
);
99 void MetricsReportingScheduler::UploadFinished(bool server_is_healthy
,
100 bool more_logs_remaining
) {
101 DCHECK(callback_pending_
);
102 callback_pending_
= false;
103 // If the server is having issues, back off. Otherwise, reset to default
104 // (unless there are more logs to send, in which case the next upload should
106 if (!server_is_healthy
) {
107 BackOffUploadInterval();
108 } else if (more_logs_remaining
) {
109 upload_interval_
= TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds
);
111 upload_interval_
= TimeDelta::FromSeconds(kStandardUploadIntervalSeconds
);
115 ScheduleNextUpload();
118 void MetricsReportingScheduler::UploadCancelled() {
119 DCHECK(callback_pending_
);
120 callback_pending_
= false;
122 ScheduleNextUpload();
125 void MetricsReportingScheduler::SetUploadIntervalForTesting(
126 base::TimeDelta interval
) {
127 upload_interval_
= interval
;
130 void MetricsReportingScheduler::TriggerUpload() {
131 // If the timer fired before the init task has completed, don't trigger the
132 // upload yet - wait for the init task to complete and do it then.
133 if (!init_task_complete_
) {
134 LogMetricsInitSequence(TIMER_FIRED_FIRST
);
135 waiting_for_init_task_complete_
= true;
138 callback_pending_
= true;
139 upload_callback_
.Run();
142 void MetricsReportingScheduler::ScheduleNextUpload() {
144 if (upload_timer_
.IsRunning() || callback_pending_
)
147 upload_timer_
.Start(FROM_HERE
, upload_interval_
, this,
148 &MetricsReportingScheduler::TriggerUpload
);
151 void MetricsReportingScheduler::BackOffUploadInterval() {
152 DCHECK_GT(kBackoffMultiplier
, 1.0);
153 upload_interval_
= TimeDelta::FromMicroseconds(
154 static_cast<int64
>(kBackoffMultiplier
*
155 upload_interval_
.InMicroseconds()));
157 TimeDelta max_interval
= kMaxBackoffMultiplier
*
158 TimeDelta::FromSeconds(kStandardUploadIntervalSeconds
);
159 if (upload_interval_
> max_interval
|| upload_interval_
.InSeconds() < 0) {
160 upload_interval_
= max_interval
;
164 } // namespace metrics