blob: 4045492123186b9a537a00f3b3846b22bfc37f5b [file] [log] [blame]
holtea3b24112017-03-14 02:08:241// Copyright 2017 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// ReportingService handles uploading serialized logs to a server.
6
7#include "components/metrics/reporting_service.h"
8
9#include "base/bind.h"
10#include "base/callback.h"
Carlos IL75b352f2017-11-07 01:43:0211#include "base/command_line.h"
holtea3b24112017-03-14 02:08:2412#include "base/strings/string_number_conversions.h"
13#include "components/metrics/data_use_tracker.h"
14#include "components/metrics/log_store.h"
15#include "components/metrics/metrics_log_uploader.h"
16#include "components/metrics/metrics_service_client.h"
17#include "components/metrics/metrics_upload_scheduler.h"
18
19namespace metrics {
20
21// static
22void ReportingService::RegisterPrefs(PrefRegistrySimple* registry) {
23 DataUseTracker::RegisterPrefs(registry);
24}
25
26ReportingService::ReportingService(MetricsServiceClient* client,
27 PrefService* local_state,
28 size_t max_retransmit_size)
29 : client_(client),
30 max_retransmit_size_(max_retransmit_size),
31 reporting_active_(false),
32 log_upload_in_progress_(false),
33 data_use_tracker_(DataUseTracker::Create(local_state)),
34 self_ptr_factory_(this) {
Steven Holte971b0592017-10-12 15:28:2635 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:2436 DCHECK(client_);
37 DCHECK(local_state);
38}
39
40ReportingService::~ReportingService() {
41 DisableReporting();
42}
43
44void ReportingService::Initialize() {
Steven Holte971b0592017-10-12 15:28:2645 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holte5576ba82017-03-15 21:26:4346 DCHECK(!upload_scheduler_);
holtea3b24112017-03-14 02:08:2447 log_store()->LoadPersistedUnsentLogs();
48 base::Closure send_next_log_callback = base::Bind(
49 &ReportingService::SendNextLog, self_ptr_factory_.GetWeakPtr());
50 upload_scheduler_.reset(new MetricsUploadScheduler(send_next_log_callback));
51}
52
53void ReportingService::Start() {
Steven Holte971b0592017-10-12 15:28:2654 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:2455 if (reporting_active_)
56 upload_scheduler_->Start();
57}
58
59void ReportingService::Stop() {
Steven Holte971b0592017-10-12 15:28:2660 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:2461 if (upload_scheduler_)
62 upload_scheduler_->Stop();
63}
64
65void ReportingService::EnableReporting() {
Steven Holte971b0592017-10-12 15:28:2666 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:2467 if (reporting_active_)
68 return;
69 reporting_active_ = true;
70 Start();
71}
72
73void ReportingService::DisableReporting() {
Steven Holte971b0592017-10-12 15:28:2674 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:2475 reporting_active_ = false;
76 Stop();
77}
78
79bool ReportingService::reporting_active() const {
Steven Holte971b0592017-10-12 15:28:2680 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:2481 return reporting_active_;
82}
83
rajendrantdce70a02018-10-12 06:24:2484void ReportingService::UpdateMetricsUsagePrefs(int message_size,
85 bool is_cellular,
86 bool is_metrics_service_usage) {
Steven Holte971b0592017-10-12 15:28:2687 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:2488 if (data_use_tracker_) {
rajendrantdce70a02018-10-12 06:24:2489 data_use_tracker_->UpdateMetricsUsagePrefs(message_size, is_cellular,
90 is_metrics_service_usage);
holtea3b24112017-03-14 02:08:2491 }
92}
93
94//------------------------------------------------------------------------------
95// private methods
96//------------------------------------------------------------------------------
97
98void ReportingService::SendNextLog() {
99 DVLOG(1) << "SendNextLog";
Steven Holte971b0592017-10-12 15:28:26100 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
Alexei Svitkineb9c826012018-10-13 00:19:26101
Alexei Svitkine01f7205e2018-11-01 23:45:04102 const base::TimeTicks now = base::TimeTicks::Now();
Alexei Svitkineb9c826012018-10-13 00:19:26103 LogActualUploadInterval(last_upload_finish_time_.is_null()
104 ? base::TimeDelta()
Alexei Svitkine01f7205e2018-11-01 23:45:04105 : now - last_upload_finish_time_);
106 last_upload_finish_time_ = now;
Alexei Svitkineb9c826012018-10-13 00:19:26107
holtea3b24112017-03-14 02:08:24108 if (!reporting_active()) {
109 upload_scheduler_->StopAndUploadCancelled();
110 return;
111 }
112 if (!log_store()->has_unsent_logs()) {
113 // Should only get here if serializing the log failed somehow.
114 upload_scheduler_->Stop();
115 // Reset backoff interval
116 upload_scheduler_->UploadFinished(true);
117 return;
118 }
Steven Holte72428db2017-10-13 19:47:22119 if (!log_store()->has_staged_log()) {
120 reporting_info_.set_attempt_count(0);
holtea3b24112017-03-14 02:08:24121 log_store()->StageNextLog();
Steven Holte72428db2017-10-13 19:47:22122 }
holtea3b24112017-03-14 02:08:24123
124 // Proceed to stage the log for upload if log size satisfies cellular log
125 // upload constrains.
126 bool upload_canceled = false;
127 bool is_cellular_logic = client_->IsUMACellularUploadLogicEnabled();
128 if (is_cellular_logic && data_use_tracker_ &&
129 !data_use_tracker_->ShouldUploadLogOnCellular(
130 log_store()->staged_log_hash().size())) {
131 upload_scheduler_->UploadOverDataUsageCap();
132 upload_canceled = true;
133 } else {
134 SendStagedLog();
135 }
136 if (is_cellular_logic) {
137 LogCellularConstraint(upload_canceled);
138 }
139}
140
141void ReportingService::SendStagedLog() {
Steven Holte971b0592017-10-12 15:28:26142 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:24143 DCHECK(log_store()->has_staged_log());
144 if (!log_store()->has_staged_log())
145 return;
146
147 DCHECK(!log_upload_in_progress_);
148 log_upload_in_progress_ = true;
149
150 if (!log_uploader_) {
151 log_uploader_ = client_->CreateUploader(
Carlos IL75b352f2017-11-07 01:43:02152 GetUploadUrl(), GetInsecureUploadUrl(), upload_mime_type(),
153 service_type(),
holtea3b24112017-03-14 02:08:24154 base::Bind(&ReportingService::OnLogUploadComplete,
155 self_ptr_factory_.GetWeakPtr()));
156 }
157
Steven Holte72428db2017-10-13 19:47:22158 reporting_info_.set_attempt_count(reporting_info_.attempt_count() + 1);
159
holtea3b24112017-03-14 02:08:24160 const std::string hash =
161 base::HexEncode(log_store()->staged_log_hash().data(),
162 log_store()->staged_log_hash().size());
Steven Holte72428db2017-10-13 19:47:22163 log_uploader_->UploadLog(log_store()->staged_log(), hash, reporting_info_);
holtea3b24112017-03-14 02:08:24164}
165
Carlos IL75b352f2017-11-07 01:43:02166void ReportingService::OnLogUploadComplete(int response_code,
167 int error_code,
168 bool was_https) {
holtea3b24112017-03-14 02:08:24169 DVLOG(1) << "OnLogUploadComplete:" << response_code;
Steven Holte971b0592017-10-12 15:28:26170 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
holtea3b24112017-03-14 02:08:24171 DCHECK(log_upload_in_progress_);
172 log_upload_in_progress_ = false;
173
Steven Holte72428db2017-10-13 19:47:22174 reporting_info_.set_last_response_code(response_code);
Carlos IL75b352f2017-11-07 01:43:02175 reporting_info_.set_last_error_code(error_code);
176 reporting_info_.set_last_attempt_was_https(was_https);
Steven Holte72428db2017-10-13 19:47:22177
holtea3b24112017-03-14 02:08:24178 // Log a histogram to track response success vs. failure rates.
Carlos ILe3fe868a2017-11-07 23:56:38179 LogResponseOrErrorCode(response_code, error_code, was_https);
holtea3b24112017-03-14 02:08:24180
181 bool upload_succeeded = response_code == 200;
182
holte77d815b2017-03-27 21:27:37183 // Staged log could have been removed already (such as by Purge() in some
184 // implementations), otherwise we may remove it here.
185 if (log_store()->has_staged_log()) {
186 // Provide boolean for error recovery (allow us to ignore response_code).
187 bool discard_log = false;
188 const size_t log_size = log_store()->staged_log().length();
189 if (upload_succeeded) {
190 LogSuccess(log_size);
191 } else if (log_size > max_retransmit_size_) {
192 LogLargeRejection(log_size);
193 discard_log = true;
194 } else if (response_code == 400) {
195 // Bad syntax. Retransmission won't work.
196 discard_log = true;
197 }
holtea3b24112017-03-14 02:08:24198
holte77d815b2017-03-27 21:27:37199 if (upload_succeeded || discard_log) {
200 log_store()->DiscardStagedLog();
201 // Store the updated list to disk now that the removed log is uploaded.
202 log_store()->PersistUnsentLogs();
203 }
holtea3b24112017-03-14 02:08:24204 }
205
206 // Error 400 indicates a problem with the log, not with the server, so
207 // don't consider that a sign that the server is in trouble.
208 bool server_is_healthy = upload_succeeded || response_code == 400;
Carlos IL75b352f2017-11-07 01:43:02209
holtea3b24112017-03-14 02:08:24210 if (!log_store()->has_unsent_logs()) {
211 DVLOG(1) << "Stopping upload_scheduler_.";
212 upload_scheduler_->Stop();
213 }
214 upload_scheduler_->UploadFinished(server_is_healthy);
215}
216
217} // namespace metrics