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 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
216 break; | 216 break; |
217 default: | 217 default: |
218 break; | 218 break; |
219 } | 219 } |
220 } | 220 } |
221 | 221 |
222 PrerenderManager::~PrerenderManager() { | 222 PrerenderManager::~PrerenderManager() { |
223 // The earlier call to ProfileKeyedService::Shutdown() should have emptied | 223 // The earlier call to ProfileKeyedService::Shutdown() should have emptied |
224 // these vectors already. | 224 // these vectors already. |
225 DCHECK(active_prerenders_.empty()); | 225 DCHECK(active_prerenders_.empty()); |
226 DCHECK(pending_prerenders_.empty()); | |
227 DCHECK(to_delete_prerenders_.empty()); | 226 DCHECK(to_delete_prerenders_.empty()); |
228 } | 227 } |
229 | 228 |
230 void PrerenderManager::Shutdown() { | 229 void PrerenderManager::Shutdown() { |
231 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); | 230 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); |
232 STLDeleteElements(&prerender_conditions_); | 231 STLDeleteElements(&prerender_conditions_); |
233 on_close_web_contents_deleters_.clear(); | 232 on_close_web_contents_deleters_.clear(); |
234 // Must happen before |profile_| is set to NULL as | 233 // Must happen before |profile_| is set to NULL as |
235 // |local_predictor_| accesses it. | 234 // |local_predictor_| accesses it. |
236 if (local_predictor_) | 235 if (local_predictor_) |
237 local_predictor_->Shutdown(); | 236 local_predictor_->Shutdown(); |
238 profile_ = NULL; | 237 profile_ = NULL; |
239 | 238 |
240 DCHECK(active_prerenders_.empty()); | 239 DCHECK(active_prerenders_.empty()); |
241 pending_prerenders_.clear(); | |
242 } | 240 } |
243 | 241 |
244 PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender( | 242 PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender( |
245 int process_id, | 243 int process_id, |
246 int route_id, | 244 int route_id, |
247 const GURL& url, | 245 const GURL& url, |
248 const content::Referrer& referrer, | 246 const content::Referrer& referrer, |
249 const gfx::Size& size) { | 247 const gfx::Size& size) { |
250 #if defined(OS_ANDROID) | 248 #if defined(OS_ANDROID) |
251 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable | 249 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable |
(...skipping 19 matching lines...) Expand all Loading... | |
271 session_storage_namespace = | 269 session_storage_namespace = |
272 source_web_contents->GetController() | 270 source_web_contents->GetController() |
273 .GetDefaultSessionStorageNamespace(); | 271 .GetDefaultSessionStorageNamespace(); |
274 } | 272 } |
275 | 273 |
276 if (PrerenderData* parent_prerender_data = | 274 if (PrerenderData* parent_prerender_data = |
277 FindPrerenderDataForChildAndRoute(process_id, route_id)) { | 275 FindPrerenderDataForChildAndRoute(process_id, route_id)) { |
278 // Instead of prerendering from inside of a running prerender, we will defer | 276 // Instead of prerendering from inside of a running prerender, we will defer |
279 // this request until its launcher is made visible. | 277 // this request until its launcher is made visible. |
280 if (PrerenderContents* contents = parent_prerender_data->contents()) { | 278 if (PrerenderContents* contents = parent_prerender_data->contents()) { |
281 pending_prerenders_.push_back(new PrerenderData(this)); | |
282 PrerenderHandle* prerender_handle = | 279 PrerenderHandle* prerender_handle = |
283 new PrerenderHandle(pending_prerenders_.back()); | 280 new PrerenderHandle(static_cast<PrerenderData*>(NULL)); |
284 DCHECK(prerender_handle->IsPending()); | |
285 | |
286 scoped_ptr<PrerenderContents::PendingPrerenderInfo> | 281 scoped_ptr<PrerenderContents::PendingPrerenderInfo> |
287 pending_prerender_info(new PrerenderContents::PendingPrerenderInfo( | 282 pending_prerender_info(new PrerenderContents::PendingPrerenderInfo( |
288 prerender_handle->weak_ptr_factory_.GetWeakPtr(), | 283 prerender_handle->weak_ptr_factory_.GetWeakPtr(), |
289 origin, url, referrer, size)); | 284 origin, url, referrer, size)); |
290 | 285 |
291 contents->AddPendingPrerender(pending_prerender_info.Pass()); | 286 contents->AddPendingPrerender(pending_prerender_info.Pass()); |
292 return prerender_handle; | 287 return prerender_handle; |
293 } | 288 } |
294 } | 289 } |
295 | 290 |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
422 prerender_contents->SetFinalStatus(FINAL_STATUS_USED); | 417 prerender_contents->SetFinalStatus(FINAL_STATUS_USED); |
423 | 418 |
424 RenderViewHost* new_render_view_host = | 419 RenderViewHost* new_render_view_host = |
425 prerender_contents->prerender_contents()->GetRenderViewHost(); | 420 prerender_contents->prerender_contents()->GetRenderViewHost(); |
426 new_render_view_host->Send( | 421 new_render_view_host->Send( |
427 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), | 422 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), |
428 false)); | 423 false)); |
429 | 424 |
430 // Start pending prerender requests from the PrerenderContents, if there are | 425 // Start pending prerender requests from the PrerenderContents, if there are |
431 // any. | 426 // any. |
432 prerender_contents->StartPendingPrerenders(); | 427 prerender_contents->PrepareForUse(); |
433 | 428 |
434 WebContents* new_web_contents = | 429 WebContents* new_web_contents = |
435 prerender_contents->ReleasePrerenderContents(); | 430 prerender_contents->ReleasePrerenderContents(); |
436 WebContents* old_web_contents = web_contents; | 431 WebContents* old_web_contents = web_contents; |
437 DCHECK(new_web_contents); | 432 DCHECK(new_web_contents); |
438 DCHECK(old_web_contents); | 433 DCHECK(old_web_contents); |
439 | 434 |
440 MarkWebContentsAsPrerendered(new_web_contents, prerender_contents->origin()); | 435 MarkWebContentsAsPrerendered(new_web_contents, prerender_contents->origin()); |
441 | 436 |
442 // Merge the browsing history. | 437 // Merge the browsing history. |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
494 // for PPLT accounting purposes for the Match Complete group. This is the case | 489 // for PPLT accounting purposes for the Match Complete group. This is the case |
495 // if the cancellation is for any reason that would not occur in the control | 490 // if the cancellation is for any reason that would not occur in the control |
496 // group case. | 491 // group case. |
497 if (entry->prerendering_has_started() && | 492 if (entry->prerendering_has_started() && |
498 entry->match_complete_status() == | 493 entry->match_complete_status() == |
499 PrerenderContents::MATCH_COMPLETE_DEFAULT && | 494 PrerenderContents::MATCH_COMPLETE_DEFAULT && |
500 NeedMatchCompleteDummyForFinalStatus(final_status) && | 495 NeedMatchCompleteDummyForFinalStatus(final_status) && |
501 ActuallyPrerendering()) { | 496 ActuallyPrerendering()) { |
502 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. | 497 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. |
503 // However, what if new conditions are added and | 498 // However, what if new conditions are added and |
504 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure | 499 // NeedMatchCompleteDummyForFinalStatus is not being updated. Not sure |
505 // what's the best thing to do here. For now, I will just check whether | 500 // what's the best thing to do here. For now, I will just check whether |
506 // we are actually prerendering. | 501 // we are actually prerendering. |
507 (*it)->MakeIntoMatchCompleteReplacement(); | 502 (*it)->MakeIntoMatchCompleteReplacement(); |
508 } else { | 503 } else { |
509 to_delete_prerenders_.push_back(*it); | 504 to_delete_prerenders_.push_back(*it); |
510 active_prerenders_.weak_erase(it); | 505 active_prerenders_.weak_erase(it); |
511 } | 506 } |
512 | 507 |
513 // Destroy the old WebContents relatively promptly to reduce resource usage, | 508 // Destroy the old WebContents relatively promptly to reduce resource usage, |
514 // and in the case of HTML5 media, reduce the change of playing any sound. | 509 // and in the case of HTML5 media, reduce the chance of playing any sound. |
515 PostCleanupTask(); | 510 PostCleanupTask(); |
516 } | 511 } |
517 | 512 |
518 // static | 513 // static |
519 void PrerenderManager::RecordPerceivedPageLoadTime( | 514 void PrerenderManager::RecordPerceivedPageLoadTime( |
520 base::TimeDelta perceived_page_load_time, | 515 base::TimeDelta perceived_page_load_time, |
521 double fraction_plt_elapsed_at_swap_in, | 516 double fraction_plt_elapsed_at_swap_in, |
522 WebContents* web_contents, | 517 WebContents* web_contents, |
523 const GURL& url) { | 518 const GURL& url) { |
524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 519 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
844 CleanUpOldNavigations(); | 839 CleanUpOldNavigations(); |
845 } | 840 } |
846 | 841 |
847 // protected | 842 // protected |
848 struct PrerenderManager::PrerenderData::OrderByExpiryTime { | 843 struct PrerenderManager::PrerenderData::OrderByExpiryTime { |
849 bool operator()(const PrerenderData* a, const PrerenderData* b) const { | 844 bool operator()(const PrerenderData* a, const PrerenderData* b) const { |
850 return a->expiry_time() < b->expiry_time(); | 845 return a->expiry_time() < b->expiry_time(); |
851 } | 846 } |
852 }; | 847 }; |
853 | 848 |
854 PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager) | |
855 : manager_(manager), contents_(NULL), handle_count_(0) { | |
856 } | |
857 | |
858 PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager, | 849 PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager, |
859 PrerenderContents* contents, | 850 PrerenderContents* contents, |
860 base::TimeTicks expiry_time) | 851 base::TimeTicks expiry_time) |
861 : manager_(manager), | 852 : manager_(manager), |
862 contents_(contents), | 853 contents_(contents), |
863 handle_count_(0), | 854 handle_count_(0), |
864 expiry_time_(expiry_time) { | 855 expiry_time_(expiry_time) { |
856 DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_); | |
865 } | 857 } |
866 | 858 |
867 PrerenderManager::PrerenderData::~PrerenderData() { | 859 PrerenderManager::PrerenderData::~PrerenderData() { |
868 } | 860 } |
869 | 861 |
870 void PrerenderManager::PrerenderData::MakeIntoMatchCompleteReplacement() { | 862 void PrerenderManager::PrerenderData::MakeIntoMatchCompleteReplacement() { |
871 DCHECK(contents_); | 863 DCHECK(contents_); |
872 contents_->set_match_complete_status( | 864 contents_->set_match_complete_status( |
873 PrerenderContents::MATCH_COMPLETE_REPLACED); | 865 PrerenderContents::MATCH_COMPLETE_REPLACED); |
874 PrerenderData* to_delete = new PrerenderData(manager_, contents_.release(), | 866 PrerenderData* to_delete = new PrerenderData(manager_, contents_.release(), |
875 expiry_time_); | 867 expiry_time_); |
876 contents_.reset(to_delete->contents_->CreateMatchCompleteReplacement()); | 868 contents_.reset(to_delete->contents_->CreateMatchCompleteReplacement()); |
877 manager_->to_delete_prerenders_.push_back(to_delete); | 869 manager_->to_delete_prerenders_.push_back(to_delete); |
878 } | 870 } |
879 | 871 |
880 void PrerenderManager::PrerenderData::OnNewHandle() { | 872 void PrerenderManager::PrerenderData::OnHandleCreated(PrerenderHandle* handle) { |
881 DCHECK(contents_ || handle_count_ == 0) << | 873 DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_); |
882 "Cannot create multiple handles to a pending prerender."; | |
883 ++handle_count_; | 874 ++handle_count_; |
875 contents_->AddObserver(handle); | |
884 } | 876 } |
885 | 877 |
886 void PrerenderManager::PrerenderData::OnNavigateAwayByHandle() { | 878 void PrerenderManager::PrerenderData::OnHandleNavigatedAway( |
887 if (!contents_) { | 879 PrerenderHandle* handle) { |
888 DCHECK_EQ(1, handle_count_); | 880 DCHECK_LT(0, handle_count_); |
889 // Pending prerenders are not maintained in the active_prerenders_, so they | 881 DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_); |
890 // will not get normal expiry. Since this prerender hasn't even been | 882 // We intentionally don't decrement the handle count here, so that the |
891 // launched yet, and it's held by a page that is being prerendered, we will | 883 // prerender won't be canceled until it times out. |
892 // just delete it. | 884 manager_->SourceNavigatedAway(this); |
893 manager_->DestroyPendingPrerenderData(this); | 885 } |
894 } else { | 886 |
895 DCHECK_LE(0, handle_count_); | 887 void PrerenderManager::PrerenderData::OnHandleCanceled( |
896 // We intentionally don't decrement the handle count here, so that the | 888 PrerenderHandle* handle) { |
897 // prerender won't be canceled until it times out. | 889 DCHECK_LE(1, handle_count_); |
mmenke
2012/12/13 18:27:16
nit: This uses "DCHECK_LE", and the above functio
gavinp
2012/12/13 20:45:34
Done.
| |
898 manager_->SourceNavigatedAway(this); | 890 DCHECK_NE(static_cast<PrerenderContents*>(NULL), contents_); |
891 | |
892 if (--handle_count_ == 0) { | |
893 // This will eventually remove this object from active_prerenders_. | |
894 contents_->Destroy(FINAL_STATUS_CANCELLED); | |
899 } | 895 } |
900 } | 896 } |
901 | 897 |
902 void PrerenderManager::PrerenderData::OnCancelByHandle() { | |
903 DCHECK_LE(1, handle_count_); | |
904 DCHECK(contents_ || handle_count_ == 1); | |
905 | |
906 if (--handle_count_ == 0) { | |
907 if (contents_) { | |
908 // This will eventually remove this object from active_prerenders_. | |
909 contents_->Destroy(FINAL_STATUS_CANCELLED); | |
910 } else { | |
911 manager_->DestroyPendingPrerenderData(this); | |
912 } | |
913 } | |
914 } | |
915 | |
916 PrerenderContents* PrerenderManager::PrerenderData::ReleaseContents() { | 898 PrerenderContents* PrerenderManager::PrerenderData::ReleaseContents() { |
917 return contents_.release(); | 899 return contents_.release(); |
918 } | 900 } |
919 | 901 |
920 void PrerenderManager::SetPrerenderContentsFactory( | 902 void PrerenderManager::SetPrerenderContentsFactory( |
921 PrerenderContents::Factory* prerender_contents_factory) { | 903 PrerenderContents::Factory* prerender_contents_factory) { |
922 DCHECK(CalledOnValidThread()); | 904 DCHECK(CalledOnValidThread()); |
923 prerender_contents_factory_.reset(prerender_contents_factory); | 905 prerender_contents_factory_.reset(prerender_contents_factory); |
924 } | 906 } |
925 | 907 |
926 void PrerenderManager::StartPendingPrerenders( | 908 void PrerenderManager::StartPendingPrerenders( |
927 const int process_id, | 909 const int process_id, |
928 ScopedVector<PrerenderContents::PendingPrerenderInfo>* pending_prerenders, | 910 ScopedVector<PrerenderContents::PendingPrerenderInfo>* pending_prerenders, |
929 content::SessionStorageNamespace* session_storage_namespace) { | 911 content::SessionStorageNamespace* session_storage_namespace) { |
930 for (ScopedVector<PrerenderContents::PendingPrerenderInfo>::iterator | 912 for (ScopedVector<PrerenderContents::PendingPrerenderInfo>::iterator |
931 it = pending_prerenders->begin(); | 913 it = pending_prerenders->begin(); |
932 it != pending_prerenders->end(); ++it) { | 914 it != pending_prerenders->end(); ++it) { |
933 PrerenderContents::PendingPrerenderInfo* info = *it; | 915 PrerenderContents::PendingPrerenderInfo* info = *it; |
934 PrerenderHandle* existing_prerender_handle = | 916 PrerenderHandle* existing_prerender_handle = |
935 info->weak_prerender_handle.get(); | 917 info->weak_prerender_handle.get(); |
936 if (!existing_prerender_handle || !existing_prerender_handle->IsValid()) | 918 if (!existing_prerender_handle) |
937 continue; | 919 continue; |
938 | 920 |
939 DCHECK(existing_prerender_handle->IsPending()); | 921 DCHECK(!existing_prerender_handle->IsPrerendering()); |
940 DCHECK(process_id == -1 || session_storage_namespace); | 922 DCHECK(process_id == -1 || session_storage_namespace); |
941 | 923 |
942 scoped_ptr<PrerenderHandle> swap_prerender_handle(AddPrerender( | 924 scoped_ptr<PrerenderHandle> new_prerender_handle(AddPrerender( |
943 info->origin, process_id, | 925 info->origin, process_id, |
944 info->url, info->referrer, info->size, | 926 info->url, info->referrer, info->size, |
945 session_storage_namespace)); | 927 session_storage_namespace)); |
946 if (swap_prerender_handle.get()) { | 928 if (new_prerender_handle) { |
947 // AddPrerender has returned a new prerender handle to us. We want to make | 929 // AddPrerender has returned a new prerender handle to us. We want to make |
948 // |existing_prerender_handle| active, so swap the underlying | 930 // |existing_prerender_handle| active, so move the underlying |
949 // PrerenderData between the two handles, and delete our old handle (which | 931 // PrerenderData to our new handle. |
950 // will release our entry in the pending_prerender_list_). | 932 existing_prerender_handle->AdoptPrerenderDataFrom( |
951 existing_prerender_handle->SwapPrerenderDataWith( | 933 new_prerender_handle.get()); |
952 swap_prerender_handle.get()); | |
953 swap_prerender_handle->OnCancel(); | |
954 continue; | 934 continue; |
955 } | 935 } |
956 | |
957 // We could not start our Prerender. Canceling the existing handle will make | |
958 // it return false for PrerenderHandle::IsPending(), and will release the | |
959 // PrerenderData from pending_prerender_list_. | |
960 existing_prerender_handle->OnCancel(); | |
961 } | 936 } |
962 } | 937 } |
963 | 938 |
964 void PrerenderManager::SourceNavigatedAway(PrerenderData* prerender_data) { | 939 void PrerenderManager::SourceNavigatedAway(PrerenderData* prerender_data) { |
965 // The expiry time of our prerender data will likely change because of | 940 // The expiry time of our prerender data will likely change because of |
966 // this navigation. This requires a resort of active_prerenders_. | 941 // this navigation. This requires a resort of active_prerenders_. |
967 ScopedVector<PrerenderData>::iterator it = | 942 ScopedVector<PrerenderData>::iterator it = |
968 std::find(active_prerenders_.begin(), active_prerenders_.end(), | 943 std::find(active_prerenders_.begin(), active_prerenders_.end(), |
969 prerender_data); | 944 prerender_data); |
970 if (it == active_prerenders_.end()) | 945 if (it == active_prerenders_.end()) |
971 return; | 946 return; |
972 | 947 |
973 (*it)->set_expiry_time( | 948 (*it)->set_expiry_time( |
974 std::min((*it)->expiry_time(), | 949 std::min((*it)->expiry_time(), |
975 GetExpiryTimeForNavigatedAwayPrerender())); | 950 GetExpiryTimeForNavigatedAwayPrerender())); |
976 SortActivePrerenders(); | 951 SortActivePrerenders(); |
977 } | 952 } |
978 | 953 |
979 void PrerenderManager::DestroyPendingPrerenderData( | |
980 PrerenderData* pending_prerender_data) { | |
981 ScopedVector<PrerenderData>::iterator it = | |
982 std::find(pending_prerenders_.begin(), pending_prerenders_.end(), | |
983 pending_prerender_data); | |
984 if (it == pending_prerenders_.end()) | |
985 return; | |
986 pending_prerenders_.erase(it); | |
987 } | |
988 | |
989 // private | 954 // private |
990 PrerenderHandle* PrerenderManager::AddPrerender( | 955 PrerenderHandle* PrerenderManager::AddPrerender( |
991 Origin origin, | 956 Origin origin, |
992 int process_id, | 957 int process_id, |
993 const GURL& url_arg, | 958 const GURL& url_arg, |
994 const content::Referrer& referrer, | 959 const content::Referrer& referrer, |
995 const gfx::Size& size, | 960 const gfx::Size& size, |
996 SessionStorageNamespace* session_storage_namespace) { | 961 SessionStorageNamespace* session_storage_namespace) { |
997 DCHECK(CalledOnValidThread()); | 962 DCHECK(CalledOnValidThread()); |
998 | 963 |
(...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1351 if (!render_process_host || !render_process_host->GetBrowserContext()) | 1316 if (!render_process_host || !render_process_host->GetBrowserContext()) |
1352 return NULL; | 1317 return NULL; |
1353 Profile* profile = Profile::FromBrowserContext( | 1318 Profile* profile = Profile::FromBrowserContext( |
1354 render_process_host->GetBrowserContext()); | 1319 render_process_host->GetBrowserContext()); |
1355 if (!profile) | 1320 if (!profile) |
1356 return NULL; | 1321 return NULL; |
1357 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); | 1322 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); |
1358 } | 1323 } |
1359 | 1324 |
1360 } // namespace prerender | 1325 } // namespace prerender |
OLD | NEW |