Avi Drissman | 9f7c8d7 | 2022-09-13 19:22:36 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 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 | |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 7 | #include "base/command_line.h" |
Avi Drissman | 90f8642 | 2023-01-11 09:16:09 | [diff] [blame] | 8 | #include "base/functional/bind.h" |
| 9 | #include "base/functional/callback.h" |
xiangdong kong | 12ec048 | 2021-12-17 00:06:44 | [diff] [blame] | 10 | #include "base/metrics/histogram_macros.h" |
Sean Maher | 365bbe9 | 2023-01-09 21:42:28 | [diff] [blame] | 11 | #include "base/task/single_thread_task_runner.h" |
Sylvain Defresne | ae05fd8 | 2021-02-22 11:23:37 | [diff] [blame] | 12 | #include "base/task/task_traits.h" |
| 13 | #include "base/task/thread_pool.h" |
Anton Swifton | d7e6292 | 2022-10-21 21:42:40 | [diff] [blame] | 14 | #include "components/feedback/features.h" |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 15 | #include "components/feedback/feedback_report.h" |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 16 | #include "components/feedback/feedback_switches.h" |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 17 | #include "components/variations/net/variations_http_headers.h" |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 18 | #include "net/base/load_flags.h" |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 19 | #include "services/network/public/cpp/resource_request.h" |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 20 | #include "services/network/public/cpp/simple_url_loader.h" |
Matt Menke | 24bc799 | 2021-07-17 20:30:00 | [diff] [blame] | 21 | #include "services/network/public/mojom/url_response_head.mojom.h" |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 22 | |
| 23 | namespace feedback { |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 24 | |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 25 | namespace { |
| 26 | |
xiangdong kong | 12ec048 | 2021-12-17 00:06:44 | [diff] [blame] | 27 | constexpr char kReportSendingResultHistogramName[] = |
| 28 | "Feedback.ReportSending.Result"; |
| 29 | // These values are persisted to logs. Entries should not be renumbered and |
| 30 | // numeric values should never be reused. |
| 31 | enum class FeedbackReportSendingResult { |
| 32 | kSuccessAtFirstTry = 0, // The report was uploaded successfully without retry |
| 33 | kSuccessAfterRetry = 1, // The report was uploaded successfully after retry |
| 34 | kDropped = 2, // The report is corrupt or invalid and was dropped |
| 35 | kMaxValue = kDropped, |
| 36 | }; |
| 37 | |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 38 | constexpr base::FilePath::CharType kFeedbackReportPath[] = |
| 39 | FILE_PATH_LITERAL("Feedback Reports"); |
| 40 | |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 41 | constexpr char kFeedbackPostUrl[] = |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 42 | "https://www.google.com/tools/feedback/chrome/__submit"; |
| 43 | |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 44 | constexpr char kProtoBufMimeType[] = "application/x-protobuf"; |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 45 | |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 46 | constexpr int kHttpPostSuccessNoContent = 204; |
| 47 | constexpr int kHttpPostFailNoConnection = -1; |
| 48 | constexpr int kHttpPostFailClientError = 400; |
| 49 | constexpr int kHttpPostFailServerError = 500; |
| 50 | |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 51 | // The minimum time to wait before uploading reports are retried. Exponential |
| 52 | // backoff delay is applied on successive failures. |
| 53 | // This value can be overriden by tests by calling |
| 54 | // FeedbackUploader::SetMinimumRetryDelayForTesting(). |
Peter Kasting | 9dbb793 | 2021-10-02 03:06:35 | [diff] [blame] | 55 | base::TimeDelta g_minimum_retry_delay = base::Minutes(60); |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 56 | |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 57 | // If a new report is queued to be dispatched immediately while another is being |
| 58 | // dispatched, this is the time to wait for the on-going dispatching to finish. |
Peter Kasting | 9dbb793 | 2021-10-02 03:06:35 | [diff] [blame] | 59 | base::TimeDelta g_dispatching_wait_delay = base::Seconds(4); |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 60 | |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 61 | GURL GetFeedbackPostGURL() { |
| 62 | const base::CommandLine& command_line = |
| 63 | *base::CommandLine::ForCurrentProcess(); |
| 64 | return GURL(command_line.HasSwitch(switches::kFeedbackServer) |
| 65 | ? command_line.GetSwitchValueASCII(switches::kFeedbackServer) |
| 66 | : kFeedbackPostUrl); |
| 67 | } |
| 68 | |
Sylvain Defresne | ae05fd8 | 2021-02-22 11:23:37 | [diff] [blame] | 69 | // Creates a new SingleThreadTaskRunner that is used to run feedback blocking |
| 70 | // background work. |
| 71 | scoped_refptr<base::SingleThreadTaskRunner> CreateUploaderTaskRunner() { |
| 72 | // Uses a BLOCK_SHUTDOWN file task runner to prevent losing reports or |
| 73 | // corrupting report's files. |
| 74 | return base::ThreadPool::CreateSingleThreadTaskRunner( |
| 75 | {base::MayBlock(), base::TaskPriority::BEST_EFFORT, |
| 76 | base::TaskShutdownBehavior::BLOCK_SHUTDOWN}); |
| 77 | } |
| 78 | |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 79 | } // namespace |
| 80 | |
Sylvain Defresne | 444aaea | 2021-02-23 09:37:39 | [diff] [blame] | 81 | FeedbackUploader::FeedbackUploader( |
| 82 | bool is_off_the_record, |
| 83 | const base::FilePath& state_path, |
| 84 | SharedURLLoaderFactoryGetter shared_url_loader_factory_getter) |
| 85 | : FeedbackUploader(is_off_the_record, |
| 86 | state_path, |
| 87 | std::move(shared_url_loader_factory_getter), |
| 88 | nullptr) {} |
| 89 | |
| 90 | FeedbackUploader::FeedbackUploader( |
| 91 | bool is_off_the_record, |
| 92 | const base::FilePath& state_path, |
| 93 | scoped_refptr<network::SharedURLLoaderFactory> shared_url_loader_factory) |
| 94 | : FeedbackUploader(is_off_the_record, |
| 95 | state_path, |
| 96 | SharedURLLoaderFactoryGetter(), |
| 97 | shared_url_loader_factory) {} |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 98 | |
Sorin Jianu | 221a3b3 | 2024-10-09 17:56:06 | [diff] [blame] | 99 | FeedbackUploader::~FeedbackUploader() = default; |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 100 | |
| 101 | // static |
| 102 | void FeedbackUploader::SetMinimumRetryDelayForTesting(base::TimeDelta delay) { |
| 103 | g_minimum_retry_delay = delay; |
| 104 | } |
| 105 | |
Miriam Zimmerman | f6a61aa | 2020-08-06 01:10:01 | [diff] [blame] | 106 | void FeedbackUploader::QueueReport(std::unique_ptr<std::string> data, |
Darren Shen | 9221ba5 | 2024-01-08 03:23:11 | [diff] [blame] | 107 | bool has_email, |
| 108 | int product_id) { |
Jeffrey Kardatzke | f7e1c95 | 2019-08-29 19:38:30 | [diff] [blame] | 109 | reports_queue_.emplace(base::MakeRefCounted<FeedbackReport>( |
Miriam Zimmerman | f6a61aa | 2020-08-06 01:10:01 | [diff] [blame] | 110 | feedback_reports_path_, base::Time::Now(), std::move(data), task_runner_, |
Darren Shen | 9221ba5 | 2024-01-08 03:23:11 | [diff] [blame] | 111 | has_email, product_id)); |
Jeffrey Kardatzke | f7e1c95 | 2019-08-29 19:38:30 | [diff] [blame] | 112 | UpdateUploadTimer(); |
| 113 | } |
| 114 | |
| 115 | void FeedbackUploader::RequeueReport(scoped_refptr<FeedbackReport> report) { |
| 116 | DCHECK_EQ(task_runner_, report->reports_task_runner()); |
| 117 | report->set_upload_at(base::Time::Now()); |
| 118 | reports_queue_.emplace(std::move(report)); |
| 119 | UpdateUploadTimer(); |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 120 | } |
| 121 | |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 122 | void FeedbackUploader::StartDispatchingReport() { |
| 123 | DispatchReport(); |
| 124 | } |
| 125 | |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 126 | void FeedbackUploader::OnReportUploadSuccess() { |
xiangdong kong | 12ec048 | 2021-12-17 00:06:44 | [diff] [blame] | 127 | if (retry_delay_ == g_minimum_retry_delay) { |
| 128 | UMA_HISTOGRAM_ENUMERATION(kReportSendingResultHistogramName, |
| 129 | FeedbackReportSendingResult::kSuccessAtFirstTry); |
| 130 | } else { |
| 131 | UMA_HISTOGRAM_ENUMERATION(kReportSendingResultHistogramName, |
| 132 | FeedbackReportSendingResult::kSuccessAfterRetry); |
| 133 | } |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 134 | retry_delay_ = g_minimum_retry_delay; |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 135 | is_dispatching_ = false; |
| 136 | // Explicitly release the successfully dispatched report. |
Ahmed Fakhry | eea11db | 2018-06-14 03:22:02 | [diff] [blame] | 137 | report_being_dispatched_->DeleteReportOnDisk(); |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 138 | report_being_dispatched_ = nullptr; |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 139 | UpdateUploadTimer(); |
| 140 | } |
| 141 | |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 142 | void FeedbackUploader::OnReportUploadFailure(bool should_retry) { |
| 143 | if (should_retry) { |
| 144 | // Implement a backoff delay by doubling the retry delay on each failure. |
| 145 | retry_delay_ *= 2; |
| 146 | report_being_dispatched_->set_upload_at(retry_delay_ + base::Time::Now()); |
| 147 | reports_queue_.emplace(report_being_dispatched_); |
Ahmed Fakhry | eea11db | 2018-06-14 03:22:02 | [diff] [blame] | 148 | } else { |
| 149 | // The report won't be retried, hence explicitly delete its file on disk. |
| 150 | report_being_dispatched_->DeleteReportOnDisk(); |
xiangdong kong | 12ec048 | 2021-12-17 00:06:44 | [diff] [blame] | 151 | UMA_HISTOGRAM_ENUMERATION(kReportSendingResultHistogramName, |
| 152 | FeedbackReportSendingResult::kDropped); |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 153 | } |
| 154 | |
| 155 | // The report dispatching failed, and should either be retried or not. In all |
| 156 | // cases, we need to release |report_being_dispatched_|. If it was up for |
| 157 | // retry, then it has already been re-enqueued and will be kept alive. |
| 158 | // Otherwise we're done with it and it should destruct. |
| 159 | report_being_dispatched_ = nullptr; |
| 160 | is_dispatching_ = false; |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 161 | UpdateUploadTimer(); |
| 162 | } |
| 163 | |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 164 | bool FeedbackUploader::ReportsUploadTimeComparator::operator()( |
dcheng | cf57b44 | 2014-09-04 04:22:38 | [diff] [blame] | 165 | const scoped_refptr<FeedbackReport>& a, |
| 166 | const scoped_refptr<FeedbackReport>& b) const { |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 167 | return a->upload_at() > b->upload_at(); |
| 168 | } |
| 169 | |
Sylvain Defresne | 444aaea | 2021-02-23 09:37:39 | [diff] [blame] | 170 | FeedbackUploader::FeedbackUploader( |
| 171 | bool is_off_the_record, |
| 172 | const base::FilePath& state_path, |
| 173 | SharedURLLoaderFactoryGetter url_loader_factory_getter, |
| 174 | scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) |
| 175 | : url_loader_factory_getter_(std::move(url_loader_factory_getter)), |
| 176 | url_loader_factory_(url_loader_factory), |
| 177 | feedback_reports_path_(state_path.Append(kFeedbackReportPath)), |
| 178 | task_runner_(CreateUploaderTaskRunner()), |
| 179 | feedback_post_url_(GetFeedbackPostGURL()), |
| 180 | retry_delay_(g_minimum_retry_delay), |
| 181 | is_off_the_record_(is_off_the_record) { |
| 182 | DCHECK(!!url_loader_factory_getter_ != !!url_loader_factory_); |
| 183 | } |
| 184 | |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 185 | void FeedbackUploader::AppendExtraHeadersToUploadRequest( |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 186 | network::ResourceRequest* resource_request) {} |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 187 | |
| 188 | void FeedbackUploader::DispatchReport() { |
| 189 | net::NetworkTrafficAnnotationTag traffic_annotation = |
| 190 | net::DefineNetworkTrafficAnnotation("chrome_feedback_report_app", R"( |
| 191 | semantics { |
| 192 | sender: "Chrome Feedback Report App" |
| 193 | description: |
| 194 | "Users can press Alt+Shift+i to report a bug or a feedback in " |
| 195 | "general. Along with the free-form text they entered, system logs " |
| 196 | "that helps in diagnosis of the issue are sent to Google. This " |
| 197 | "service uploads the report to Google Feedback server." |
| 198 | trigger: |
| 199 | "When user chooses to send a feedback to Google." |
| 200 | data: |
| 201 | "The free-form text that user has entered and useful debugging " |
| 202 | "logs (UI logs, Chrome logs, kernel logs, auto update engine logs, " |
Nicolas Ouellet-Payeur | 72e5171 | 2021-07-14 20:48:59 | [diff] [blame] | 203 | "ARC++ logs, etc.). The logs are redacted to remove any " |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 204 | "user-private data. The user can view the system information " |
| 205 | "before sending, and choose to send the feedback report without " |
| 206 | "system information and the logs (unchecking 'Send system " |
| 207 | "information' prevents sending logs as well), the screenshot, or " |
| 208 | "even his/her email address." |
| 209 | destination: GOOGLE_OWNED_SERVICE |
Aiden Chiavatti | 3586654 | 2023-08-17 20:36:54 | [diff] [blame] | 210 | internal { |
| 211 | contacts { |
Chad Duffin | e779cbe | 2024-10-01 20:53:17 | [diff] [blame] | 212 | email: "[email protected]" |
Aiden Chiavatti | 3586654 | 2023-08-17 20:36:54 | [diff] [blame] | 213 | } |
| 214 | } |
| 215 | user_data { |
| 216 | type: ARBITRARY_DATA |
| 217 | type: EMAIL |
| 218 | type: IMAGE |
| 219 | type: USER_CONTENT |
| 220 | } |
| 221 | last_reviewed: "2023-08-14" |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 222 | } |
| 223 | policy { |
| 224 | cookies_allowed: NO |
| 225 | setting: |
| 226 | "This feature cannot be disabled by settings and is only activated " |
| 227 | "by direct user request." |
Nicolas Ouellet-Payeur | 72e5171 | 2021-07-14 20:48:59 | [diff] [blame] | 228 | chrome_policy { |
| 229 | UserFeedbackAllowed { |
| 230 | UserFeedbackAllowed: false |
| 231 | } |
| 232 | } |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 233 | })"); |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 234 | auto resource_request = std::make_unique<network::ResourceRequest>(); |
| 235 | resource_request->url = feedback_post_url_; |
Yutaka Hirano | d04cfe2 | 2019-07-29 06:41:34 | [diff] [blame] | 236 | resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit; |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 237 | resource_request->method = "POST"; |
| 238 | |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 239 | // Tell feedback server about the variation state of this install. |
Darren Shen | 9221ba5 | 2024-01-08 03:23:11 | [diff] [blame] | 240 | if (report_being_dispatched_->should_include_variations()) { |
| 241 | variations::AppendVariationsHeaderUnknownSignedIn( |
| 242 | feedback_post_url_, |
| 243 | is_off_the_record_ ? variations::InIncognito::kYes |
| 244 | : variations::InIncognito::kNo, |
| 245 | resource_request.get()); |
| 246 | } |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 247 | |
Miriam Zimmerman | f6a61aa | 2020-08-06 01:10:01 | [diff] [blame] | 248 | if (report_being_dispatched_->has_email()) { |
| 249 | AppendExtraHeadersToUploadRequest(resource_request.get()); |
| 250 | } |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 251 | |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 252 | std::unique_ptr<network::SimpleURLLoader> simple_url_loader = |
| 253 | network::SimpleURLLoader::Create(std::move(resource_request), |
| 254 | traffic_annotation); |
| 255 | network::SimpleURLLoader* simple_url_loader_ptr = simple_url_loader.get(); |
| 256 | simple_url_loader->AttachStringForUpload(report_being_dispatched_->data(), |
| 257 | kProtoBufMimeType); |
| 258 | auto it = uploads_in_progress_.insert(uploads_in_progress_.begin(), |
| 259 | std::move(simple_url_loader)); |
Evan Stade | ffd2089 | 2019-10-09 01:15:36 | [diff] [blame] | 260 | |
Evan Stade | ffd2089 | 2019-10-09 01:15:36 | [diff] [blame] | 261 | if (!url_loader_factory_) { |
Sylvain Defresne | 444aaea | 2021-02-23 09:37:39 | [diff] [blame] | 262 | // Lazily create the URLLoaderFactory. |
| 263 | url_loader_factory_ = std::move(url_loader_factory_getter_).Run(); |
| 264 | DCHECK(url_loader_factory_); |
Evan Stade | ffd2089 | 2019-10-09 01:15:36 | [diff] [blame] | 265 | } |
| 266 | |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 267 | simple_url_loader_ptr->DownloadToStringOfUnboundedSizeUntilCrashAndDie( |
| 268 | url_loader_factory_.get(), |
| 269 | base::BindOnce(&FeedbackUploader::OnDispatchComplete, |
| 270 | base::Unretained(this), std::move(it))); |
| 271 | } |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 272 | |
Robbie McElrath | eb1ff13 | 2018-07-09 22:01:02 | [diff] [blame] | 273 | void FeedbackUploader::OnDispatchComplete( |
| 274 | UrlLoaderList::iterator it, |
| 275 | std::unique_ptr<std::string> response_body) { |
| 276 | std::stringstream error_stream; |
| 277 | network::SimpleURLLoader* simple_url_loader = it->get(); |
| 278 | int response_code = kHttpPostFailNoConnection; |
| 279 | if (simple_url_loader->ResponseInfo() && |
| 280 | simple_url_loader->ResponseInfo()->headers) { |
| 281 | response_code = simple_url_loader->ResponseInfo()->headers->response_code(); |
| 282 | } |
| 283 | if (response_code == kHttpPostSuccessNoContent) { |
| 284 | error_stream << "Success"; |
| 285 | OnReportUploadSuccess(); |
| 286 | } else { |
| 287 | bool should_retry = true; |
| 288 | // Process the error for debug output |
| 289 | if (response_code == kHttpPostFailNoConnection) { |
| 290 | error_stream << "No connection to server."; |
| 291 | } else if ((response_code >= kHttpPostFailClientError) && |
| 292 | (response_code < kHttpPostFailServerError)) { |
| 293 | // Client errors mean that the server failed to parse the proto that was |
| 294 | // sent, or that some requirements weren't met by the server side |
| 295 | // validation, and hence we should NOT retry sending this corrupt report |
| 296 | // and give up. |
| 297 | should_retry = false; |
| 298 | |
| 299 | error_stream << "Client error: HTTP response code " << response_code; |
| 300 | } else if (response_code >= kHttpPostFailServerError) { |
| 301 | error_stream << "Server error: HTTP response code " << response_code; |
| 302 | } else { |
| 303 | error_stream << "Unknown error: HTTP response code " << response_code; |
| 304 | } |
| 305 | |
| 306 | OnReportUploadFailure(should_retry); |
| 307 | } |
| 308 | |
| 309 | LOG(WARNING) << "FEEDBACK: Submission to feedback server (" |
| 310 | << simple_url_loader->GetFinalURL() |
| 311 | << ") status: " << error_stream.str(); |
| 312 | uploads_in_progress_.erase(it); |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 313 | } |
| 314 | |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 315 | void FeedbackUploader::UpdateUploadTimer() { |
| 316 | if (reports_queue_.empty()) |
| 317 | return; |
| 318 | |
| 319 | scoped_refptr<FeedbackReport> report = reports_queue_.top(); |
Anton Swifton | d7e6292 | 2022-10-21 21:42:40 | [diff] [blame] | 320 | |
| 321 | // Don't send reports in Tast tests so that they don't spam Listnr. |
| 322 | if (feedback::features::IsSkipSendingFeedbackReportInTastTestsEnabled()) { |
| 323 | report->DeleteReportOnDisk(); |
| 324 | reports_queue_.pop(); |
| 325 | return; |
| 326 | } |
| 327 | |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 328 | const base::Time now = base::Time::Now(); |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 329 | if (report->upload_at() <= now && !is_dispatching_) { |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 330 | reports_queue_.pop(); |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 331 | is_dispatching_ = true; |
| 332 | report_being_dispatched_ = report; |
| 333 | StartDispatchingReport(); |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 334 | } else { |
| 335 | // Stop the old timer and start an updated one. |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 336 | const base::TimeDelta delay = (is_dispatching_ || now > report->upload_at()) |
| 337 | ? g_dispatching_wait_delay |
| 338 | : report->upload_at() - now; |
Ahmed Fakhry | 435b15e | 2017-07-21 21:39:07 | [diff] [blame] | 339 | upload_timer_.Stop(); |
Ahmed Fakhry | b0e32d8 | 2017-08-22 20:11:45 | [diff] [blame] | 340 | upload_timer_.Start(FROM_HERE, delay, this, |
| 341 | &FeedbackUploader::UpdateUploadTimer); |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 342 | } |
| 343 | } |
| 344 | |
[email protected] | 28548b0 | 2014-05-09 02:17:19 | [diff] [blame] | 345 | } // namespace feedback |