1 // Copyright 2014 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 #include "components/feedback/feedback_uploader.h" 6 7 #include "base/callback.h" 8 #include "base/command_line.h" 9 #include "base/files/file_path.h" 10 #include "base/sequenced_task_runner.h" 11 #include "base/task_runner_util.h" 12 #include "base/threading/sequenced_worker_pool.h" 13 #include "components/feedback/feedback_report.h" 14 15 namespace feedback { 16 namespace { 17 18 const char kFeedbackPostUrl[] = 19 "https://www.google.com/tools/feedback/chrome/__submit"; 20 21 const int64 kRetryDelayMinutes = 60; 22 23 const base::FilePath::CharType kFeedbackReportPath[] = 24 FILE_PATH_LITERAL("Feedback Reports"); 25 26 } // namespace 27 28 bool FeedbackUploader::ReportsUploadTimeComparator::operator()( 29 const scoped_refptr<FeedbackReport>& a, 30 const scoped_refptr<FeedbackReport>& b) const { 31 return a->upload_at() > b->upload_at(); 32 } 33 34 FeedbackUploader::FeedbackUploader(const base::FilePath& path, 35 base::SequencedWorkerPool* pool) 36 : report_path_(path.Append(kFeedbackReportPath)), 37 retry_delay_(base::TimeDelta::FromMinutes(kRetryDelayMinutes)), 38 url_(kFeedbackPostUrl), 39 pool_(pool) { 40 Init(); 41 } 42 43 FeedbackUploader::FeedbackUploader(const base::FilePath& path, 44 base::SequencedWorkerPool* pool, 45 const std::string& url) 46 : report_path_(path.Append(kFeedbackReportPath)), 47 retry_delay_(base::TimeDelta::FromMinutes(kRetryDelayMinutes)), 48 url_(url), 49 pool_(pool) { 50 Init(); 51 } 52 53 FeedbackUploader::~FeedbackUploader() {} 54 55 void FeedbackUploader::Init() { 56 dispatch_callback_ = base::Bind(&FeedbackUploader::DispatchReport, 57 AsWeakPtr()); 58 } 59 60 void FeedbackUploader::QueueReport(const std::string& data) { 61 QueueReportWithDelay(data, base::TimeDelta()); 62 } 63 64 void FeedbackUploader::UpdateUploadTimer() { 65 if (reports_queue_.empty()) 66 return; 67 68 scoped_refptr<FeedbackReport> report = reports_queue_.top(); 69 base::Time now = base::Time::Now(); 70 if (report->upload_at() <= now) { 71 reports_queue_.pop(); 72 dispatch_callback_.Run(report->data()); 73 report->DeleteReportOnDisk(); 74 } else { 75 // Stop the old timer and start an updated one. 76 if (upload_timer_.IsRunning()) 77 upload_timer_.Stop(); 78 upload_timer_.Start( 79 FROM_HERE, report->upload_at() - now, this, 80 &FeedbackUploader::UpdateUploadTimer); 81 } 82 } 83 84 void FeedbackUploader::RetryReport(const std::string& data) { 85 QueueReportWithDelay(data, retry_delay_); 86 } 87 88 void FeedbackUploader::QueueReportWithDelay(const std::string& data, 89 base::TimeDelta delay) { 90 // Uses a BLOCK_SHUTDOWN file task runner because we really don't want to 91 // lose reports. 92 scoped_refptr<base::SequencedTaskRunner> task_runner = 93 pool_->GetSequencedTaskRunnerWithShutdownBehavior( 94 pool_->GetSequenceToken(), 95 base::SequencedWorkerPool::BLOCK_SHUTDOWN); 96 97 reports_queue_.push(new FeedbackReport(report_path_, 98 base::Time::Now() + delay, 99 data, 100 task_runner)); 101 UpdateUploadTimer(); 102 } 103 104 void FeedbackUploader::setup_for_test( 105 const ReportDataCallback& dispatch_callback, 106 const base::TimeDelta& retry_delay) { 107 dispatch_callback_ = dispatch_callback; 108 retry_delay_ = retry_delay; 109 } 110 111 } // namespace feedback 112