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