| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/android/offline_pages/background_loader_offliner.h" | 5 #include "chrome/browser/android/offline_pages/background_loader_offliner.h" |
| 6 | 6 |
| 7 #include "base/bind.h" |
| 7 #include "base/json/json_writer.h" | 8 #include "base/json/json_writer.h" |
| 8 #include "base/metrics/histogram_macros.h" | 9 #include "base/metrics/histogram_macros.h" |
| 9 #include "base/sys_info.h" | 10 #include "base/sys_info.h" |
| 11 #include "base/threading/thread_task_runner_handle.h" |
| 10 #include "base/time/time.h" | 12 #include "base/time/time.h" |
| 11 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" | 13 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" |
| 12 #include "chrome/browser/android/offline_pages/offliner_helper.h" | 14 #include "chrome/browser/android/offline_pages/offliner_helper.h" |
| 13 #include "chrome/browser/profiles/profile.h" | 15 #include "chrome/browser/profiles/profile.h" |
| 14 #include "components/offline_pages/core/background/offliner_policy.h" | 16 #include "components/offline_pages/core/background/offliner_policy.h" |
| 15 #include "components/offline_pages/core/background/save_page_request.h" | 17 #include "components/offline_pages/core/background/save_page_request.h" |
| 16 #include "components/offline_pages/core/client_namespace_constants.h" | 18 #include "components/offline_pages/core/client_namespace_constants.h" |
| 17 #include "components/offline_pages/core/offline_page_feature.h" | 19 #include "components/offline_pages/core/offline_page_feature.h" |
| 18 #include "components/offline_pages/core/offline_page_model.h" | 20 #include "components/offline_pages/core/offline_page_model.h" |
| 19 #include "content/public/browser/browser_context.h" | 21 #include "content/public/browser/browser_context.h" |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 adjusted_histogram_name += "." + client_id.name_space; | 67 adjusted_histogram_name += "." + client_id.name_space; |
| 66 return adjusted_histogram_name; | 68 return adjusted_histogram_name; |
| 67 } | 69 } |
| 68 | 70 |
| 69 void RecordErrorCauseUMA(const ClientId& client_id, net::Error error_code) { | 71 void RecordErrorCauseUMA(const ClientId& client_id, net::Error error_code) { |
| 70 UMA_HISTOGRAM_SPARSE_SLOWLY( | 72 UMA_HISTOGRAM_SPARSE_SLOWLY( |
| 71 AddHistogramSuffix(client_id, | 73 AddHistogramSuffix(client_id, |
| 72 "OfflinePages.Background.BackgroundLoadingFailedCode"), | 74 "OfflinePages.Background.BackgroundLoadingFailedCode"), |
| 73 std::abs(error_code)); | 75 std::abs(error_code)); |
| 74 } | 76 } |
| 77 |
| 78 void HandleApplicationStateChangeCancel( |
| 79 const Offliner::CompletionCallback& completion_callback, |
| 80 const SavePageRequest& canceled_request) { |
| 81 completion_callback.Run(canceled_request, |
| 82 Offliner::RequestStatus::FOREGROUND_CANCELED); |
| 83 } |
| 75 } // namespace | 84 } // namespace |
| 76 | 85 |
| 77 BackgroundLoaderOffliner::BackgroundLoaderOffliner( | 86 BackgroundLoaderOffliner::BackgroundLoaderOffliner( |
| 78 content::BrowserContext* browser_context, | 87 content::BrowserContext* browser_context, |
| 79 const OfflinerPolicy* policy, | 88 const OfflinerPolicy* policy, |
| 80 OfflinePageModel* offline_page_model) | 89 OfflinePageModel* offline_page_model) |
| 81 : browser_context_(browser_context), | 90 : browser_context_(browser_context), |
| 82 offline_page_model_(offline_page_model), | 91 offline_page_model_(offline_page_model), |
| 83 policy_(policy), | 92 policy_(policy), |
| 84 is_low_end_device_(base::SysInfo::IsLowEndDevice()), | 93 is_low_end_device_(base::SysInfo::IsLowEndDevice()), |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 // Load page attempt. | 191 // Load page attempt. |
| 183 loader_.get()->LoadPage(request.url()); | 192 loader_.get()->LoadPage(request.url()); |
| 184 | 193 |
| 185 snapshot_controller_.reset( | 194 snapshot_controller_.reset( |
| 186 new SnapshotController(base::ThreadTaskRunnerHandle::Get(), this, | 195 new SnapshotController(base::ThreadTaskRunnerHandle::Get(), this, |
| 187 kOfflineDomContentLoadedMs, page_delay_ms_)); | 196 kOfflineDomContentLoadedMs, page_delay_ms_)); |
| 188 | 197 |
| 189 return true; | 198 return true; |
| 190 } | 199 } |
| 191 | 200 |
| 192 void BackgroundLoaderOffliner::Cancel(const CancelCallback& callback) { | 201 bool BackgroundLoaderOffliner::Cancel(const CancelCallback& callback) { |
| 202 DCHECK(pending_request_); |
| 203 // We ignore the case where pending_request_ is not set, but given the checks |
| 204 // in RequestCoordinator this should not happen. |
| 205 if (!pending_request_) |
| 206 return false; |
| 207 |
| 193 // TODO(chili): We are not able to cancel a pending | 208 // TODO(chili): We are not able to cancel a pending |
| 194 // OfflinePageModel::SaveSnapshot() operation. We will notify caller that | 209 // OfflinePageModel::SaveSnapshot() operation. We will notify caller that |
| 195 // cancel completed once the SavePage operation returns. | 210 // cancel completed once the SavePage operation returns. |
| 196 if (!pending_request_) { | |
| 197 callback.Run(0LL); | |
| 198 return; | |
| 199 } | |
| 200 | |
| 201 if (save_state_ != NONE) { | 211 if (save_state_ != NONE) { |
| 202 save_state_ = DELETE_AFTER_SAVE; | 212 save_state_ = DELETE_AFTER_SAVE; |
| 203 cancel_callback_ = callback; | 213 cancel_callback_ = callback; |
| 204 return; | 214 return true; |
| 205 } | 215 } |
| 206 | 216 |
| 207 int64_t request_id = pending_request_->request_id(); | 217 // Post the cancel callback right after this call concludes. |
| 218 base::ThreadTaskRunnerHandle::Get()->PostTask( |
| 219 FROM_HERE, base::Bind(callback, *pending_request_.get())); |
| 208 ResetState(); | 220 ResetState(); |
| 209 callback.Run(request_id); | 221 return true; |
| 210 } | 222 } |
| 211 | 223 |
| 212 bool BackgroundLoaderOffliner::HandleTimeout(const SavePageRequest& request) { | 224 bool BackgroundLoaderOffliner::HandleTimeout(int64_t request_id) { |
| 213 if (pending_request_) { | 225 if (pending_request_) { |
| 214 DCHECK(request.request_id() == pending_request_->request_id()); | 226 DCHECK(request_id == pending_request_->request_id()); |
| 215 if (is_low_bar_met_ && | 227 if (is_low_bar_met_ && (pending_request_->started_attempt_count() + 1 >= |
| 216 (request.started_attempt_count() + 1 >= policy_->GetMaxStartedTries() || | 228 policy_->GetMaxStartedTries() || |
| 217 request.completed_attempt_count() + 1 >= | 229 pending_request_->completed_attempt_count() + 1 >= |
| 218 policy_->GetMaxCompletedTries())) { | 230 policy_->GetMaxCompletedTries())) { |
| 219 // If we are already in the middle of a save operation, let it finish | 231 // If we are already in the middle of a save operation, let it finish |
| 220 // but do not return SAVED_ON_LAST_RETRY | 232 // but do not return SAVED_ON_LAST_RETRY |
| 221 if (save_state_ == NONE) { | 233 if (save_state_ == NONE) { |
| 222 did_snapshot_on_last_retry_ = true; | 234 did_snapshot_on_last_retry_ = true; |
| 223 StartSnapshot(); | 235 StartSnapshot(); |
| 224 } | 236 } |
| 225 return true; | 237 return true; |
| 226 } | 238 } |
| 227 } | 239 } |
| 228 return false; | 240 return false; |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 int64_t offline_id) { | 407 int64_t offline_id) { |
| 396 if (!pending_request_) | 408 if (!pending_request_) |
| 397 return; | 409 return; |
| 398 | 410 |
| 399 SavePageRequest request(*pending_request_.get()); | 411 SavePageRequest request(*pending_request_.get()); |
| 400 bool did_snapshot_on_last_retry = did_snapshot_on_last_retry_; | 412 bool did_snapshot_on_last_retry = did_snapshot_on_last_retry_; |
| 401 ResetState(); | 413 ResetState(); |
| 402 | 414 |
| 403 if (save_state_ == DELETE_AFTER_SAVE) { | 415 if (save_state_ == DELETE_AFTER_SAVE) { |
| 404 save_state_ = NONE; | 416 save_state_ = NONE; |
| 405 cancel_callback_.Run(request.request_id()); | 417 cancel_callback_.Run(request); |
| 406 return; | 418 return; |
| 407 } | 419 } |
| 408 | 420 |
| 409 save_state_ = NONE; | 421 save_state_ = NONE; |
| 410 | 422 |
| 411 Offliner::RequestStatus save_status; | 423 Offliner::RequestStatus save_status; |
| 412 if (save_result == SavePageResult::SUCCESS) { | 424 if (save_result == SavePageResult::SUCCESS) { |
| 413 if (did_snapshot_on_last_retry) | 425 if (did_snapshot_on_last_retry) |
| 414 save_status = RequestStatus::SAVED_ON_LAST_RETRY; | 426 save_status = RequestStatus::SAVED_ON_LAST_RETRY; |
| 415 else | 427 else |
| (...skipping 23 matching lines...) Expand all Loading... |
| 439 content::WebContentsObserver::Observe(contents); | 451 content::WebContentsObserver::Observe(contents); |
| 440 OfflinerData::AddToWebContents(contents, this); | 452 OfflinerData::AddToWebContents(contents, this); |
| 441 } | 453 } |
| 442 | 454 |
| 443 void BackgroundLoaderOffliner::OnApplicationStateChange( | 455 void BackgroundLoaderOffliner::OnApplicationStateChange( |
| 444 base::android::ApplicationState application_state) { | 456 base::android::ApplicationState application_state) { |
| 445 if (pending_request_ && is_low_end_device_ && | 457 if (pending_request_ && is_low_end_device_ && |
| 446 application_state == | 458 application_state == |
| 447 base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) { | 459 base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) { |
| 448 DVLOG(1) << "App became active, canceling current offlining request"; | 460 DVLOG(1) << "App became active, canceling current offlining request"; |
| 449 SavePageRequest* request = pending_request_.get(); | 461 // No need to check the return value or complete early, as false would |
| 450 // This works because Bind will make a copy of request, and we | 462 // indicate that there was no request, in which case the state change is |
| 451 // should not have to worry about reset being called before cancel callback. | 463 // ignored. |
| 452 Cancel(base::Bind( | 464 Cancel( |
| 453 &BackgroundLoaderOffliner::HandleApplicationStateChangeCancel, | 465 base::Bind(HandleApplicationStateChangeCancel, completion_callback_)); |
| 454 weak_ptr_factory_.GetWeakPtr(), *request)); | |
| 455 } | 466 } |
| 456 } | 467 } |
| 457 | 468 |
| 458 void BackgroundLoaderOffliner::HandleApplicationStateChangeCancel( | |
| 459 const SavePageRequest& request, | |
| 460 int64_t offline_id) { | |
| 461 // If for some reason the request was reset during while waiting for callback | |
| 462 // ignore the completion callback. | |
| 463 if (pending_request_ && pending_request_->request_id() != offline_id) | |
| 464 return; | |
| 465 completion_callback_.Run(request, RequestStatus::FOREGROUND_CANCELED); | |
| 466 } | |
| 467 | |
| 468 void BackgroundLoaderOffliner::AddLoadingSignal(const char* signal_name) { | 469 void BackgroundLoaderOffliner::AddLoadingSignal(const char* signal_name) { |
| 469 base::TimeTicks current_time = base::TimeTicks::Now(); | 470 base::TimeTicks current_time = base::TimeTicks::Now(); |
| 470 base::TimeDelta delay_so_far = current_time - load_start_time_; | 471 base::TimeDelta delay_so_far = current_time - load_start_time_; |
| 471 // We would prefer to use int64_t here, but JSON does not support that type. | 472 // We would prefer to use int64_t here, but JSON does not support that type. |
| 472 // Given the choice between int and double, we choose to implicitly convert to | 473 // Given the choice between int and double, we choose to implicitly convert to |
| 473 // a double since it maintains more precision (we can get a longer time in | 474 // a double since it maintains more precision (we can get a longer time in |
| 474 // milliseconds than we can with a 2 bit int, 53 bits vs 32). | 475 // milliseconds than we can with a 2 bit int, 53 bits vs 32). |
| 475 double delay = delay_so_far.InMilliseconds(); | 476 double delay = delay_so_far.InMilliseconds(); |
| 476 signal_data_.SetDouble(signal_name, delay); | 477 signal_data_.SetDouble(signal_name, delay); |
| 477 } | 478 } |
| 478 | 479 |
| 479 } // namespace offline_pages | 480 } // namespace offline_pages |
| 480 | 481 |
| 481 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::OfflinerData); | 482 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::OfflinerData); |
| OLD | NEW |