OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/prerender/prerender_manager.h" | 5 #include "chrome/browser/prerender/prerender_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 #include "content/public/browser/notification_source.h" | 48 #include "content/public/browser/notification_source.h" |
49 #include "content/public/browser/render_process_host.h" | 49 #include "content/public/browser/render_process_host.h" |
50 #include "content/public/browser/render_view_host.h" | 50 #include "content/public/browser/render_view_host.h" |
51 #include "content/public/browser/session_storage_namespace.h" | 51 #include "content/public/browser/session_storage_namespace.h" |
52 #include "content/public/browser/web_contents.h" | 52 #include "content/public/browser/web_contents.h" |
53 #include "content/public/browser/web_contents_delegate.h" | 53 #include "content/public/browser/web_contents_delegate.h" |
54 #include "content/public/browser/web_contents_view.h" | 54 #include "content/public/browser/web_contents_view.h" |
55 | 55 |
56 using content::BrowserThread; | 56 using content::BrowserThread; |
57 using content::RenderViewHost; | 57 using content::RenderViewHost; |
58 using content::SessionStorageNamespace; | 58 using content::SessionStorageNamespaceMap; |
59 using content::WebContents; | 59 using content::WebContents; |
60 | 60 |
61 namespace prerender { | 61 namespace prerender { |
62 | 62 |
63 namespace { | 63 namespace { |
64 | 64 |
65 // Time interval at which periodic cleanups are performed. | 65 // Time interval at which periodic cleanups are performed. |
66 const int kPeriodicCleanupIntervalMs = 1000; | 66 const int kPeriodicCleanupIntervalMs = 1000; |
67 | 67 |
68 // Valid HTTP methods for prerendering. | 68 // Valid HTTP methods for prerendering. |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
201 | 201 |
202 PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender( | 202 PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender( |
203 int process_id, | 203 int process_id, |
204 int route_id, | 204 int route_id, |
205 const GURL& url, | 205 const GURL& url, |
206 const content::Referrer& referrer, | 206 const content::Referrer& referrer, |
207 const gfx::Size& size) { | 207 const gfx::Size& size) { |
208 #if defined(OS_ANDROID) | 208 #if defined(OS_ANDROID) |
209 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable | 209 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable |
210 // link-prerender and enable omnibox-prerender only. | 210 // link-prerender and enable omnibox-prerender only. |
211 return NULL; | 211 return false; |
212 #else | 212 #else |
213 DCHECK(!size.IsEmpty()); | 213 DCHECK(!size.IsEmpty()); |
214 if (PrerenderData* parent_prerender_data = | 214 if (PrerenderData* parent_prerender_data = |
215 FindPrerenderDataForChildAndRoute(process_id, route_id)) { | 215 FindPrerenderDataForChildAndRoute(process_id, route_id)) { |
216 // Instead of prerendering from inside of a running prerender, we will defer | 216 // Instead of prerendering from inside of a running prerender, we will defer |
217 // this request until its launcher is made visible. | 217 // this request until its launcher is made visible. |
218 if (PrerenderContents* contents = parent_prerender_data->contents_) { | 218 if (PrerenderContents* contents = parent_prerender_data->contents_) { |
219 pending_prerender_list_.push_back( | 219 pending_prerender_list_.push_back( |
220 linked_ptr<PrerenderData>(new PrerenderData(this))); | 220 linked_ptr<PrerenderData>(new PrerenderData(this))); |
221 PrerenderHandle* prerender_handle = | 221 PrerenderHandle* prerender_handle = |
222 new PrerenderHandle(pending_prerender_list_.back().get()); | 222 new PrerenderHandle(pending_prerender_list_.back().get()); |
223 contents->AddPendingPrerender( | 223 contents->AddPendingPrerender( |
224 prerender_handle->weak_ptr_factory_.GetWeakPtr(), | 224 prerender_handle->weak_ptr_factory_.GetWeakPtr(), |
225 url, referrer, size); | 225 url, referrer, size); |
226 return prerender_handle; | 226 return prerender_handle; |
227 } | 227 } |
228 } | 228 } |
229 | 229 |
230 // Unit tests pass in a process_id == -1. | 230 // Unit tests pass in a process_id == -1. |
231 SessionStorageNamespace* session_storage_namespace = NULL; | 231 if (process_id == -1) { |
232 if (process_id != -1) { | 232 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, |
233 RenderViewHost* source_render_view_host = | 233 process_id, url, referrer, size, |
234 RenderViewHost::FromID(process_id, route_id); | 234 SessionStorageNamespaceMap()); |
235 if (!source_render_view_host) | |
236 return NULL; | |
237 WebContents* source_web_contents = | |
238 WebContents::FromRenderViewHost(source_render_view_host); | |
239 if (!source_web_contents) | |
240 return NULL; | |
241 // TODO(ajwong): This does not correctly handle storage for isolated apps. | |
242 session_storage_namespace = | |
243 source_web_contents->GetController() | |
244 .GetSessionStorageNamespaceMap().find("")->second; | |
245 } | 235 } |
246 | 236 |
| 237 RenderViewHost* source_render_view_host = |
| 238 RenderViewHost::FromID(process_id, route_id); |
| 239 if (!source_render_view_host) |
| 240 return NULL; |
| 241 |
| 242 WebContents* source_web_contents = |
| 243 WebContents::FromRenderViewHost(source_render_view_host); |
247 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, | 244 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, |
248 process_id, url, referrer, size, | 245 process_id, url, referrer, size, |
249 session_storage_namespace); | 246 source_web_contents->GetController() |
| 247 .GetSessionStorageNamespaceMap()); |
250 #endif | 248 #endif |
251 } | 249 } |
252 | 250 |
253 PrerenderHandle* PrerenderManager::AddPrerenderFromOmnibox( | 251 PrerenderHandle* PrerenderManager::AddPrerenderFromOmnibox( |
254 const GURL& url, | 252 const GURL& url, |
255 SessionStorageNamespace* session_storage_namespace, | 253 const SessionStorageNamespaceMap& session_storage_namespace_map, |
256 const gfx::Size& size) { | 254 const gfx::Size& size) { |
257 if (!IsOmniboxEnabled(profile_)) | 255 if (!IsOmniboxEnabled(profile_)) |
258 return NULL; | 256 return NULL; |
259 return AddPrerender(ORIGIN_OMNIBOX, -1, url, content::Referrer(), size, | 257 return AddPrerender(ORIGIN_OMNIBOX, -1, url, content::Referrer(), size, |
260 session_storage_namespace); | 258 session_storage_namespace_map); |
261 } | 259 } |
262 | 260 |
263 void PrerenderManager::DestroyPrerenderForRenderView( | 261 void PrerenderManager::DestroyPrerenderForRenderView( |
264 int process_id, int view_id, FinalStatus final_status) { | 262 int process_id, int view_id, FinalStatus final_status) { |
265 DCHECK(CalledOnValidThread()); | 263 DCHECK(CalledOnValidThread()); |
266 if (PrerenderData* prerender_data = | 264 if (PrerenderData* prerender_data = |
267 FindPrerenderDataForChildAndRoute(process_id, view_id)) { | 265 FindPrerenderDataForChildAndRoute(process_id, view_id)) { |
268 prerender_data->contents_->Destroy(final_status); | 266 prerender_data->contents_->Destroy(final_status); |
269 } | 267 } |
270 } | 268 } |
271 | 269 |
272 void PrerenderManager::CancelAllPrerenders() { | 270 void PrerenderManager::CancelAllPrerenders() { |
273 DCHECK(CalledOnValidThread()); | 271 DCHECK(CalledOnValidThread()); |
274 while (!active_prerender_list_.empty()) { | 272 while (!active_prerender_list_.empty()) { |
275 PrerenderContents* prerender_contents = | 273 PrerenderContents* prerender_contents = |
276 active_prerender_list_.front()->contents(); | 274 active_prerender_list_.front()->contents(); |
277 prerender_contents->Destroy(FINAL_STATUS_CANCELLED); | 275 prerender_contents->Destroy(FINAL_STATUS_CANCELLED); |
278 } | 276 } |
279 } | 277 } |
280 | 278 |
281 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, | 279 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, |
282 const GURL& url) { | 280 const GURL& url) { |
283 DCHECK(CalledOnValidThread()); | 281 DCHECK(CalledOnValidThread()); |
284 DCHECK(!IsWebContentsPrerendering(web_contents)); | 282 DCHECK(!IsWebContentsPrerendering(web_contents)); |
285 | 283 |
| 284 const SessionStorageNamespaceMap& old_session_storage_namespace_map = |
| 285 web_contents->GetController().GetSessionStorageNamespaceMap(); |
286 DeleteOldEntries(); | 286 DeleteOldEntries(); |
287 DeletePendingDeleteEntries(); | 287 DeletePendingDeleteEntries(); |
288 // TODO(ajwong): This doesn't handle isolated apps correctly. | 288 PrerenderData* prerender_data = |
289 PrerenderData* prerender_data = FindPrerenderData( | 289 FindPrerenderData(url, old_session_storage_namespace_map); |
290 url, | |
291 web_contents->GetController().GetSessionStorageNamespaceMap() | |
292 .find("")->second); | |
293 if (!prerender_data) | 290 if (!prerender_data) |
294 return false; | 291 return false; |
295 DCHECK(prerender_data->contents_); | 292 DCHECK(prerender_data->contents_); |
296 if (IsNoSwapInExperiment(prerender_data->contents_->experiment_id())) | 293 if (IsNoSwapInExperiment(prerender_data->contents_->experiment_id())) |
297 return false; | 294 return false; |
298 | 295 |
299 if (TabContents* new_tab_contents = | 296 if (TabContents* new_tab_contents = |
300 prerender_data->contents_->prerender_contents()) { | 297 prerender_data->contents_->prerender_contents()) { |
301 if (web_contents == new_tab_contents->web_contents()) | 298 if (web_contents == new_tab_contents->web_contents()) |
302 return false; // Do not swap in to ourself. | 299 return false; // Do not swap in to ourself. |
(...skipping 500 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
803 prerender_contents_factory_.reset(prerender_contents_factory); | 800 prerender_contents_factory_.reset(prerender_contents_factory); |
804 } | 801 } |
805 | 802 |
806 void PrerenderManager::StartPendingPrerender( | 803 void PrerenderManager::StartPendingPrerender( |
807 PrerenderHandle* existing_prerender_handle, | 804 PrerenderHandle* existing_prerender_handle, |
808 Origin origin, | 805 Origin origin, |
809 int process_id, | 806 int process_id, |
810 const GURL& url, | 807 const GURL& url, |
811 const content::Referrer& referrer, | 808 const content::Referrer& referrer, |
812 const gfx::Size& size, | 809 const gfx::Size& size, |
813 content::SessionStorageNamespace* session_storage_namespace) { | 810 const content::SessionStorageNamespaceMap& session_storage_namespace_map) { |
814 DCHECK(existing_prerender_handle); | 811 DCHECK(existing_prerender_handle); |
815 DCHECK(existing_prerender_handle->IsValid()); | 812 DCHECK(existing_prerender_handle->IsValid()); |
816 DCHECK(existing_prerender_handle->IsPending()); | 813 DCHECK(existing_prerender_handle->IsPending()); |
817 | 814 |
818 DVLOG(6) << "StartPendingPrerender"; | 815 DVLOG(6) << "StartPendingPrerender"; |
819 DVLOG(6) << "existing_prerender_handle->handle_count_ = " << | 816 DVLOG(6) << "existing_prerender_handle->handle_count_ = " << |
820 existing_prerender_handle->prerender_data_->handle_count_; | 817 existing_prerender_handle->prerender_data_->handle_count_; |
821 | 818 |
822 DCHECK(process_id == -1 || session_storage_namespace); | 819 DCHECK(process_id == -1 || !session_storage_namespace_map.empty()); |
823 | 820 |
824 scoped_ptr<PrerenderHandle> swap_prerender_handle(AddPrerender( | 821 scoped_ptr<PrerenderHandle> swap_prerender_handle(AddPrerender( |
825 origin, process_id, url, referrer, size, session_storage_namespace)); | 822 origin, process_id, url, referrer, size, session_storage_namespace_map)); |
826 if (swap_prerender_handle.get()) { | 823 if (swap_prerender_handle.get()) { |
827 // AddPrerender has returned a new prerender handle to us. We want to make | 824 // AddPrerender has returned a new prerender handle to us. We want to make |
828 // |existing_prerender_handle| active, so swap the underlying PrerenderData | 825 // |existing_prerender_handle| active, so swap the underlying PrerenderData |
829 // between the two handles, and delete our old handle (which will release | 826 // between the two handles, and delete our old handle (which will release |
830 // our entry in the pending_prerender_list_). | 827 // our entry in the pending_prerender_list_). |
831 existing_prerender_handle->SwapPrerenderDataWith( | 828 existing_prerender_handle->SwapPrerenderDataWith( |
832 swap_prerender_handle.get()); | 829 swap_prerender_handle.get()); |
833 swap_prerender_handle->OnCancel(); | 830 swap_prerender_handle->OnCancel(); |
834 return; | 831 return; |
835 } | 832 } |
(...skipping 28 matching lines...) Expand all Loading... |
864 DCHECK(active_prerender_list_.empty()); | 861 DCHECK(active_prerender_list_.empty()); |
865 } | 862 } |
866 | 863 |
867 // private | 864 // private |
868 PrerenderHandle* PrerenderManager::AddPrerender( | 865 PrerenderHandle* PrerenderManager::AddPrerender( |
869 Origin origin, | 866 Origin origin, |
870 int process_id, | 867 int process_id, |
871 const GURL& url_arg, | 868 const GURL& url_arg, |
872 const content::Referrer& referrer, | 869 const content::Referrer& referrer, |
873 const gfx::Size& size, | 870 const gfx::Size& size, |
874 SessionStorageNamespace* session_storage_namespace) { | 871 const SessionStorageNamespaceMap& session_storage_namespace_map) { |
875 DCHECK(CalledOnValidThread()); | 872 DCHECK(CalledOnValidThread()); |
876 | 873 |
877 if (!IsEnabled()) | 874 if (!IsEnabled()) |
878 return NULL; | 875 return NULL; |
879 | 876 |
880 if (origin == ORIGIN_LINK_REL_PRERENDER && | 877 if (origin == ORIGIN_LINK_REL_PRERENDER && |
881 IsGoogleSearchResultURL(referrer.url)) { | 878 IsGoogleSearchResultURL(referrer.url)) { |
882 origin = ORIGIN_GWS_PRERENDER; | 879 origin = ORIGIN_GWS_PRERENDER; |
883 } | 880 } |
884 | 881 |
885 DeleteOldEntries(); | 882 DeleteOldEntries(); |
886 DeletePendingDeleteEntries(); | 883 DeletePendingDeleteEntries(); |
887 | 884 |
888 GURL url = url_arg; | 885 GURL url = url_arg; |
889 GURL alias_url; | 886 GURL alias_url; |
890 uint8 experiment = GetQueryStringBasedExperiment(url_arg); | 887 uint8 experiment = GetQueryStringBasedExperiment(url_arg); |
891 bool control_group_behavior = | 888 bool control_group_behavior = |
892 IsControlGroup() || IsControlGroupExperiment(experiment); | 889 IsControlGroup() || IsControlGroupExperiment(experiment); |
893 if (control_group_behavior && | 890 if (control_group_behavior && |
894 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { | 891 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { |
895 url = alias_url; | 892 url = alias_url; |
896 } | 893 } |
897 | 894 |
898 // From here on, we will record a FinalStatus so we need to register with the | 895 // From here on, we will record a FinalStatus so we need to register with the |
899 // histogram tracking. | 896 // histogram tracking. |
900 histograms_->RecordPrerender(origin, url_arg); | 897 histograms_->RecordPrerender(origin, url_arg); |
901 | 898 |
902 if (PrerenderData* preexisting_prerender_data = | 899 if (PrerenderData* preexisting_prerender_data = |
903 FindPrerenderData(url, session_storage_namespace)) { | 900 FindPrerenderData(url, session_storage_namespace_map)) { |
904 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); | 901 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); |
905 return new PrerenderHandle(preexisting_prerender_data); | 902 return new PrerenderHandle(preexisting_prerender_data); |
906 } | 903 } |
907 | 904 |
908 // Do not prerender if there are too many render processes, and we would | 905 // Do not prerender if there are too many render processes, and we would |
909 // have to use an existing one. We do not want prerendering to happen in | 906 // have to use an existing one. We do not want prerendering to happen in |
910 // a shared process, so that we can always reliably lower the CPU | 907 // a shared process, so that we can always reliably lower the CPU |
911 // priority for prerendering. | 908 // priority for prerendering. |
912 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns | 909 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns |
913 // true, so that case needs to be explicitly checked for. | 910 // true, so that case needs to be explicitly checked for. |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
945 linked_ptr<PrerenderData>(new PrerenderData(this, prerender_contents))); | 942 linked_ptr<PrerenderData>(new PrerenderData(this, prerender_contents))); |
946 PrerenderHandle* prerender_handle = | 943 PrerenderHandle* prerender_handle = |
947 new PrerenderHandle(active_prerender_list_.back().get()); | 944 new PrerenderHandle(active_prerender_list_.back().get()); |
948 | 945 |
949 last_prerender_start_time_ = GetCurrentTimeTicks(); | 946 last_prerender_start_time_ = GetCurrentTimeTicks(); |
950 | 947 |
951 gfx::Size contents_size = | 948 gfx::Size contents_size = |
952 size.IsEmpty() ? config_.default_tab_bounds.size() : size; | 949 size.IsEmpty() ? config_.default_tab_bounds.size() : size; |
953 | 950 |
954 prerender_contents->StartPrerendering(process_id, contents_size, | 951 prerender_contents->StartPrerendering(process_id, contents_size, |
955 session_storage_namespace, | 952 session_storage_namespace_map, |
956 control_group_behavior); | 953 control_group_behavior); |
957 | 954 |
958 while (active_prerender_list_.size() > config_.max_concurrency) { | 955 while (active_prerender_list_.size() > config_.max_concurrency) { |
959 prerender_contents = active_prerender_list_.front()->contents_; | 956 prerender_contents = active_prerender_list_.front()->contents_; |
960 DCHECK(prerender_contents); | 957 DCHECK(prerender_contents); |
961 prerender_contents->Destroy(FINAL_STATUS_EVICTED); | 958 prerender_contents->Destroy(FINAL_STATUS_EVICTED); |
962 } | 959 } |
963 | 960 |
964 histograms_->RecordConcurrency(active_prerender_list_.size()); | 961 histograms_->RecordConcurrency(active_prerender_list_.size()); |
965 | 962 |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1057 void PrerenderManager::DeletePendingDeleteEntries() { | 1054 void PrerenderManager::DeletePendingDeleteEntries() { |
1058 while (!pending_delete_list_.empty()) { | 1055 while (!pending_delete_list_.empty()) { |
1059 PrerenderContents* contents = pending_delete_list_.front(); | 1056 PrerenderContents* contents = pending_delete_list_.front(); |
1060 pending_delete_list_.pop_front(); | 1057 pending_delete_list_.pop_front(); |
1061 delete contents; | 1058 delete contents; |
1062 } | 1059 } |
1063 } | 1060 } |
1064 | 1061 |
1065 PrerenderManager::PrerenderData* PrerenderManager::FindPrerenderData( | 1062 PrerenderManager::PrerenderData* PrerenderManager::FindPrerenderData( |
1066 const GURL& url, | 1063 const GURL& url, |
1067 const SessionStorageNamespace* session_storage_namespace) { | 1064 const SessionStorageNamespaceMap& session_storage_namespace_map) { |
1068 for (std::list<linked_ptr<PrerenderData> >::iterator | 1065 for (std::list<linked_ptr<PrerenderData> >::iterator |
1069 it = active_prerender_list_.begin(); | 1066 it = active_prerender_list_.begin(); |
1070 it != active_prerender_list_.end(); | 1067 it != active_prerender_list_.end(); |
1071 ++it) { | 1068 ++it) { |
1072 PrerenderContents* prerender_contents = it->get()->contents_; | 1069 PrerenderContents* prerender_contents = it->get()->contents_; |
1073 if (prerender_contents->Matches(url, session_storage_namespace)) | 1070 if (prerender_contents->Matches(url, session_storage_namespace_map)) |
1074 return it->get(); | 1071 return it->get(); |
1075 } | 1072 } |
1076 return NULL; | 1073 return NULL; |
1077 } | 1074 } |
1078 | 1075 |
1079 PrerenderManager::PrerenderData* | 1076 PrerenderManager::PrerenderData* |
1080 PrerenderManager::FindPrerenderDataForChildAndRoute( | 1077 PrerenderManager::FindPrerenderDataForChildAndRoute( |
1081 const int child_id, const int route_id) { | 1078 const int child_id, const int route_id) { |
1082 for (std::list<linked_ptr<PrerenderData> >::iterator | 1079 for (std::list<linked_ptr<PrerenderData> >::iterator |
1083 it = active_prerender_list_.begin(); | 1080 it = active_prerender_list_.begin(); |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1236 if (!render_process_host || !render_process_host->GetBrowserContext()) | 1233 if (!render_process_host || !render_process_host->GetBrowserContext()) |
1237 return NULL; | 1234 return NULL; |
1238 Profile* profile = Profile::FromBrowserContext( | 1235 Profile* profile = Profile::FromBrowserContext( |
1239 render_process_host->GetBrowserContext()); | 1236 render_process_host->GetBrowserContext()); |
1240 if (!profile) | 1237 if (!profile) |
1241 return NULL; | 1238 return NULL; |
1242 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); | 1239 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); |
1243 } | 1240 } |
1244 | 1241 |
1245 } // namespace prerender | 1242 } // namespace prerender |
OLD | NEW |