| Index: components/metrics/reporting_service.cc
|
| diff --git a/components/metrics/reporting_service.cc b/components/metrics/reporting_service.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a541b298be8ffc829b7ba076f429ded46ffb0f29
|
| --- /dev/null
|
| +++ b/components/metrics/reporting_service.cc
|
| @@ -0,0 +1,197 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// ReportingService handles uploading serialized logs to a server.
|
| +
|
| +#include "components/metrics/reporting_service.h"
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/callback.h"
|
| +#include "base/memory/ptr_util.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| +#include "components/metrics/data_use_tracker.h"
|
| +#include "components/metrics/log_store.h"
|
| +#include "components/metrics/metrics_log_uploader.h"
|
| +#include "components/metrics/metrics_service_client.h"
|
| +#include "components/metrics/metrics_upload_scheduler.h"
|
| +
|
| +namespace metrics {
|
| +
|
| +// static
|
| +void ReportingService::RegisterPrefs(PrefRegistrySimple* registry) {
|
| + DataUseTracker::RegisterPrefs(registry);
|
| +}
|
| +
|
| +ReportingService::ReportingService(MetricsServiceClient* client,
|
| + PrefService* local_state,
|
| + size_t max_retransmit_size)
|
| + : client_(client),
|
| + max_retransmit_size_(max_retransmit_size),
|
| + reporting_active_(false),
|
| + log_upload_in_progress_(false),
|
| + data_use_tracker_(DataUseTracker::Create(local_state)),
|
| + self_ptr_factory_(this) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(client_);
|
| + DCHECK(local_state);
|
| +}
|
| +
|
| +ReportingService::~ReportingService() {
|
| + DisableReporting();
|
| +}
|
| +
|
| +void ReportingService::Initialize() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + log_store()->LoadPersistedUnsentLogs();
|
| + base::Closure send_next_log_callback = base::Bind(
|
| + &ReportingService::SendNextLog, self_ptr_factory_.GetWeakPtr());
|
| + upload_scheduler_.reset(new MetricsUploadScheduler(send_next_log_callback));
|
| +}
|
| +
|
| +void ReportingService::Start() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (reporting_active_)
|
| + upload_scheduler_->Start();
|
| +}
|
| +
|
| +void ReportingService::Stop() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (upload_scheduler_)
|
| + upload_scheduler_->Stop();
|
| +}
|
| +
|
| +void ReportingService::EnableReporting() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (reporting_active_)
|
| + return;
|
| + reporting_active_ = true;
|
| + Start();
|
| +}
|
| +
|
| +void ReportingService::DisableReporting() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + reporting_active_ = false;
|
| + Stop();
|
| +}
|
| +
|
| +bool ReportingService::reporting_active() const {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + return reporting_active_;
|
| +}
|
| +
|
| +void ReportingService::UpdateMetricsUsagePrefs(const std::string& service_name,
|
| + int message_size,
|
| + bool is_cellular) {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (data_use_tracker_) {
|
| + data_use_tracker_->UpdateMetricsUsagePrefs(service_name, message_size,
|
| + is_cellular);
|
| + }
|
| +}
|
| +
|
| +//------------------------------------------------------------------------------
|
| +// private methods
|
| +//------------------------------------------------------------------------------
|
| +
|
| +void ReportingService::SendNextLog() {
|
| + DVLOG(1) << "SendNextLog";
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + if (!last_upload_finish_time_.is_null()) {
|
| + LogActualUploadInterval(base::TimeTicks::Now() - last_upload_finish_time_);
|
| + last_upload_finish_time_ = base::TimeTicks();
|
| + }
|
| + if (!reporting_active()) {
|
| + upload_scheduler_->StopAndUploadCancelled();
|
| + return;
|
| + }
|
| + if (!log_store()->has_unsent_logs()) {
|
| + // Should only get here if serializing the log failed somehow.
|
| + upload_scheduler_->Stop();
|
| + // Reset backoff interval
|
| + upload_scheduler_->UploadFinished(true);
|
| + return;
|
| + }
|
| + if (!log_store()->has_staged_log())
|
| + log_store()->StageNextLog();
|
| +
|
| + // Proceed to stage the log for upload if log size satisfies cellular log
|
| + // upload constrains.
|
| + bool upload_canceled = false;
|
| + bool is_cellular_logic = client_->IsUMACellularUploadLogicEnabled();
|
| + if (is_cellular_logic && data_use_tracker_ &&
|
| + !data_use_tracker_->ShouldUploadLogOnCellular(
|
| + log_store()->staged_log_hash().size())) {
|
| + upload_scheduler_->UploadOverDataUsageCap();
|
| + upload_canceled = true;
|
| + } else {
|
| + SendStagedLog();
|
| + }
|
| + if (is_cellular_logic) {
|
| + LogCellularConstraint(upload_canceled);
|
| + }
|
| +}
|
| +
|
| +void ReportingService::SendStagedLog() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(log_store()->has_staged_log());
|
| + if (!log_store()->has_staged_log())
|
| + return;
|
| +
|
| + DCHECK(!log_upload_in_progress_);
|
| + log_upload_in_progress_ = true;
|
| +
|
| + if (!log_uploader_) {
|
| + log_uploader_ = client_->CreateUploader(
|
| + GetUploadUrl(), upload_mime_type(), service_type(),
|
| + base::Bind(&ReportingService::OnLogUploadComplete,
|
| + self_ptr_factory_.GetWeakPtr()));
|
| + }
|
| +
|
| + const std::string hash =
|
| + base::HexEncode(log_store()->staged_log_hash().data(),
|
| + log_store()->staged_log_hash().size());
|
| + log_uploader_->UploadLog(log_store()->staged_log(), hash);
|
| +}
|
| +
|
| +void ReportingService::OnLogUploadComplete(int response_code) {
|
| + DVLOG(1) << "OnLogUploadComplete:" << response_code;
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| + DCHECK(log_upload_in_progress_);
|
| + log_upload_in_progress_ = false;
|
| +
|
| + // Log a histogram to track response success vs. failure rates.
|
| + LogResponseCode(response_code);
|
| +
|
| + bool upload_succeeded = response_code == 200;
|
| +
|
| + // Provide boolean for error recovery (allow us to ignore response_code).
|
| + bool discard_log = false;
|
| + const size_t log_size = log_store()->staged_log().length();
|
| + if (upload_succeeded) {
|
| + LogSuccess(log_size);
|
| + } else if (log_size > max_retransmit_size_) {
|
| + LogLargeRejection(log_size);
|
| + discard_log = true;
|
| + } else if (response_code == 400) {
|
| + // Bad syntax. Retransmission won't work.
|
| + discard_log = true;
|
| + }
|
| +
|
| + if (upload_succeeded || discard_log) {
|
| + log_store()->DiscardStagedLog();
|
| + // Store the updated list to disk now that the removed log is uploaded.
|
| + log_store()->PersistUnsentLogs();
|
| + }
|
| +
|
| + // Error 400 indicates a problem with the log, not with the server, so
|
| + // don't consider that a sign that the server is in trouble.
|
| + bool server_is_healthy = upload_succeeded || response_code == 400;
|
| + if (!log_store()->has_unsent_logs()) {
|
| + DVLOG(1) << "Stopping upload_scheduler_.";
|
| + upload_scheduler_->Stop();
|
| + }
|
| + upload_scheduler_->UploadFinished(server_is_healthy);
|
| +}
|
| +
|
| +} // namespace metrics
|
|
|