Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(123)

Side by Side Diff: chrome/browser/prerender/prerender_manager.cc

Issue 10198040: New link rel=prerender api, using WebKit::WebPrerenderingPlatform (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: friendship is hard Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 <set>
7 #include <string> 8 #include <string>
9 #include <vector>
8 10
9 #include "base/bind.h" 11 #include "base/bind.h"
10 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
11 #include "base/logging.h" 13 #include "base/logging.h"
12 #include "base/memory/weak_ptr.h" 14 #include "base/memory/weak_ptr.h"
13 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
14 #include "base/stl_util.h" 16 #include "base/stl_util.h"
15 #include "base/time.h" 17 #include "base/time.h"
16 #include "base/utf_string_conversions.h" 18 #include "base/utf_string_conversions.h"
17 #include "base/values.h" 19 #include "base/values.h"
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after
168 // static 170 // static
169 int PrerenderManager::prerenders_per_session_count_ = 0; 171 int PrerenderManager::prerenders_per_session_count_ = 0;
170 172
171 // static 173 // static
172 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = 174 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ =
173 PRERENDER_MODE_ENABLED; 175 PRERENDER_MODE_ENABLED;
174 176
175 struct PrerenderManager::PrerenderContentsData { 177 struct PrerenderManager::PrerenderContentsData {
176 PrerenderContents* contents_; 178 PrerenderContents* contents_;
177 base::Time start_time_; 179 base::Time start_time_;
180 int active_count_;
178 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) 181 PrerenderContentsData(PrerenderContents* contents, base::Time start_time)
179 : contents_(contents), 182 : contents_(contents),
180 start_time_(start_time) { 183 start_time_(start_time),
184 active_count_(1) {
181 CHECK(contents); 185 CHECK(contents);
182 } 186 }
183 }; 187 };
184 188
185 struct PrerenderManager::NavigationRecord { 189 struct PrerenderManager::NavigationRecord {
186 GURL url_; 190 GURL url_;
187 base::TimeTicks time_; 191 base::TimeTicks time_;
188 NavigationRecord(const GURL& url, base::TimeTicks time) 192 NavigationRecord(const GURL& url, base::TimeTicks time)
189 : url_(url), 193 : url_(url),
190 time_(time) { 194 time_(time) {
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
267 } 271 }
268 272
269 void PrerenderManager::Shutdown() { 273 void PrerenderManager::Shutdown() {
270 DoShutdown(); 274 DoShutdown();
271 } 275 }
272 276
273 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( 277 bool PrerenderManager::AddPrerenderFromLinkRelPrerender(
274 int process_id, 278 int process_id,
275 int route_id, 279 int route_id,
276 const GURL& url, 280 const GURL& url,
277 const content::Referrer& referrer) { 281 const content::Referrer& referrer,
282 const gfx::Size& size) {
278 #if defined(OS_ANDROID) 283 #if defined(OS_ANDROID)
279 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable 284 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable
280 // link-prerender and enable omnibox-prerender only. 285 // link-prerender and enable omnibox-prerender only.
281 return false; 286 return false;
282 #else 287 #else
283 std::pair<int, int> child_route_id_pair = std::make_pair(process_id, 288 std::pair<int, int> child_route_id_pair(process_id, route_id);
284 route_id); 289 PrerenderContentsDataList::iterator it =
290 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair);
291 if (it != prerender_list_.end()) {
292 // Instead of prerendering from inside of a running prerender, we will defer
293 // this request until its launcher is made visible.
294 it->contents_->AddPendingPrerender(url, referrer, size);
cbentzel 2012/05/02 15:54:22 This will add a pending prerender even if the Prer
gavinp 2012/05/02 16:23:42 Yes. The funny behaviour from this is: 1. User h
cbentzel 2012/05/04 15:32:25 Correct.
295 return true;
296 }
285 297
286 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, child_route_id_pair, 298 // Unit tests pass in a process_id == -1.
287 url, referrer, NULL); 299 RenderViewHost* source_render_view_host = NULL;
300 SessionStorageNamespace* session_storage_namespace = NULL;
301 if (process_id != -1) {
302 source_render_view_host =
303 RenderViewHost::FromID(process_id, route_id);
304 if (!source_render_view_host || !source_render_view_host->GetView())
305 return false;
306 session_storage_namespace =
307 source_render_view_host->GetSessionStorageNamespace();
308 }
309
310 return AddPrerender(ORIGIN_LINK_REL_PRERENDER,
311 process_id, url, referrer, size,
312 session_storage_namespace);
288 #endif 313 #endif
289 } 314 }
290 315
291 bool PrerenderManager::AddPrerenderFromOmnibox( 316 bool PrerenderManager::AddPrerenderFromOmnibox(
292 const GURL& url, 317 const GURL& url,
293 SessionStorageNamespace* session_storage_namespace) { 318 SessionStorageNamespace* session_storage_namespace) {
294 if (!IsOmniboxEnabled(profile_)) 319 if (!IsOmniboxEnabled(profile_))
295 return false; 320 return false;
296 return AddPrerender(ORIGIN_OMNIBOX, std::make_pair(-1, -1), url, 321 return AddPrerender(ORIGIN_OMNIBOX, -1, url,
297 content::Referrer(), session_storage_namespace); 322 content::Referrer(), gfx::Size(),
323 session_storage_namespace);
324 }
325
326 void PrerenderManager::MaybeCancelPrerender(const GURL& url) {
327 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
328 if (it == prerender_list_.end())
329 return;
330 PrerenderContentsData& prerender_contents_data = *it;
331 if (--prerender_contents_data.active_count_ == 0)
332 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED);
298 } 333 }
299 334
300 void PrerenderManager::DestroyPrerenderForRenderView( 335 void PrerenderManager::DestroyPrerenderForRenderView(
301 int process_id, int view_id, FinalStatus final_status) { 336 int process_id, int view_id, FinalStatus final_status) {
302 DCHECK(CalledOnValidThread()); 337 DCHECK(CalledOnValidThread());
303 PrerenderContentsDataList::iterator it = 338 PrerenderContentsDataList::iterator it =
304 FindPrerenderContentsForChildRouteIdPair( 339 FindPrerenderContentsForChildRouteIdPair(
305 std::make_pair(process_id, view_id)); 340 std::make_pair(process_id, view_id));
306 if (it != prerender_list_.end()) { 341 if (it != prerender_list_.end()) {
307 PrerenderContents* prerender_contents = it->contents_; 342 PrerenderContents* prerender_contents = it->contents_;
308 prerender_contents->Destroy(final_status); 343 prerender_contents->Destroy(final_status);
309 } 344 }
310 } 345 }
311 346
312 void PrerenderManager::CancelAllPrerenders() { 347 void PrerenderManager::CancelAllPrerenders() {
313 DCHECK(CalledOnValidThread()); 348 DCHECK(CalledOnValidThread());
314 while (!prerender_list_.empty()) { 349 while (!prerender_list_.empty()) {
315 PrerenderContentsData data = prerender_list_.front(); 350 PrerenderContentsData data = prerender_list_.front();
316 DCHECK(data.contents_); 351 DCHECK(data.contents_);
317 data.contents_->Destroy(FINAL_STATUS_CANCELLED); 352 data.contents_->Destroy(FINAL_STATUS_CANCELLED);
318 } 353 }
319 } 354 }
320 355
321 void PrerenderManager::CancelOmniboxPrerenders() { 356 void PrerenderManager::CancelOmniboxPrerenders() {
cbentzel 2012/05/02 15:54:22 Does this need to change so the omnibox prerenderi
322 DCHECK(CalledOnValidThread()); 357 DCHECK(CalledOnValidThread());
323 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 358 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
324 it != prerender_list_.end(); ) { 359 it != prerender_list_.end(); ) {
325 PrerenderContentsDataList::iterator cur = it++; 360 PrerenderContentsDataList::iterator cur = it++;
326 if (cur->contents_->origin() == ORIGIN_OMNIBOX) 361 if (cur->contents_->origin() == ORIGIN_OMNIBOX)
327 cur->contents_->Destroy(FINAL_STATUS_CANCELLED); 362 cur->contents_->Destroy(FINAL_STATUS_CANCELLED);
328 } 363 }
329 } 364 }
330 365
331 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, 366 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
(...skipping 484 matching lines...) Expand 10 before | Expand all | Expand 10 after
816 void PrerenderManager::DoShutdown() { 851 void PrerenderManager::DoShutdown() {
817 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); 852 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN);
818 STLDeleteElements(&prerender_conditions_); 853 STLDeleteElements(&prerender_conditions_);
819 on_close_tab_contents_deleters_.reset(); 854 on_close_tab_contents_deleters_.reset();
820 profile_ = NULL; 855 profile_ = NULL;
821 } 856 }
822 857
823 // private 858 // private
824 bool PrerenderManager::AddPrerender( 859 bool PrerenderManager::AddPrerender(
825 Origin origin, 860 Origin origin,
826 const std::pair<int, int>& child_route_id_pair, 861 int process_id,
827 const GURL& url_arg, 862 const GURL& url_arg,
828 const content::Referrer& referrer, 863 const content::Referrer& referrer,
864 const gfx::Size& size,
829 SessionStorageNamespace* session_storage_namespace) { 865 SessionStorageNamespace* session_storage_namespace) {
830 DCHECK(CalledOnValidThread()); 866 DCHECK(CalledOnValidThread());
831 867
832 if (!IsEnabled()) 868 if (!IsEnabled())
833 return false; 869 return false;
834 870
835 if (origin == ORIGIN_LINK_REL_PRERENDER && 871 if (origin == ORIGIN_LINK_REL_PRERENDER &&
836 IsGoogleSearchResultURL(referrer.url)) { 872 IsGoogleSearchResultURL(referrer.url)) {
837 origin = ORIGIN_GWS_PRERENDER; 873 origin = ORIGIN_GWS_PRERENDER;
838 } 874 }
839 875
840 // If the referring page is prerendering, defer the prerender.
841 PrerenderContentsDataList::iterator source_prerender =
842 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair);
843 if (source_prerender != prerender_list_.end()) {
844 source_prerender->contents_->AddPendingPrerender(
845 origin, url_arg, referrer);
846 return true;
847 }
848
849 DeleteOldEntries(); 876 DeleteOldEntries();
850 DeletePendingDeleteEntries(); 877 DeletePendingDeleteEntries();
851 878
852 GURL url = url_arg; 879 GURL url = url_arg;
853 GURL alias_url; 880 GURL alias_url;
854 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) 881 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url))
855 url = alias_url; 882 url = alias_url;
856 883
857 // From here on, we will record a FinalStatus so we need to register with the 884 // From here on, we will record a FinalStatus so we need to register with the
858 // histogram tracking. 885 // histogram tracking.
859 histograms_->RecordPrerender(origin, url_arg); 886 histograms_->RecordPrerender(origin, url_arg);
860 887
861 uint8 experiment = GetQueryStringBasedExperiment(url_arg); 888 uint8 experiment = GetQueryStringBasedExperiment(url_arg);
862 889
863 if (FindEntry(url)) { 890 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) {
891 ++prerender_contents_data->active_count_;
864 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); 892 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE);
865 return false; 893 return true;
866 } 894 }
867 895
868 // Do not prerender if there are too many render processes, and we would 896 // Do not prerender if there are too many render processes, and we would
869 // have to use an existing one. We do not want prerendering to happen in 897 // have to use an existing one. We do not want prerendering to happen in
870 // a shared process, so that we can always reliably lower the CPU 898 // a shared process, so that we can always reliably lower the CPU
871 // priority for prerendering. 899 // priority for prerendering.
872 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns 900 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns
873 // true, so that case needs to be explicitly checked for. 901 // true, so that case needs to be explicitly checked for.
874 // TODO(tburkard): Figure out how to cancel prerendering in the opposite 902 // TODO(tburkard): Figure out how to cancel prerendering in the opposite
875 // case, when a new tab is added to a process used for prerendering. 903 // case, when a new tab is added to a process used for prerendering.
(...skipping 10 matching lines...) Expand all
886 914
887 // Check if enough time has passed since the last prerender. 915 // Check if enough time has passed since the last prerender.
888 if (!DoesRateLimitAllowPrerender()) { 916 if (!DoesRateLimitAllowPrerender()) {
889 // Cancel the prerender. We could add it to the pending prerender list but 917 // Cancel the prerender. We could add it to the pending prerender list but
890 // this doesn't make sense as the next prerender request will be triggered 918 // this doesn't make sense as the next prerender request will be triggered
891 // by a navigation and is unlikely to be the same site. 919 // by a navigation and is unlikely to be the same site.
892 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); 920 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED);
893 return false; 921 return false;
894 } 922 }
895 923
896 RenderViewHost* source_render_view_host = NULL;
897 if (child_route_id_pair.first != -1) {
898 source_render_view_host =
899 RenderViewHost::FromID(child_route_id_pair.first,
900 child_route_id_pair.second);
901 // Don't prerender page if parent RenderViewHost no longer exists, or it has
902 // no view. The latter should only happen when the RenderView has closed.
903 if (!source_render_view_host || !source_render_view_host->GetView()) {
904 RecordFinalStatus(origin, experiment,
905 FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED);
906 return false;
907 }
908 }
909
910 if (!session_storage_namespace && source_render_view_host) {
911 session_storage_namespace =
912 source_render_view_host->GetSessionStorageNamespace();
913 }
914
915 PrerenderContents* prerender_contents = CreatePrerenderContents( 924 PrerenderContents* prerender_contents = CreatePrerenderContents(
916 url, referrer, origin, experiment); 925 url, referrer, origin, experiment);
917 if (!prerender_contents || !prerender_contents->Init()) 926 if (!prerender_contents || !prerender_contents->Init())
918 return false; 927 return false;
919 928
920 histograms_->RecordPrerenderStarted(origin); 929 histograms_->RecordPrerenderStarted(origin);
921 930
922 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? 931 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
923 PrerenderContentsData data(prerender_contents, GetCurrentTime()); 932 PrerenderContentsData data(prerender_contents, GetCurrentTime());
924 933
925 prerender_list_.push_back(data); 934 prerender_list_.push_back(data);
926 935
927 last_prerender_start_time_ = GetCurrentTimeTicks(); 936 last_prerender_start_time_ = GetCurrentTimeTicks();
928 937
929 if (!IsControlGroup()) { 938 if (!IsControlGroup()) {
930 data.contents_->StartPrerendering(source_render_view_host, 939 data.contents_->StartPrerendering(process_id,
931 session_storage_namespace); 940 size, session_storage_namespace);
932 } 941 }
933 while (prerender_list_.size() > config_.max_elements) { 942 while (prerender_list_.size() > config_.max_elements) {
934 data = prerender_list_.front(); 943 data = prerender_list_.front();
935 prerender_list_.pop_front(); 944 prerender_list_.pop_front();
936 data.contents_->Destroy(FINAL_STATUS_EVICTED); 945 data.contents_->Destroy(FINAL_STATUS_EVICTED);
937 } 946 }
938 StartSchedulingPeriodicCleanups(); 947 StartSchedulingPeriodicCleanups();
939 return true; 948 return true;
940 } 949 }
941 950
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1072 } 1081 }
1073 1082
1074 void PrerenderManager::DeletePendingDeleteEntries() { 1083 void PrerenderManager::DeletePendingDeleteEntries() {
1075 while (!pending_delete_list_.empty()) { 1084 while (!pending_delete_list_.empty()) {
1076 PrerenderContents* contents = pending_delete_list_.front(); 1085 PrerenderContents* contents = pending_delete_list_.front();
1077 pending_delete_list_.pop_front(); 1086 pending_delete_list_.pop_front();
1078 delete contents; 1087 delete contents;
1079 } 1088 }
1080 } 1089 }
1081 1090
1091 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData(
1092 const GURL& url) {
1093 DCHECK(CalledOnValidThread());
1094 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
1095 if (it == prerender_list_.end())
1096 return NULL;
1097 PrerenderContentsData& prerender_contents_data = *it;
1098 return &prerender_contents_data;
1099 }
1100
1082 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const { 1101 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const {
1083 DCHECK(CalledOnValidThread()); 1102 DCHECK(CalledOnValidThread());
1084 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 1103 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
1085 it != prerender_list_.end(); 1104 it != prerender_list_.end();
1086 ++it) { 1105 ++it) {
1087 if (it->contents_->MatchesURL(url, NULL)) 1106 if (it->contents_->MatchesURL(url, NULL))
1088 return it->contents_; 1107 return it->contents_;
1089 } 1108 }
1090 // Entry not found. 1109 // Entry not found.
1091 return NULL; 1110 return NULL;
1092 } 1111 }
1093 1112
1094 std::list<PrerenderManager::PrerenderContentsData>::iterator 1113 PrerenderManager::PrerenderContentsDataList::iterator
1095 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( 1114 PrerenderManager::FindPrerenderContentsForChildRouteIdPair(
1096 const std::pair<int, int>& child_route_id_pair) { 1115 const std::pair<int, int>& child_route_id_pair) {
1097 PrerenderContentsDataList::iterator it = prerender_list_.begin(); 1116 PrerenderContentsDataList::iterator it = prerender_list_.begin();
1098 for (; it != prerender_list_.end(); ++it) { 1117 for (; it != prerender_list_.end(); ++it) {
1099 PrerenderContents* prerender_contents = it->contents_; 1118 PrerenderContents* prerender_contents = it->contents_;
1100 1119
1101 int child_id; 1120 int child_id;
1102 int route_id; 1121 int route_id;
1103 bool has_child_id = prerender_contents->GetChildId(&child_id); 1122 bool has_child_id = prerender_contents->GetChildId(&child_id);
1104 bool has_route_id = has_child_id && 1123 bool has_route_id = has_child_id &&
1105 prerender_contents->GetRouteId(&route_id); 1124 prerender_contents->GetRouteId(&route_id);
1106 1125
1107 if (has_child_id && has_route_id && 1126 if (has_child_id && has_route_id &&
1108 child_id == child_route_id_pair.first && 1127 child_id == child_route_id_pair.first &&
1109 route_id == child_route_id_pair.second) { 1128 route_id == child_route_id_pair.second) {
1110 break; 1129 break;
1111 } 1130 }
1112 } 1131 }
1113 return it; 1132 return it;
1114 } 1133 }
1115 1134
1135 PrerenderManager::PrerenderContentsDataList::iterator
1136 PrerenderManager::FindPrerenderContentsForURL(const GURL& url) {
1137 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
1138 it != prerender_list_.end(); ++it) {
1139 if (it->contents_->MatchesURL(url, NULL))
1140 return it;
1141 }
1142 return prerender_list_.end();
1143 }
1144
1116 bool PrerenderManager::DoesRateLimitAllowPrerender() const { 1145 bool PrerenderManager::DoesRateLimitAllowPrerender() const {
1117 DCHECK(CalledOnValidThread()); 1146 DCHECK(CalledOnValidThread());
1118 base::TimeDelta elapsed_time = 1147 base::TimeDelta elapsed_time =
1119 GetCurrentTimeTicks() - last_prerender_start_time_; 1148 GetCurrentTimeTicks() - last_prerender_start_time_;
1120 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); 1149 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time);
1121 if (!config_.rate_limit_enabled) 1150 if (!config_.rate_limit_enabled)
1122 return true; 1151 return true;
1123 return elapsed_time > 1152 return elapsed_time >
1124 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); 1153 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs);
1125 } 1154 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1240 if (!render_process_host || !render_process_host->GetBrowserContext()) 1269 if (!render_process_host || !render_process_host->GetBrowserContext())
1241 return NULL; 1270 return NULL;
1242 Profile* profile = Profile::FromBrowserContext( 1271 Profile* profile = Profile::FromBrowserContext(
1243 render_process_host->GetBrowserContext()); 1272 render_process_host->GetBrowserContext());
1244 if (!profile) 1273 if (!profile)
1245 return NULL; 1274 return NULL;
1246 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); 1275 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile);
1247 } 1276 }
1248 1277
1249 } // namespace prerender 1278 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698