| 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/render_frame_host.h" |
| 17 #include "content/public/browser/web_contents.h" | 18 #include "content/public/browser/web_contents.h" |
| 18 #include "content/public/browser/web_contents_user_data.h" | 19 #include "content/public/browser/web_contents_user_data.h" |
| 19 | 20 |
| 20 namespace offline_pages { | 21 namespace offline_pages { |
| 21 | 22 |
| 22 namespace { | 23 namespace { |
| 23 const long kOfflinePageDelayMs = 2000; | 24 const long kOfflinePageDelayMs = 2000; |
| 25 const long kOfflineDomContentLoadedMs = 25000; |
| 24 | 26 |
| 25 class OfflinerData : public content::WebContentsUserData<OfflinerData> { | 27 class OfflinerData : public content::WebContentsUserData<OfflinerData> { |
| 26 public: | 28 public: |
| 27 static void AddToWebContents(content::WebContents* webcontents, | 29 static void AddToWebContents(content::WebContents* webcontents, |
| 28 BackgroundLoaderOffliner* offliner) { | 30 BackgroundLoaderOffliner* offliner) { |
| 29 DCHECK(offliner); | 31 DCHECK(offliner); |
| 30 webcontents->SetUserData(UserDataKey(), std::unique_ptr<OfflinerData>( | 32 webcontents->SetUserData(UserDataKey(), std::unique_ptr<OfflinerData>( |
| 31 new OfflinerData(offliner))); | 33 new OfflinerData(offliner))); |
| 32 } | 34 } |
| 33 | 35 |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 } | 148 } |
| 147 | 149 |
| 148 if (!OfflinePageModel::CanSaveURL(request.url())) { | 150 if (!OfflinePageModel::CanSaveURL(request.url())) { |
| 149 DVLOG(1) << "Not able to save page for requested url: " << request.url(); | 151 DVLOG(1) << "Not able to save page for requested url: " << request.url(); |
| 150 return false; | 152 return false; |
| 151 } | 153 } |
| 152 | 154 |
| 153 if (!loader_) | 155 if (!loader_) |
| 154 ResetState(); | 156 ResetState(); |
| 155 | 157 |
| 156 // Invalidate ptrs for all delayed/saving tasks. | |
| 157 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 158 | |
| 159 // Track copy of pending request. | 158 // Track copy of pending request. |
| 160 pending_request_.reset(new SavePageRequest(request)); | 159 pending_request_.reset(new SavePageRequest(request)); |
| 161 completion_callback_ = completion_callback; | 160 completion_callback_ = completion_callback; |
| 162 progress_callback_ = progress_callback; | 161 progress_callback_ = progress_callback; |
| 163 | 162 |
| 164 // Listen for app foreground/background change. | 163 // Listen for app foreground/background change. |
| 165 app_listener_.reset(new base::android::ApplicationStatusListener( | 164 app_listener_.reset(new base::android::ApplicationStatusListener( |
| 166 base::Bind(&BackgroundLoaderOffliner::OnApplicationStateChange, | 165 base::Bind(&BackgroundLoaderOffliner::OnApplicationStateChange, |
| 167 weak_ptr_factory_.GetWeakPtr()))); | 166 weak_ptr_factory_.GetWeakPtr()))); |
| 168 | 167 |
| 169 // Load page attempt. | 168 // Load page attempt. |
| 170 loader_.get()->LoadPage(request.url()); | 169 loader_.get()->LoadPage(request.url()); |
| 171 | 170 |
| 171 snapshot_controller_.reset( |
| 172 new SnapshotController(base::ThreadTaskRunnerHandle::Get(), this, |
| 173 kOfflineDomContentLoadedMs, page_delay_ms_)); |
| 174 |
| 172 return true; | 175 return true; |
| 173 } | 176 } |
| 174 | 177 |
| 175 void BackgroundLoaderOffliner::Cancel(const CancelCallback& callback) { | 178 void BackgroundLoaderOffliner::Cancel(const CancelCallback& callback) { |
| 176 // TODO(chili): We are not able to cancel a pending | 179 // TODO(chili): We are not able to cancel a pending |
| 177 // OfflinePageModel::SavePage() operation. We will notify caller that | 180 // OfflinePageModel::SaveSnapshot() operation. We will notify caller that |
| 178 // cancel completed once the SavePage operation returns. | 181 // cancel completed once the SavePage operation returns. |
| 179 if (!pending_request_) { | 182 if (!pending_request_) { |
| 180 callback.Run(0LL); | 183 callback.Run(0LL); |
| 181 return; | 184 return; |
| 182 } | 185 } |
| 183 | 186 |
| 184 if (save_state_ != NONE) { | 187 if (save_state_ != NONE) { |
| 185 save_state_ = DELETE_AFTER_SAVE; | 188 save_state_ = DELETE_AFTER_SAVE; |
| 186 cancel_callback_ = callback; | 189 cancel_callback_ = callback; |
| 187 return; | 190 return; |
| 188 } | 191 } |
| 189 | 192 |
| 190 int64_t request_id = pending_request_->request_id(); | 193 int64_t request_id = pending_request_->request_id(); |
| 191 ResetState(); | 194 ResetState(); |
| 192 callback.Run(request_id); | 195 callback.Run(request_id); |
| 193 } | 196 } |
| 194 | 197 |
| 195 bool BackgroundLoaderOffliner::HandleTimeout(const SavePageRequest& request) { | 198 bool BackgroundLoaderOffliner::HandleTimeout(const SavePageRequest& request) { |
| 196 // TODO(romax) Decide if we want to also take a snapshot on the last timeout | 199 // TODO(romax) Decide if we want to also take a snapshot on the last timeout |
| 197 // for the background loader offliner. | 200 // for the background loader offliner. |
| 198 return false; | 201 return false; |
| 199 } | 202 } |
| 200 | 203 |
| 204 void BackgroundLoaderOffliner::DocumentLoadedInFrame( |
| 205 content::RenderFrameHost* render_host) { |
| 206 // Inform snapshot controller if in main frame. |
| 207 if (!render_host->GetParent()) |
| 208 snapshot_controller_->DocumentAvailableInMainFrame(); |
| 209 } |
| 210 |
| 201 void BackgroundLoaderOffliner::DidStopLoading() { | 211 void BackgroundLoaderOffliner::DidStopLoading() { |
| 202 if (!pending_request_.get()) { | 212 if (!pending_request_.get()) { |
| 203 DVLOG(1) << "DidStopLoading called even though no pending request."; | 213 DVLOG(1) << "DidStopLoading called even though no pending request."; |
| 204 return; | 214 return; |
| 205 } | 215 } |
| 206 | 216 |
| 207 // Invalidate ptrs for any ongoing save operation. | 217 snapshot_controller_->DocumentOnLoadCompletedInMainFrame(); |
| 208 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 209 | |
| 210 // Post SavePage task with 2 second delay. | |
| 211 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | |
| 212 FROM_HERE, | |
| 213 base::Bind(&BackgroundLoaderOffliner::SavePage, | |
| 214 weak_ptr_factory_.GetWeakPtr()), | |
| 215 base::TimeDelta::FromMilliseconds(page_delay_ms_)); | |
| 216 } | 218 } |
| 217 | 219 |
| 218 void BackgroundLoaderOffliner::RenderProcessGone( | 220 void BackgroundLoaderOffliner::RenderProcessGone( |
| 219 base::TerminationStatus status) { | 221 base::TerminationStatus status) { |
| 220 if (pending_request_) { | 222 if (pending_request_) { |
| 221 SavePageRequest request(*pending_request_.get()); | 223 SavePageRequest request(*pending_request_.get()); |
| 222 switch (status) { | 224 switch (status) { |
| 223 case base::TERMINATION_STATUS_OOM: | 225 case base::TERMINATION_STATUS_OOM: |
| 224 case base::TERMINATION_STATUS_PROCESS_CRASHED: | 226 case base::TERMINATION_STATUS_PROCESS_CRASHED: |
| 225 case base::TERMINATION_STATUS_STILL_RUNNING: | 227 case base::TERMINATION_STATUS_STILL_RUNNING: |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 case net::ERR_UNKNOWN_URL_SCHEME: | 281 case net::ERR_UNKNOWN_URL_SCHEME: |
| 280 page_load_state_ = NONRETRIABLE; | 282 page_load_state_ = NONRETRIABLE; |
| 281 break; | 283 break; |
| 282 case net::ERR_INTERNET_DISCONNECTED: | 284 case net::ERR_INTERNET_DISCONNECTED: |
| 283 page_load_state_ = DELAY_RETRY; | 285 page_load_state_ = DELAY_RETRY; |
| 284 break; | 286 break; |
| 285 default: | 287 default: |
| 286 page_load_state_ = RETRIABLE; | 288 page_load_state_ = RETRIABLE; |
| 287 } | 289 } |
| 288 } | 290 } |
| 289 | |
| 290 // If the document is not the same invalidate any pending save tasks. | |
| 291 // | |
| 292 // Downloads or 204/205 response codes do not commit (no new navigation) | |
| 293 // Same-Document (committed) navigations are: | |
| 294 // - reference fragment navigations | |
| 295 // - pushState/replaceState | |
| 296 // - same document history navigation | |
| 297 if (navigation_handle->HasCommitted() && | |
| 298 !navigation_handle->IsSameDocument()) { | |
| 299 weak_ptr_factory_.InvalidateWeakPtrs(); | |
| 300 } | |
| 301 } | 291 } |
| 302 | 292 |
| 303 void BackgroundLoaderOffliner::SetPageDelayForTest(long delay_ms) { | 293 void BackgroundLoaderOffliner::SetPageDelayForTest(long delay_ms) { |
| 304 page_delay_ms_ = delay_ms; | 294 page_delay_ms_ = delay_ms; |
| 305 } | 295 } |
| 306 | 296 |
| 307 void BackgroundLoaderOffliner::OnNetworkBytesChanged(int64_t bytes) { | 297 void BackgroundLoaderOffliner::OnNetworkBytesChanged(int64_t bytes) { |
| 308 if (pending_request_ && save_state_ != SAVING) { | 298 if (pending_request_ && save_state_ != SAVING) { |
| 309 network_bytes_ += bytes; | 299 network_bytes_ += bytes; |
| 310 progress_callback_.Run(*pending_request_, network_bytes_); | 300 progress_callback_.Run(*pending_request_, network_bytes_); |
| 311 } | 301 } |
| 312 } | 302 } |
| 313 | 303 |
| 314 void BackgroundLoaderOffliner::SavePage() { | 304 void BackgroundLoaderOffliner::StartSnapshot() { |
| 315 if (!pending_request_.get()) { | 305 if (!pending_request_.get()) { |
| 316 DVLOG(1) << "Pending request was cleared during delay."; | 306 DVLOG(1) << "Pending request was cleared during delay."; |
| 317 return; | 307 return; |
| 318 } | 308 } |
| 319 | 309 |
| 320 SavePageRequest request(*pending_request_.get()); | 310 SavePageRequest request(*pending_request_.get()); |
| 321 // If there was an error navigating to page, return loading failed. | 311 // If there was an error navigating to page, return loading failed. |
| 322 if (page_load_state_ != SUCCESS) { | 312 if (page_load_state_ != SUCCESS) { |
| 323 Offliner::RequestStatus status; | 313 Offliner::RequestStatus status; |
| 324 switch (page_load_state_) { | 314 switch (page_load_state_) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 375 SavePageRequest request(*pending_request_.get()); | 365 SavePageRequest request(*pending_request_.get()); |
| 376 ResetState(); | 366 ResetState(); |
| 377 | 367 |
| 378 if (save_state_ == DELETE_AFTER_SAVE) { | 368 if (save_state_ == DELETE_AFTER_SAVE) { |
| 379 save_state_ = NONE; | 369 save_state_ = NONE; |
| 380 cancel_callback_.Run(request.request_id()); | 370 cancel_callback_.Run(request.request_id()); |
| 381 return; | 371 return; |
| 382 } | 372 } |
| 383 | 373 |
| 384 save_state_ = NONE; | 374 save_state_ = NONE; |
| 375 // Prevent snapshot controller from making any more snapshots. |
| 376 snapshot_controller_->Stop(); |
| 385 | 377 |
| 386 Offliner::RequestStatus save_status; | 378 Offliner::RequestStatus save_status; |
| 387 if (save_result == SavePageResult::SUCCESS) | 379 if (save_result == SavePageResult::SUCCESS) |
| 388 save_status = RequestStatus::SAVED; | 380 save_status = RequestStatus::SAVED; |
| 389 else | 381 else |
| 390 save_status = RequestStatus::SAVE_FAILED; | 382 save_status = RequestStatus::SAVE_FAILED; |
| 391 | 383 |
| 392 completion_callback_.Run(request, save_status); | 384 completion_callback_.Run(request, save_status); |
| 393 } | 385 } |
| 394 | 386 |
| 395 void BackgroundLoaderOffliner::ResetState() { | 387 void BackgroundLoaderOffliner::ResetState() { |
| 396 pending_request_.reset(); | 388 pending_request_.reset(); |
| 389 snapshot_controller_.reset(); |
| 397 page_load_state_ = SUCCESS; | 390 page_load_state_ = SUCCESS; |
| 398 network_bytes_ = 0LL; | 391 network_bytes_ = 0LL; |
| 399 // TODO(chili): Remove after RequestCoordinator can handle multiple offliners. | 392 // TODO(chili): Remove after RequestCoordinator can handle multiple offliners. |
| 400 // We reset the loader and observer after completion so loaders | 393 // We reset the loader and observer after completion so loaders |
| 401 // will not be re-used across different requests/tries. This is a temporary | 394 // will not be re-used across different requests/tries. This is a temporary |
| 402 // solution while there exists assumptions about the number of offliners | 395 // solution while there exists assumptions about the number of offliners |
| 403 // there are. | 396 // there are. |
| 404 loader_.reset( | 397 loader_.reset( |
| 405 new background_loader::BackgroundLoaderContents(browser_context_)); | 398 new background_loader::BackgroundLoaderContents(browser_context_)); |
| 406 content::WebContents* contents = loader_->web_contents(); | 399 content::WebContents* contents = loader_->web_contents(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 428 int64_t offline_id) { | 421 int64_t offline_id) { |
| 429 // If for some reason the request was reset during while waiting for callback | 422 // If for some reason the request was reset during while waiting for callback |
| 430 // ignore the completion callback. | 423 // ignore the completion callback. |
| 431 if (pending_request_ && pending_request_->request_id() != offline_id) | 424 if (pending_request_ && pending_request_->request_id() != offline_id) |
| 432 return; | 425 return; |
| 433 completion_callback_.Run(request, RequestStatus::FOREGROUND_CANCELED); | 426 completion_callback_.Run(request, RequestStatus::FOREGROUND_CANCELED); |
| 434 } | 427 } |
| 435 } // namespace offline_pages | 428 } // namespace offline_pages |
| 436 | 429 |
| 437 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::OfflinerData); | 430 DEFINE_WEB_CONTENTS_USER_DATA_KEY(offline_pages::OfflinerData); |
| OLD | NEW |