blob: a17c9a7df03cd338776aa4d3a716981f11a238bc [file] [log] [blame]
// Copyright 2014 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/feedback/feedback_uploader.h"
#include <stdint.h>
#include "base/callback.h"
#include "base/command_line.h"
#include "components/feedback/feedback_report.h"
#include "components/feedback/feedback_switches.h"
namespace feedback {
namespace {
constexpr char kFeedbackPostUrl[] =
"https://www.google.com/tools/feedback/chrome/__submit";
constexpr base::FilePath::CharType kFeedbackReportPath[] =
FILE_PATH_LITERAL("Feedback Reports");
// The minimum time to wait before uploading reports are retried. Exponential
// backoff delay is applied on successive failures.
// This value can be overriden by tests by calling
// FeedbackUploader::SetMinimumRetryDelayForTesting().
base::TimeDelta g_minimum_retry_delay = base::TimeDelta::FromMinutes(60);
GURL GetFeedbackPostGURL() {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
return GURL(command_line.HasSwitch(switches::kFeedbackServer)
? command_line.GetSwitchValueASCII(switches::kFeedbackServer)
: kFeedbackPostUrl);
}
} // namespace
FeedbackUploader::FeedbackUploader(
const base::FilePath& path,
scoped_refptr<base::SingleThreadTaskRunner> task_runner)
: feedback_reports_path_(path.Append(kFeedbackReportPath)),
task_runner_(task_runner),
retry_delay_(g_minimum_retry_delay),
feedback_post_url_(GetFeedbackPostGURL()) {
DCHECK(task_runner_);
}
FeedbackUploader::~FeedbackUploader() {}
// static
void FeedbackUploader::SetMinimumRetryDelayForTesting(base::TimeDelta delay) {
g_minimum_retry_delay = delay;
}
void FeedbackUploader::QueueReport(const std::string& data) {
QueueReportWithDelay(data, base::TimeDelta());
}
void FeedbackUploader::OnReportUploadSuccess() {
retry_delay_ = g_minimum_retry_delay;
UpdateUploadTimer();
}
void FeedbackUploader::OnReportUploadFailure(
scoped_refptr<FeedbackReport> report) {
// Implement a backoff delay by doubling the retry delay on each failure.
retry_delay_ *= 2;
report->set_upload_at(retry_delay_ + base::Time::Now());
reports_queue_.emplace(report);
UpdateUploadTimer();
}
bool FeedbackUploader::ReportsUploadTimeComparator::operator()(
const scoped_refptr<FeedbackReport>& a,
const scoped_refptr<FeedbackReport>& b) const {
return a->upload_at() > b->upload_at();
}
void FeedbackUploader::UpdateUploadTimer() {
if (reports_queue_.empty())
return;
scoped_refptr<FeedbackReport> report = reports_queue_.top();
const base::Time now = base::Time::Now();
if (report->upload_at() <= now) {
reports_queue_.pop();
DispatchReport(report);
report->DeleteReportOnDisk();
} else {
// Stop the old timer and start an updated one.
upload_timer_.Stop();
upload_timer_.Start(
FROM_HERE, report->upload_at() - now, this,
&FeedbackUploader::UpdateUploadTimer);
}
}
void FeedbackUploader::QueueReportWithDelay(const std::string& data,
base::TimeDelta delay) {
reports_queue_.emplace(base::MakeRefCounted<FeedbackReport>(
feedback_reports_path_, base::Time::Now() + delay, data, task_runner_));
UpdateUploadTimer();
}
} // namespace feedback