| OLD | NEW |
| (Empty) | |
| 1 // 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" |
| 11 #include "base/memory/ptr_util.h" |
| 12 #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 |
| 19 namespace metrics { |
| 20 |
| 21 // static |
| 22 void ReportingService::RegisterPrefs(PrefRegistrySimple* registry) { |
| 23 DataUseTracker::RegisterPrefs(registry); |
| 24 } |
| 25 |
| 26 ReportingService::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) { |
| 35 DCHECK(thread_checker_.CalledOnValidThread()); |
| 36 DCHECK(client_); |
| 37 DCHECK(local_state); |
| 38 } |
| 39 |
| 40 ReportingService::~ReportingService() { |
| 41 DisableReporting(); |
| 42 } |
| 43 |
| 44 void ReportingService::Initialize() { |
| 45 DCHECK(thread_checker_.CalledOnValidThread()); |
| 46 log_store()->LoadPersistedUnsentLogs(); |
| 47 base::Closure send_next_log_callback = base::Bind( |
| 48 &ReportingService::SendNextLog, self_ptr_factory_.GetWeakPtr()); |
| 49 upload_scheduler_.reset(new MetricsUploadScheduler(send_next_log_callback)); |
| 50 } |
| 51 |
| 52 void ReportingService::Start() { |
| 53 DCHECK(thread_checker_.CalledOnValidThread()); |
| 54 if (reporting_active_) |
| 55 upload_scheduler_->Start(); |
| 56 } |
| 57 |
| 58 void ReportingService::Stop() { |
| 59 DCHECK(thread_checker_.CalledOnValidThread()); |
| 60 if (upload_scheduler_) |
| 61 upload_scheduler_->Stop(); |
| 62 } |
| 63 |
| 64 void ReportingService::EnableReporting() { |
| 65 DCHECK(thread_checker_.CalledOnValidThread()); |
| 66 if (reporting_active_) |
| 67 return; |
| 68 reporting_active_ = true; |
| 69 Start(); |
| 70 } |
| 71 |
| 72 void ReportingService::DisableReporting() { |
| 73 DCHECK(thread_checker_.CalledOnValidThread()); |
| 74 reporting_active_ = false; |
| 75 Stop(); |
| 76 } |
| 77 |
| 78 bool ReportingService::reporting_active() const { |
| 79 DCHECK(thread_checker_.CalledOnValidThread()); |
| 80 return reporting_active_; |
| 81 } |
| 82 |
| 83 void ReportingService::UpdateMetricsUsagePrefs(const std::string& service_name, |
| 84 int message_size, |
| 85 bool is_cellular) { |
| 86 DCHECK(thread_checker_.CalledOnValidThread()); |
| 87 if (data_use_tracker_) { |
| 88 data_use_tracker_->UpdateMetricsUsagePrefs(service_name, message_size, |
| 89 is_cellular); |
| 90 } |
| 91 } |
| 92 |
| 93 //------------------------------------------------------------------------------ |
| 94 // private methods |
| 95 //------------------------------------------------------------------------------ |
| 96 |
| 97 void ReportingService::SendNextLog() { |
| 98 DVLOG(1) << "SendNextLog"; |
| 99 DCHECK(thread_checker_.CalledOnValidThread()); |
| 100 if (!last_upload_finish_time_.is_null()) { |
| 101 LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_); |
| 102 last_upload_finish_time_ = base::TimeTicks(); |
| 103 } |
| 104 if (!reporting_active()) { |
| 105 upload_scheduler_->StopAndUploadCancelled(); |
| 106 return; |
| 107 } |
| 108 if (!log_store()->has_unsent_logs()) { |
| 109 // Should only get here if serializing the log failed somehow. |
| 110 upload_scheduler_->Stop(); |
| 111 // Reset backoff interval |
| 112 upload_scheduler_->UploadFinished(true); |
| 113 return; |
| 114 } |
| 115 if (!log_store()->has_staged_log()) |
| 116 log_store()->StageNextLog(); |
| 117 |
| 118 // Proceed to stage the log for upload if log size satisfies cellular log |
| 119 // upload constrains. |
| 120 bool upload_canceled = false; |
| 121 bool is_cellular_logic = client_->IsUMACellularUploadLogicEnabled(); |
| 122 if (is_cellular_logic && data_use_tracker_ && |
| 123 !data_use_tracker_->ShouldUploadLogOnCellular( |
| 124 log_store()->staged_log_hash().size())) { |
| 125 upload_scheduler_->UploadOverDataUsageCap(); |
| 126 upload_canceled = true; |
| 127 } else { |
| 128 SendStagedLog(); |
| 129 } |
| 130 if (is_cellular_logic) { |
| 131 LogCellularConstraint(upload_canceled); |
| 132 } |
| 133 } |
| 134 |
| 135 void ReportingService::SendStagedLog() { |
| 136 DCHECK(thread_checker_.CalledOnValidThread()); |
| 137 DCHECK(log_store()->has_staged_log()); |
| 138 if (!log_store()->has_staged_log()) |
| 139 return; |
| 140 |
| 141 DCHECK(!log_upload_in_progress_); |
| 142 log_upload_in_progress_ = true; |
| 143 |
| 144 if (!log_uploader_) { |
| 145 log_uploader_ = client_->CreateUploader( |
| 146 GetUploadUrl(), upload_mime_type(), service_type(), |
| 147 base::Bind(&ReportingService::OnLogUploadComplete, |
| 148 self_ptr_factory_.GetWeakPtr())); |
| 149 } |
| 150 |
| 151 const std::string hash = |
| 152 base::HexEncode(log_store()->staged_log_hash().data(), |
| 153 log_store()->staged_log_hash().size()); |
| 154 log_uploader_->UploadLog(log_store()->staged_log(), hash); |
| 155 } |
| 156 |
| 157 void ReportingService::OnLogUploadComplete(int response_code) { |
| 158 DVLOG(1) << "OnLogUploadComplete:" << response_code; |
| 159 DCHECK(thread_checker_.CalledOnValidThread()); |
| 160 DCHECK(log_upload_in_progress_); |
| 161 log_upload_in_progress_ = false; |
| 162 |
| 163 // Log a histogram to track response success vs. failure rates. |
| 164 LogResponseCode(response_code); |
| 165 |
| 166 bool upload_succeeded = response_code == 200; |
| 167 |
| 168 // Provide boolean for error recovery (allow us to ignore response_code). |
| 169 bool discard_log = false; |
| 170 const size_t log_size = log_store()->staged_log().length(); |
| 171 if (upload_succeeded) { |
| 172 LogSuccess(log_size); |
| 173 } else if (log_size > max_retransmit_size_) { |
| 174 LogLargeRejection(log_size); |
| 175 discard_log = true; |
| 176 } else if (response_code == 400) { |
| 177 // Bad syntax. Retransmission won't work. |
| 178 discard_log = true; |
| 179 } |
| 180 |
| 181 if (upload_succeeded || discard_log) { |
| 182 log_store()->DiscardStagedLog(); |
| 183 // Store the updated list to disk now that the removed log is uploaded. |
| 184 log_store()->PersistUnsentLogs(); |
| 185 } |
| 186 |
| 187 // Error 400 indicates a problem with the log, not with the server, so |
| 188 // don't consider that a sign that the server is in trouble. |
| 189 bool server_is_healthy = upload_succeeded || response_code == 400; |
| 190 if (!log_store()->has_unsent_logs()) { |
| 191 DVLOG(1) << "Stopping upload_scheduler_."; |
| 192 upload_scheduler_->Stop(); |
| 193 } |
| 194 upload_scheduler_->UploadFinished(server_is_healthy); |
| 195 } |
| 196 |
| 197 } // namespace metrics |
| OLD | NEW |