| 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/metrics/histogram_macros.h" | 7 #include "base/metrics/histogram_macros.h" |
| 8 #include "base/sys_info.h" | 8 #include "base/sys_info.h" |
| 9 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" | 9 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" |
| 10 #include "chrome/browser/android/offline_pages/offliner_helper.h" | 10 #include "chrome/browser/android/offline_pages/offliner_helper.h" |
| 11 #include "chrome/browser/profiles/profile.h" | 11 #include "chrome/browser/profiles/profile.h" |
| 12 #include "components/offline_pages/core/background/save_page_request.h" | 12 #include "components/offline_pages/core/background/save_page_request.h" |
| 13 #include "components/offline_pages/core/client_namespace_constants.h" | 13 #include "components/offline_pages/core/client_namespace_constants.h" |
| 14 #include "components/offline_pages/core/offline_page_model.h" | 14 #include "components/offline_pages/core/offline_page_model.h" |
| 15 #include "content/public/browser/browser_context.h" | 15 #include "content/public/browser/browser_context.h" |
| 16 #include "content/public/browser/navigation_handle.h" | 16 #include "content/public/browser/navigation_handle.h" |
| 17 #include "content/public/browser/web_contents.h" | 17 #include "content/public/browser/web_contents.h" |
| 18 #include "content/public/browser/web_contents_user_data.h" |
| 18 | 19 |
| 19 namespace offline_pages { | 20 namespace offline_pages { |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 long kOfflinePageDelayMs = 2000; | 23 const long kOfflinePageDelayMs = 2000; |
| 24 |
| 25 class OfflinerData : public content::WebContentsUserData<OfflinerData> { |
| 26 public: |
| 27 static void AddToWebContents(content::WebContents* webcontents, |
| 28 BackgroundLoaderOffliner* offliner) { |
| 29 DCHECK(offliner); |
| 30 webcontents->SetUserData(UserDataKey(), std::unique_ptr<OfflinerData>( |
| 31 new OfflinerData(offliner))); |
| 32 } |
| 33 |
| 34 explicit OfflinerData(BackgroundLoaderOffliner* offliner) { |
| 35 offliner_ = offliner; |
| 36 } |
| 37 BackgroundLoaderOffliner* offliner() { return offliner_; } |
| 38 |
| 39 private: |
| 40 // The offliner that the WebContents is attached to. The offliner owns the |
| 41 // Delegate which owns the WebContents that this data is attached to. |
| 42 // Therefore, its lifetime should exceed that of the WebContents, so this |
| 43 // should always be non-null. |
| 44 BackgroundLoaderOffliner* offliner_; |
| 45 }; |
| 46 |
| 23 } // namespace | 47 } // namespace |
| 24 | 48 |
| 25 BackgroundLoaderOffliner::BackgroundLoaderOffliner( | 49 BackgroundLoaderOffliner::BackgroundLoaderOffliner( |
| 26 content::BrowserContext* browser_context, | 50 content::BrowserContext* browser_context, |
| 27 const OfflinerPolicy* policy, | 51 const OfflinerPolicy* policy, |
| 28 OfflinePageModel* offline_page_model) | 52 OfflinePageModel* offline_page_model) |
| 29 : browser_context_(browser_context), | 53 : browser_context_(browser_context), |
| 30 offline_page_model_(offline_page_model), | 54 offline_page_model_(offline_page_model), |
| 31 is_low_end_device_(base::SysInfo::IsLowEndDevice()), | 55 is_low_end_device_(base::SysInfo::IsLowEndDevice()), |
| 32 save_state_(NONE), | 56 save_state_(NONE), |
| 33 page_load_state_(SUCCESS), | 57 page_load_state_(SUCCESS), |
| 34 page_delay_ms_(kOfflinePageDelayMs), | 58 page_delay_ms_(kOfflinePageDelayMs), |
| 59 network_bytes_(0LL), |
| 35 weak_ptr_factory_(this) { | 60 weak_ptr_factory_(this) { |
| 36 DCHECK(offline_page_model_); | 61 DCHECK(offline_page_model_); |
| 37 DCHECK(browser_context_); | 62 DCHECK(browser_context_); |
| 38 } | 63 } |
| 39 | 64 |
| 40 BackgroundLoaderOffliner::~BackgroundLoaderOffliner() {} | 65 BackgroundLoaderOffliner::~BackgroundLoaderOffliner() {} |
| 41 | 66 |
| 42 // TODO(dimich): Invoke progress_callback as appropriate. | 67 // static |
| 68 BackgroundLoaderOffliner* BackgroundLoaderOffliner::FromWebContents( |
| 69 content::WebContents* contents) { |
| 70 OfflinerData* data = OfflinerData::FromWebContents(contents); |
| 71 if (data) |
| 72 return data->offliner(); |
| 73 return nullptr; |
| 74 } |
| 75 |
| 43 bool BackgroundLoaderOffliner::LoadAndSave( | 76 bool BackgroundLoaderOffliner::LoadAndSave( |
| 44 const SavePageRequest& request, | 77 const SavePageRequest& request, |
| 45 const CompletionCallback& completion_callback, | 78 const CompletionCallback& completion_callback, |
| 46 const ProgressCallback& progress_callback) { | 79 const ProgressCallback& progress_callback) { |
| 47 DCHECK(completion_callback); | 80 DCHECK(completion_callback); |
| 48 DCHECK(progress_callback); | 81 DCHECK(progress_callback); |
| 49 | 82 |
| 50 if (pending_request_) { | 83 if (pending_request_) { |
| 51 DVLOG(1) << "Already have pending request"; | 84 DVLOG(1) << "Already have pending request"; |
| 52 return false; | 85 return false; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 | 135 |
| 103 if (!loader_) | 136 if (!loader_) |
| 104 ResetState(); | 137 ResetState(); |
| 105 | 138 |
| 106 // Invalidate ptrs for all delayed/saving tasks. | 139 // Invalidate ptrs for all delayed/saving tasks. |
| 107 weak_ptr_factory_.InvalidateWeakPtrs(); | 140 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 108 | 141 |
| 109 // Track copy of pending request. | 142 // Track copy of pending request. |
| 110 pending_request_.reset(new SavePageRequest(request)); | 143 pending_request_.reset(new SavePageRequest(request)); |
| 111 completion_callback_ = completion_callback; | 144 completion_callback_ = completion_callback; |
| 145 progress_callback_ = progress_callback; |
| 112 | 146 |
| 113 // Listen for app foreground/background change. | 147 // Listen for app foreground/background change. |
| 114 app_listener_.reset(new base::android::ApplicationStatusListener( | 148 app_listener_.reset(new base::android::ApplicationStatusListener( |
| 115 base::Bind(&BackgroundLoaderOffliner::OnApplicationStateChange, | 149 base::Bind(&BackgroundLoaderOffliner::OnApplicationStateChange, |
| 116 weak_ptr_factory_.GetWeakPtr()))); | 150 weak_ptr_factory_.GetWeakPtr()))); |
| 117 | 151 |
| 118 // Load page attempt. | 152 // Load page attempt. |
| 119 loader_.get()->LoadPage(request.url()); | 153 loader_.get()->LoadPage(request.url()); |
| 120 | 154 |
| 121 return true; | 155 return true; |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 238 // - pushState/replaceState | 272 // - pushState/replaceState |
| 239 // - same page history navigation | 273 // - same page history navigation |
| 240 if (navigation_handle->HasCommitted() && !navigation_handle->IsSamePage()) | 274 if (navigation_handle->HasCommitted() && !navigation_handle->IsSamePage()) |
| 241 weak_ptr_factory_.InvalidateWeakPtrs(); | 275 weak_ptr_factory_.InvalidateWeakPtrs(); |
| 242 } | 276 } |
| 243 | 277 |
| 244 void BackgroundLoaderOffliner::SetPageDelayForTest(long delay_ms) { | 278 void BackgroundLoaderOffliner::SetPageDelayForTest(long delay_ms) { |
| 245 page_delay_ms_ = delay_ms; | 279 page_delay_ms_ = delay_ms; |
| 246 } | 280 } |
| 247 | 281 |
| 282 void BackgroundLoaderOffliner::OnNetworkBytesChanged(int64_t bytes) { |
| 283 if (pending_request_ && save_state_ != SAVING) { |
| 284 network_bytes_ += bytes; |
| 285 progress_callback_.Run(*pending_request_, network_bytes_); |
| 286 } |
| 287 } |
| 288 |
| 248 void BackgroundLoaderOffliner::SavePage() { | 289 void BackgroundLoaderOffliner::SavePage() { |
| 249 if (!pending_request_.get()) { | 290 if (!pending_request_.get()) { |
| 250 DVLOG(1) << "Pending request was cleared during delay."; | 291 DVLOG(1) << "Pending request was cleared during delay."; |
| 251 return; | 292 return; |
| 252 } | 293 } |
| 253 | 294 |
| 254 SavePageRequest request(*pending_request_.get()); | 295 SavePageRequest request(*pending_request_.get()); |
| 255 // If there was an error navigating to page, return loading failed. | 296 // If there was an error navigating to page, return loading failed. |
| 256 if (page_load_state_ != SUCCESS) { | 297 if (page_load_state_ != SUCCESS) { |
| 257 Offliner::RequestStatus status = | 298 Offliner::RequestStatus status = |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 310 save_status = RequestStatus::SAVED; | 351 save_status = RequestStatus::SAVED; |
| 311 else | 352 else |
| 312 save_status = RequestStatus::SAVE_FAILED; | 353 save_status = RequestStatus::SAVE_FAILED; |
| 313 | 354 |
| 314 completion_callback_.Run(request, save_status); | 355 completion_callback_.Run(request, save_status); |
| 315 } | 356 } |
| 316 | 357 |
| 317 void BackgroundLoaderOffliner::ResetState() { | 358 void BackgroundLoaderOffliner::ResetState() { |
| 318 pending_request_.reset(); | 359 pending_request_.reset(); |
| 319 page_load_state_ = SUCCESS; | 360 page_load_state_ = SUCCESS; |
| 361 network_bytes_ = 0LL; |
| 320 // TODO(chili): Remove after RequestCoordinator can handle multiple offliners. | 362 // TODO(chili): Remove after RequestCoordinator can handle multiple offliners. |
| 321 // We reset the loader and observer after completion so loaders | 363 // We reset the loader and observer after completion so loaders |
| 322 // will not be re-used across different requests/tries. This is a temporary | 364 // will not be re-used across different requests/tries. This is a temporary |
| 323 // solution while there exists assumptions about the number of offliners | 365 // solution while there exists assumptions about the number of offliners |
| 324 // there are. | 366 // there are. |
| 325 loader_.reset( | 367 loader_.reset( |
| 326 new background_loader::BackgroundLoaderContents(browser_context_)); | 368 new background_loader::BackgroundLoaderContents(browser_context_)); |
| 327 content::WebContentsObserver::Observe(loader_.get()->web_contents()); | 369 content::WebContents* contents = loader_->web_contents(); |
| 370 content::WebContentsObserver::Observe(contents); |
| 371 OfflinerData::AddToWebContents(contents, this); |
| 328 } | 372 } |
| 329 | 373 |
| 330 void BackgroundLoaderOffliner::OnApplicationStateChange( | 374 void BackgroundLoaderOffliner::OnApplicationStateChange( |
| 331 base::android::ApplicationState application_state) { | 375 base::android::ApplicationState application_state) { |
| 332 if (pending_request_ && is_low_end_device_ && | 376 if (pending_request_ && is_low_end_device_ && |
| 333 application_state == | 377 application_state == |
| 334 base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) { | 378 base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) { |
| 335 DVLOG(1) << "App became active, canceling current offlining request"; | 379 DVLOG(1) << "App became active, canceling current offlining request"; |
| 336 SavePageRequest* request = pending_request_.get(); | 380 SavePageRequest* request = pending_request_.get(); |
| 337 // This works because Bind will make a copy of request, and we | 381 // This works because Bind will make a copy of request, and we |
| 338 // should not have to worry about reset being called before cancel callback. | 382 // should not have to worry about reset being called before cancel callback. |
| 339 Cancel(base::Bind( | 383 Cancel(base::Bind( |
| 340 &BackgroundLoaderOffliner::HandleApplicationStateChangeCancel, | 384 &BackgroundLoaderOffliner::HandleApplicationStateChangeCancel, |
| 341 weak_ptr_factory_.GetWeakPtr(), *request)); | 385 weak_ptr_factory_.GetWeakPtr(), *request)); |
| 342 } | 386 } |
| 343 } | 387 } |
| 344 | 388 |
| 345 void BackgroundLoaderOffliner::HandleApplicationStateChangeCancel( | 389 void BackgroundLoaderOffliner::HandleApplicationStateChangeCancel( |
| 346 const SavePageRequest& request, | 390 const SavePageRequest& request, |
| 347 int64_t offline_id) { | 391 int64_t offline_id) { |
| 348 // If for some reason the request was reset during while waiting for callback | 392 // If for some reason the request was reset during while waiting for callback |
| 349 // ignore the completion callback. | 393 // ignore the completion callback. |
| 350 if (pending_request_ && pending_request_->request_id() != offline_id) | 394 if (pending_request_ && pending_request_->request_id() != offline_id) |
| 351 return; | 395 return; |
| 352 completion_callback_.Run(request, RequestStatus::FOREGROUND_CANCELED); | 396 completion_callback_.Run(request, RequestStatus::FOREGROUND_CANCELED); |
| 353 } | 397 } |
| 354 } // namespace offline_pages | 398 } // namespace offline_pages |
| 399 |
| 400 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::OfflinerData); |
| OLD | NEW |