| // 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. | 
 |  | 
 | #include "components/metrics/metrics_upload_scheduler.h" | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include "base/feature_list.h" | 
 | #include "base/metrics/field_trial_params.h" | 
 | #include "base/metrics/histogram_macros.h" | 
 | #include "base/strings/string_number_conversions.h" | 
 | #include "build/build_config.h" | 
 | #include "components/metrics/metrics_scheduler.h" | 
 |  | 
 | namespace metrics { | 
 |  | 
 | namespace { | 
 |  | 
 | // When uploading metrics to the server fails, we progressively wait longer and | 
 | // longer before sending the next log. This backoff process helps reduce load | 
 | // on a server that is having issues. | 
 | // The following is the multiplier we use to expand that inter-log duration. | 
 | const double kBackoffMultiplier = 2; | 
 |  | 
 | // The maximum backoff interval in hours. | 
 | const int kMaxBackoffIntervalHours = 24; | 
 |  | 
 | // Minutes to wait if we are unable to upload due to data usage cap. | 
 | const int kOverDataUsageIntervalMinutes = 5; | 
 |  | 
 | // Increases the upload interval each time it's called, to handle the case | 
 | // where the server is having issues. | 
 | base::TimeDelta BackOffUploadInterval(base::TimeDelta interval) { | 
 |   DCHECK_GT(kBackoffMultiplier, 1.0); | 
 |   interval = base::TimeDelta::FromMicroseconds(static_cast<int64_t>( | 
 |       kBackoffMultiplier * interval.InMicroseconds())); | 
 |  | 
 |   base::TimeDelta max_interval = | 
 |       base::TimeDelta::FromHours(kMaxBackoffIntervalHours); | 
 |   if (interval > max_interval || interval.InSeconds() < 0) { | 
 |     interval = max_interval; | 
 |   } | 
 |   return interval; | 
 | } | 
 |  | 
 | // Time delay after a log is uploaded successfully before attempting another. | 
 | // On mobile, keeping the radio on is very expensive, so prefer to keep this | 
 | // short and send in bursts. | 
 | base::TimeDelta GetUnsentLogsInterval() { | 
 |   return base::TimeDelta::FromSeconds(3); | 
 | } | 
 |  | 
 | // Initial time delay after a log uploaded fails before retrying it. | 
 | base::TimeDelta GetInitialBackoffInterval() { | 
 |   return base::TimeDelta::FromMinutes(5); | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | MetricsUploadScheduler::MetricsUploadScheduler( | 
 |     const base::RepeatingClosure& upload_callback, | 
 |     bool fast_startup_for_testing) | 
 |     : MetricsScheduler(upload_callback, fast_startup_for_testing), | 
 |       unsent_logs_interval_(GetUnsentLogsInterval()), | 
 |       initial_backoff_interval_(GetInitialBackoffInterval()), | 
 |       backoff_interval_(initial_backoff_interval_) {} | 
 |  | 
 | MetricsUploadScheduler::~MetricsUploadScheduler() {} | 
 |  | 
 | void MetricsUploadScheduler::UploadFinished(bool server_is_healthy) { | 
 |   // If the server is having issues, back off. Otherwise, reset to default | 
 |   // (unless there are more logs to send, in which case the next upload should | 
 |   // happen sooner). | 
 |   if (!server_is_healthy) { | 
 |     TaskDone(backoff_interval_); | 
 |     backoff_interval_ = BackOffUploadInterval(backoff_interval_); | 
 |   } else { | 
 |     backoff_interval_ = initial_backoff_interval_; | 
 |     TaskDone(unsent_logs_interval_); | 
 |   } | 
 | } | 
 |  | 
 | void MetricsUploadScheduler::StopAndUploadCancelled() { | 
 |   Stop(); | 
 |   TaskDone(unsent_logs_interval_); | 
 | } | 
 |  | 
 | void MetricsUploadScheduler::UploadOverDataUsageCap() { | 
 |   TaskDone(base::TimeDelta::FromMinutes(kOverDataUsageIntervalMinutes)); | 
 | } | 
 |  | 
 | }  // namespace metrics |