Chromium Code Reviews| 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/prerendering_offliner.h" | 5 #include "chrome/browser/android/offline_pages/prerendering_offliner.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/sys_info.h" | |
| 8 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" | 9 #include "chrome/browser/android/offline_pages/offline_page_mhtml_archiver.h" |
| 9 #include "components/offline_pages/background/save_page_request.h" | 10 #include "components/offline_pages/background/save_page_request.h" |
| 10 #include "components/offline_pages/offline_page_model.h" | 11 #include "components/offline_pages/offline_page_model.h" |
| 11 #include "content/public/browser/browser_context.h" | 12 #include "content/public/browser/browser_context.h" |
| 12 #include "content/public/browser/web_contents.h" | 13 #include "content/public/browser/web_contents.h" |
| 13 | 14 |
| 14 namespace offline_pages { | 15 namespace offline_pages { |
| 15 | 16 |
| 16 PrerenderingOffliner::PrerenderingOffliner( | 17 PrerenderingOffliner::PrerenderingOffliner( |
| 17 content::BrowserContext* browser_context, | 18 content::BrowserContext* browser_context, |
| 18 const OfflinerPolicy* policy, | 19 const OfflinerPolicy* policy, |
| 19 OfflinePageModel* offline_page_model) | 20 OfflinePageModel* offline_page_model) |
| 20 : browser_context_(browser_context), | 21 : browser_context_(browser_context), |
| 21 offline_page_model_(offline_page_model), | 22 offline_page_model_(offline_page_model), |
| 22 pending_request_(nullptr), | 23 pending_request_(nullptr), |
| 24 app_listener_(nullptr), | |
| 23 weak_ptr_factory_(this) {} | 25 weak_ptr_factory_(this) {} |
| 24 | 26 |
| 25 PrerenderingOffliner::~PrerenderingOffliner() {} | 27 PrerenderingOffliner::~PrerenderingOffliner() {} |
| 26 | 28 |
| 27 void PrerenderingOffliner::OnLoadPageDone( | 29 void PrerenderingOffliner::OnLoadPageDone( |
| 28 const SavePageRequest& request, | 30 const SavePageRequest& request, |
| 29 const CompletionCallback& completion_callback, | |
| 30 Offliner::RequestStatus load_status, | 31 Offliner::RequestStatus load_status, |
| 31 content::WebContents* web_contents) { | 32 content::WebContents* web_contents) { |
| 32 // Check if request is still pending receiving a callback. | 33 // Check if request is still pending receiving a callback. |
| 33 // Note: it is possible to get a loaded page, start the save operation, | 34 // Note: it is possible to get a loaded page, start the save operation, |
| 34 // and then get another callback from the Loader (eg, if its loaded | 35 // and then get another callback from the Loader (eg, if its loaded |
| 35 // WebContents is being destroyed for some resource reclamation). | 36 // WebContents is being destroyed for some resource reclamation). |
| 36 if (!pending_request_) | 37 if (!pending_request_) |
| 37 return; | 38 return; |
| 38 | 39 |
| 39 // Since we are able to stop/cancel a previous load request, we should | 40 // Since we are able to stop/cancel a previous load request, we should |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 54 std::unique_ptr<OfflinePageArchiver> archiver( | 55 std::unique_ptr<OfflinePageArchiver> archiver( |
| 55 new OfflinePageMHTMLArchiver(web_contents)); | 56 new OfflinePageMHTMLArchiver(web_contents)); |
| 56 // Pass in the URL from the WebContents in case it is redirected from | 57 // Pass in the URL from the WebContents in case it is redirected from |
| 57 // the requested URL. This is to work around a check in the | 58 // the requested URL. This is to work around a check in the |
| 58 // OfflinePageModel implementation that ensures URL passed in here is | 59 // OfflinePageModel implementation that ensures URL passed in here is |
| 59 // same as LastCommittedURL from the snapshot. | 60 // same as LastCommittedURL from the snapshot. |
| 60 // TODO(dougarnett): Raise issue of how to better deal with redirects. | 61 // TODO(dougarnett): Raise issue of how to better deal with redirects. |
| 61 SavePage(web_contents->GetLastCommittedURL(), request.client_id(), | 62 SavePage(web_contents->GetLastCommittedURL(), request.client_id(), |
| 62 std::move(archiver), | 63 std::move(archiver), |
| 63 base::Bind(&PrerenderingOffliner::OnSavePageDone, | 64 base::Bind(&PrerenderingOffliner::OnSavePageDone, |
| 64 weak_ptr_factory_.GetWeakPtr(), request, | 65 weak_ptr_factory_.GetWeakPtr(), request)); |
| 65 completion_callback)); | |
| 66 } else { | 66 } else { |
| 67 // Clear pending request and then run the completion callback. | 67 // Clear pending request and then run its completion callback. |
| 68 pending_request_.reset(nullptr); | 68 pending_request_.reset(nullptr); |
| 69 completion_callback.Run(request, load_status); | 69 app_listener_.reset(nullptr); |
| 70 completion_callback_.Run(request, load_status); | |
| 70 } | 71 } |
| 71 } | 72 } |
| 72 | 73 |
| 73 void PrerenderingOffliner::OnSavePageDone( | 74 void PrerenderingOffliner::OnSavePageDone( |
| 74 const SavePageRequest& request, | 75 const SavePageRequest& request, |
| 75 const CompletionCallback& completion_callback, | |
| 76 SavePageResult save_result, | 76 SavePageResult save_result, |
| 77 int64_t offline_id) { | 77 int64_t offline_id) { |
| 78 // Check if request is still pending receiving a callback. | 78 // Check if request is still pending receiving a callback. |
| 79 if (!pending_request_) | 79 if (!pending_request_) |
| 80 return; | 80 return; |
| 81 | 81 |
| 82 // Also check that save callback is for same request as pending request | 82 // Also check that this completed request is same as the pending one |
| 83 // (since SavePage request is not cancel-able currently and could be old). | 83 // (since SavePage request is not cancel-able currently and could be old). |
| 84 if (request.request_id() != pending_request_->request_id()) { | 84 if (request.request_id() != pending_request_->request_id()) { |
| 85 DVLOG(1) << "Ignoring save callback for old request"; | 85 DVLOG(1) << "Ignoring save callback for old request"; |
| 86 return; | 86 return; |
| 87 } | 87 } |
| 88 | 88 |
| 89 // Clear pending request here and inform loader we are done with WebContents. | 89 // Clear pending request here and inform loader we are done with WebContents. |
| 90 pending_request_.reset(nullptr); | 90 pending_request_.reset(nullptr); |
| 91 app_listener_.reset(nullptr); | |
|
Pete Williamson
2016/07/13 23:17:55
Why do we reset for both SavePage done and LoadPag
dougarnett
2016/07/13 23:44:20
Paired with clearing pending_request_. Only reset
| |
| 91 GetOrCreateLoader()->StopLoading(); | 92 GetOrCreateLoader()->StopLoading(); |
| 92 | 93 |
| 93 // Determine status and run the completion callback. | 94 // Determine status and run the completion callback. |
| 94 Offliner::RequestStatus save_status; | 95 Offliner::RequestStatus save_status; |
| 95 if (save_result == SavePageResult::SUCCESS) { | 96 if (save_result == SavePageResult::SUCCESS) { |
| 96 save_status = RequestStatus::SAVED; | 97 save_status = RequestStatus::SAVED; |
| 97 } else { | 98 } else { |
| 98 // TODO(dougarnett): Consider reflecting some recommendation to retry the | 99 // TODO(dougarnett): Consider reflecting some recommendation to retry the |
| 99 // request based on specific save error cases. | 100 // request based on specific save error cases. |
| 100 save_status = RequestStatus::SAVE_FAILED; | 101 save_status = RequestStatus::SAVE_FAILED; |
| 101 } | 102 } |
| 102 completion_callback.Run(request, save_status); | 103 completion_callback_.Run(request, save_status); |
| 103 } | 104 } |
| 104 | 105 |
| 105 bool PrerenderingOffliner::LoadAndSave(const SavePageRequest& request, | 106 bool PrerenderingOffliner::LoadAndSave(const SavePageRequest& request, |
| 106 const CompletionCallback& callback) { | 107 const CompletionCallback& callback) { |
| 107 if (pending_request_) { | 108 if (pending_request_) { |
| 108 DVLOG(1) << "Already have pending request"; | 109 DVLOG(1) << "Already have pending request"; |
| 109 return false; | 110 return false; |
| 110 } | 111 } |
| 111 | 112 |
| 112 if (!GetOrCreateLoader()->CanPrerender()) { | 113 if (!GetOrCreateLoader()->CanPrerender()) { |
| 113 DVLOG(1) << "Prerendering not allowed/configured"; | 114 DVLOG(1) << "Prerendering not allowed/configured"; |
| 114 return false; | 115 return false; |
| 115 } | 116 } |
| 116 | 117 |
| 117 if (!OfflinePageModel::CanSaveURL(request.url())) { | 118 if (!OfflinePageModel::CanSaveURL(request.url())) { |
| 118 DVLOG(1) << "Not able to save page for requested url: " << request.url(); | 119 DVLOG(1) << "Not able to save page for requested url: " << request.url(); |
| 119 return false; | 120 return false; |
| 120 } | 121 } |
| 121 | 122 |
| 122 // Track copy of pending request for callback handling. | 123 // Track copy of pending request for callback handling. |
| 123 pending_request_.reset(new SavePageRequest(request)); | 124 pending_request_.reset(new SavePageRequest(request)); |
| 125 completion_callback_ = callback; | |
| 124 | 126 |
| 125 // Kick off load page attempt. | 127 // Kick off load page attempt. |
| 126 bool accepted = GetOrCreateLoader()->LoadPage( | 128 bool accepted = GetOrCreateLoader()->LoadPage( |
| 127 request.url(), | 129 request.url(), base::Bind(&PrerenderingOffliner::OnLoadPageDone, |
| 128 base::Bind(&PrerenderingOffliner::OnLoadPageDone, | 130 weak_ptr_factory_.GetWeakPtr(), request)); |
| 129 weak_ptr_factory_.GetWeakPtr(), request, callback)); | 131 if (!accepted) { |
| 130 if (!accepted) | |
| 131 pending_request_.reset(nullptr); | 132 pending_request_.reset(nullptr); |
| 133 } else if (base::SysInfo::IsLowEndDevice()) { | |
| 134 app_listener_.reset(new base::android::ApplicationStatusListener( | |
|
Pete Williamson
2016/07/13 23:17:55
Would it be better to always set up a listener, ev
dougarnett
2016/07/13 23:44:20
Had that originally but didn't come up with any us
Pete Williamson
2016/07/13 23:57:12
I suppose I would be OK with waiting until we need
fgorski
2016/07/14 17:01:45
I second Pete's initial comment.
It is the state c
dougarnett
2016/07/15 16:00:25
Done.
| |
| 135 base::Bind(&PrerenderingOffliner::OnApplicationStateChange, | |
| 136 weak_ptr_factory_.GetWeakPtr()))); | |
| 137 } | |
| 132 | 138 |
| 133 return accepted; | 139 return accepted; |
| 134 } | 140 } |
| 135 | 141 |
| 136 void PrerenderingOffliner::Cancel() { | 142 void PrerenderingOffliner::Cancel() { |
| 137 if (pending_request_) { | 143 if (pending_request_) { |
| 138 pending_request_.reset(nullptr); | 144 pending_request_.reset(nullptr); |
| 145 app_listener_.reset(nullptr); | |
| 139 GetOrCreateLoader()->StopLoading(); | 146 GetOrCreateLoader()->StopLoading(); |
| 140 // TODO(dougarnett): Consider ability to cancel SavePage request. | 147 // TODO(dougarnett): Consider ability to cancel SavePage request. |
| 141 } | 148 } |
| 142 } | 149 } |
| 143 | 150 |
| 144 void PrerenderingOffliner::SetLoaderForTesting( | 151 void PrerenderingOffliner::SetLoaderForTesting( |
| 145 std::unique_ptr<PrerenderingLoader> loader) { | 152 std::unique_ptr<PrerenderingLoader> loader) { |
| 146 DCHECK(!loader_); | 153 DCHECK(!loader_); |
| 147 loader_ = std::move(loader); | 154 loader_ = std::move(loader); |
| 148 } | 155 } |
| 149 | 156 |
| 157 void PrerenderingOffliner::SetApplicationStateForTesting( | |
| 158 base::android::ApplicationState application_state) { | |
| 159 OnApplicationStateChange(application_state); | |
| 160 } | |
| 161 | |
| 150 void PrerenderingOffliner::SavePage( | 162 void PrerenderingOffliner::SavePage( |
| 151 const GURL& url, | 163 const GURL& url, |
| 152 const ClientId& client_id, | 164 const ClientId& client_id, |
| 153 std::unique_ptr<OfflinePageArchiver> archiver, | 165 std::unique_ptr<OfflinePageArchiver> archiver, |
| 154 const SavePageCallback& callback) { | 166 const SavePageCallback& save_callback) { |
| 155 DCHECK(offline_page_model_); | 167 DCHECK(offline_page_model_); |
| 156 offline_page_model_->SavePage(url, client_id, std::move(archiver), callback); | 168 offline_page_model_->SavePage(url, client_id, std::move(archiver), |
| 169 save_callback); | |
| 157 } | 170 } |
| 158 | 171 |
| 159 PrerenderingLoader* PrerenderingOffliner::GetOrCreateLoader() { | 172 PrerenderingLoader* PrerenderingOffliner::GetOrCreateLoader() { |
| 160 if (!loader_) { | 173 if (!loader_) { |
| 161 loader_.reset(new PrerenderingLoader(browser_context_)); | 174 loader_.reset(new PrerenderingLoader(browser_context_)); |
| 162 } | 175 } |
| 163 return loader_.get(); | 176 return loader_.get(); |
| 164 } | 177 } |
| 165 | 178 |
| 179 void PrerenderingOffliner::OnApplicationStateChange( | |
| 180 base::android::ApplicationState application_state) { | |
| 181 if (pending_request_ && base::SysInfo::IsLowEndDevice() && | |
| 182 application_state == | |
| 183 base::android::APPLICATION_STATE_HAS_RUNNING_ACTIVITIES) { | |
| 184 DVLOG(1) << "App became active, canceling current offlining request"; | |
| 185 SavePageRequest* request = pending_request_.get(); | |
| 186 Cancel(); | |
| 187 completion_callback_.Run(*request, | |
| 188 Offliner::RequestStatus::FOREGROUND_CANCELED); | |
| 189 } | |
| 190 } | |
| 191 | |
| 166 } // namespace offline_pages | 192 } // namespace offline_pages |
| OLD | NEW |