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"
9 #include "base/strings/string_number_conversions.h"
10 #include "components/variations/variations_associated_data.h"
12 using base::TimeDelta
;
18 // The delay, in seconds, after startup before sending the first log message.
19 #if defined(OS_ANDROID) || defined(OS_IOS)
20 // Sessions are more likely to be short on a mobile device, so handle the
21 // initial log quickly.
22 const int kInitialUploadIntervalSeconds
= 15;
24 const int kInitialUploadIntervalSeconds
= 60;
27 // The delay, in seconds, between uploading when there are queued logs from
28 // previous sessions to send.
29 #if defined(OS_ANDROID) || defined(OS_IOS)
30 // Sending in a burst is better on a mobile device, since keeping the radio on
32 const int kUnsentLogsIntervalSeconds
= 3;
34 const int kUnsentLogsIntervalSeconds
= 15;
37 // When uploading metrics to the server fails, we progressively wait longer and
38 // longer before sending the next log. This backoff process helps reduce load
39 // on a server that is having issues.
40 // The following is the multiplier we use to expand that inter-log duration.
41 const double kBackoffMultiplier
= 1.1;
43 // The maximum backoff multiplier.
44 const int kMaxBackoffMultiplier
= 10;
48 INIT_TASK_COMPLETED_FIRST
,
49 INIT_SEQUENCE_ENUM_SIZE
,
52 void LogMetricsInitSequence(InitSequence sequence
) {
53 UMA_HISTOGRAM_ENUMERATION("UMA.InitSequence", sequence
,
54 INIT_SEQUENCE_ENUM_SIZE
);
57 void LogActualUploadInterval(TimeDelta interval
) {
58 UMA_HISTOGRAM_CUSTOM_COUNTS("UMA.ActualLogUploadInterval",
61 base::TimeDelta::FromHours(12).InMinutes(),
65 } // anonymous namespace
67 MetricsReportingScheduler::MetricsReportingScheduler(
68 const base::Closure
& upload_callback
,
69 const base::Callback
<base::TimeDelta(void)>& upload_interval_callback
)
70 : upload_callback_(upload_callback
),
71 upload_interval_(TimeDelta::FromSeconds(kInitialUploadIntervalSeconds
)),
73 callback_pending_(false),
74 init_task_complete_(false),
75 waiting_for_init_task_complete_(false),
76 upload_interval_callback_(upload_interval_callback
) {
79 MetricsReportingScheduler::~MetricsReportingScheduler() {}
81 void MetricsReportingScheduler::Start() {
86 void MetricsReportingScheduler::Stop() {
88 if (upload_timer_
.IsRunning())
92 // Callback from MetricsService when the startup init task has completed.
93 void MetricsReportingScheduler::InitTaskComplete() {
94 DCHECK(!init_task_complete_
);
95 init_task_complete_
= true;
96 if (waiting_for_init_task_complete_
) {
97 waiting_for_init_task_complete_
= false;
100 LogMetricsInitSequence(INIT_TASK_COMPLETED_FIRST
);
104 void MetricsReportingScheduler::UploadFinished(bool server_is_healthy
,
105 bool more_logs_remaining
) {
106 DCHECK(callback_pending_
);
107 callback_pending_
= false;
108 // If the server is having issues, back off. Otherwise, reset to default
109 // (unless there are more logs to send, in which case the next upload should
111 if (!server_is_healthy
) {
112 BackOffUploadInterval();
113 } else if (more_logs_remaining
) {
114 upload_interval_
= TimeDelta::FromSeconds(kUnsentLogsIntervalSeconds
);
116 upload_interval_
= GetStandardUploadInterval();
117 last_upload_finish_time_
= base::TimeTicks::Now();
121 ScheduleNextUpload();
124 void MetricsReportingScheduler::UploadCancelled() {
125 DCHECK(callback_pending_
);
126 callback_pending_
= false;
128 ScheduleNextUpload();
131 void MetricsReportingScheduler::SetUploadIntervalForTesting(
132 base::TimeDelta interval
) {
133 upload_interval_
= interval
;
136 void MetricsReportingScheduler::TriggerUpload() {
137 // If the timer fired before the init task has completed, don't trigger the
138 // upload yet - wait for the init task to complete and do it then.
139 if (!init_task_complete_
) {
140 LogMetricsInitSequence(TIMER_FIRED_FIRST
);
141 waiting_for_init_task_complete_
= true;
145 if (!last_upload_finish_time_
.is_null()) {
146 LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_
);
147 last_upload_finish_time_
= base::TimeTicks();
150 callback_pending_
= true;
151 upload_callback_
.Run();
154 void MetricsReportingScheduler::ScheduleNextUpload() {
156 if (upload_timer_
.IsRunning() || callback_pending_
)
159 upload_timer_
.Start(FROM_HERE
, upload_interval_
, this,
160 &MetricsReportingScheduler::TriggerUpload
);
163 void MetricsReportingScheduler::BackOffUploadInterval() {
164 DCHECK_GT(kBackoffMultiplier
, 1.0);
165 upload_interval_
= TimeDelta::FromMicroseconds(
166 static_cast<int64
>(kBackoffMultiplier
*
167 upload_interval_
.InMicroseconds()));
169 TimeDelta max_interval
= kMaxBackoffMultiplier
* GetStandardUploadInterval();
170 if (upload_interval_
> max_interval
|| upload_interval_
.InSeconds() < 0) {
171 upload_interval_
= max_interval
;
175 base::TimeDelta
MetricsReportingScheduler::GetStandardUploadInterval() {
176 return upload_interval_callback_
.Run();
179 } // namespace metrics