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

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: remove the urls_to_id_map_, and follow consequences through. 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 add_count_;
dominich 2012/04/29 18:52:55 active_count_?
gavinp 2012/04/30 11:43:16 Done.
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 add_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,
283 SessionStorageNamespace* session_storage_namespace) {
278 #if defined(OS_ANDROID) 284 #if defined(OS_ANDROID)
279 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable 285 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable
280 // link-prerender and enable omnibox-prerender only. 286 // link-prerender and enable omnibox-prerender only.
281 return false; 287 return false;
282 #else 288 #else
283 std::pair<int, int> child_route_id_pair = std::make_pair(process_id, 289 std::pair<int, int> child_route_id_pair(process_id, route_id);
284 route_id); 290 PrerenderContentsDataList::iterator it =
285 291 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair);
286 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, child_route_id_pair, 292 if (it != prerender_list_.end()) {
287 url, referrer, NULL); 293 // Instead of prerendering from inside of a running prerender, we will defer
294 // this request until its launcher is made visible.
295 it->contents_->AddPendingPrerender(url, referrer);
296 return true;
297 }
298 return AddPrerender(ORIGIN_LINK_REL_PRERENDER,
299 process_id, url, referrer, size,
300 session_storage_namespace);
288 #endif 301 #endif
289 } 302 }
290 303
291 bool PrerenderManager::AddPrerenderFromOmnibox( 304 bool PrerenderManager::AddPrerenderFromOmnibox(
292 const GURL& url, 305 const GURL& url,
293 SessionStorageNamespace* session_storage_namespace) { 306 SessionStorageNamespace* session_storage_namespace) {
294 if (!IsOmniboxEnabled(profile_)) 307 if (!IsOmniboxEnabled(profile_))
295 return false; 308 return false;
296 return AddPrerender(ORIGIN_OMNIBOX, std::make_pair(-1, -1), url, 309 return AddPrerender(ORIGIN_OMNIBOX, -1, url,
297 content::Referrer(), session_storage_namespace); 310 content::Referrer(), gfx::Size(0, 0),
311 session_storage_namespace);
312 }
313
314 void PrerenderManager::MaybeCancelPrerender(const GURL& url) {
315 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
316 if (it == prerender_list_.end())
317 return;
318 PrerenderContentsData& prerender_contents_data = *it;
319 if (--prerender_contents_data.add_count_ > 0)
dominich 2012/04/29 18:52:55 why not: if (--prerender_contents_data.add_count_
gavinp 2012/04/30 11:43:16 Done.
320 return;
321 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED);
298 } 322 }
299 323
300 void PrerenderManager::DestroyPrerenderForRenderView( 324 void PrerenderManager::DestroyPrerenderForRenderView(
301 int process_id, int view_id, FinalStatus final_status) { 325 int process_id, int view_id, FinalStatus final_status) {
302 DCHECK(CalledOnValidThread()); 326 DCHECK(CalledOnValidThread());
303 PrerenderContentsDataList::iterator it = 327 PrerenderContentsDataList::iterator it =
304 FindPrerenderContentsForChildRouteIdPair( 328 FindPrerenderContentsForChildRouteIdPair(
305 std::make_pair(process_id, view_id)); 329 std::make_pair(process_id, view_id));
306 if (it != prerender_list_.end()) { 330 if (it != prerender_list_.end()) {
307 PrerenderContents* prerender_contents = it->contents_; 331 PrerenderContents* prerender_contents = it->contents_;
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after
816 void PrerenderManager::DoShutdown() { 840 void PrerenderManager::DoShutdown() {
817 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); 841 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN);
818 STLDeleteElements(&prerender_conditions_); 842 STLDeleteElements(&prerender_conditions_);
819 on_close_tab_contents_deleters_.reset(); 843 on_close_tab_contents_deleters_.reset();
820 profile_ = NULL; 844 profile_ = NULL;
821 } 845 }
822 846
823 // private 847 // private
824 bool PrerenderManager::AddPrerender( 848 bool PrerenderManager::AddPrerender(
825 Origin origin, 849 Origin origin,
826 const std::pair<int, int>& child_route_id_pair, 850 int process_id,
827 const GURL& url_arg, 851 const GURL& url_arg,
828 const content::Referrer& referrer, 852 const content::Referrer& referrer,
853 const gfx::Size& size,
829 SessionStorageNamespace* session_storage_namespace) { 854 SessionStorageNamespace* session_storage_namespace) {
830 DCHECK(CalledOnValidThread()); 855 DCHECK(CalledOnValidThread());
831 856
832 if (!IsEnabled()) 857 if (!IsEnabled())
833 return false; 858 return false;
834 859
835 if (origin == ORIGIN_LINK_REL_PRERENDER && 860 if (origin == ORIGIN_LINK_REL_PRERENDER &&
836 IsGoogleSearchResultURL(referrer.url)) { 861 IsGoogleSearchResultURL(referrer.url)) {
837 origin = ORIGIN_GWS_PRERENDER; 862 origin = ORIGIN_GWS_PRERENDER;
838 } 863 }
839 864
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(); 865 DeleteOldEntries();
850 DeletePendingDeleteEntries(); 866 DeletePendingDeleteEntries();
851 867
852 GURL url = url_arg; 868 GURL url = url_arg;
853 GURL alias_url; 869 GURL alias_url;
854 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) 870 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url))
855 url = alias_url; 871 url = alias_url;
856 872
857 // From here on, we will record a FinalStatus so we need to register with the 873 // From here on, we will record a FinalStatus so we need to register with the
858 // histogram tracking. 874 // histogram tracking.
859 histograms_->RecordPrerender(origin, url_arg); 875 histograms_->RecordPrerender(origin, url_arg);
860 876
861 uint8 experiment = GetQueryStringBasedExperiment(url_arg); 877 uint8 experiment = GetQueryStringBasedExperiment(url_arg);
862 878
863 if (FindEntry(url)) { 879 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) {
880 ++prerender_contents_data->add_count_;
864 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); 881 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE);
dominich 2012/04/29 18:52:55 this is going to mess with the stats. If the prere
gavinp 2012/04/30 11:43:16 Isn't this already exactly the case on pages that
dominich 2012/04/30 15:52:05 You're correct, but we do have to be careful with
865 return false; 882 return true;
866 } 883 }
867 884
868 // Do not prerender if there are too many render processes, and we would 885 // 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 886 // 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 887 // a shared process, so that we can always reliably lower the CPU
871 // priority for prerendering. 888 // priority for prerendering.
872 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns 889 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns
873 // true, so that case needs to be explicitly checked for. 890 // true, so that case needs to be explicitly checked for.
874 // TODO(tburkard): Figure out how to cancel prerendering in the opposite 891 // 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. 892 // case, when a new tab is added to a process used for prerendering.
(...skipping 10 matching lines...) Expand all
886 903
887 // Check if enough time has passed since the last prerender. 904 // Check if enough time has passed since the last prerender.
888 if (!DoesRateLimitAllowPrerender()) { 905 if (!DoesRateLimitAllowPrerender()) {
889 // Cancel the prerender. We could add it to the pending prerender list but 906 // 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 907 // 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. 908 // by a navigation and is unlikely to be the same site.
892 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); 909 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED);
893 return false; 910 return false;
894 } 911 }
895 912
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( 913 PrerenderContents* prerender_contents = CreatePrerenderContents(
916 url, referrer, origin, experiment); 914 url, referrer, origin, experiment);
917 if (!prerender_contents || !prerender_contents->Init()) 915 if (!prerender_contents || !prerender_contents->Init())
918 return false; 916 return false;
919 917
920 histograms_->RecordPrerenderStarted(origin); 918 histograms_->RecordPrerenderStarted(origin);
921 919
922 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? 920 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
923 PrerenderContentsData data(prerender_contents, GetCurrentTime()); 921 PrerenderContentsData data(prerender_contents, GetCurrentTime());
924 922
925 prerender_list_.push_back(data); 923 prerender_list_.push_back(data);
926 924
927 last_prerender_start_time_ = GetCurrentTimeTicks(); 925 last_prerender_start_time_ = GetCurrentTimeTicks();
928 926
929 if (!IsControlGroup()) { 927 if (!IsControlGroup()) {
930 data.contents_->StartPrerendering(source_render_view_host, 928 data.contents_->StartPrerendering(process_id,
931 session_storage_namespace); 929 size, session_storage_namespace);
932 } 930 }
933 while (prerender_list_.size() > config_.max_elements) { 931 while (prerender_list_.size() > config_.max_elements) {
934 data = prerender_list_.front(); 932 data = prerender_list_.front();
935 prerender_list_.pop_front(); 933 prerender_list_.pop_front();
936 data.contents_->Destroy(FINAL_STATUS_EVICTED); 934 data.contents_->Destroy(FINAL_STATUS_EVICTED);
937 } 935 }
938 StartSchedulingPeriodicCleanups(); 936 StartSchedulingPeriodicCleanups();
939 return true; 937 return true;
940 } 938 }
941 939
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1072 } 1070 }
1073 1071
1074 void PrerenderManager::DeletePendingDeleteEntries() { 1072 void PrerenderManager::DeletePendingDeleteEntries() {
1075 while (!pending_delete_list_.empty()) { 1073 while (!pending_delete_list_.empty()) {
1076 PrerenderContents* contents = pending_delete_list_.front(); 1074 PrerenderContents* contents = pending_delete_list_.front();
1077 pending_delete_list_.pop_front(); 1075 pending_delete_list_.pop_front();
1078 delete contents; 1076 delete contents;
1079 } 1077 }
1080 } 1078 }
1081 1079
1080 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData(
1081 const GURL& url) {
1082 DCHECK(CalledOnValidThread());
1083 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
1084 if (it == prerender_list_.end())
1085 return NULL;
1086 return address_of(*it);
1087 }
1088
1082 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const { 1089 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const {
1083 DCHECK(CalledOnValidThread()); 1090 DCHECK(CalledOnValidThread());
1084 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 1091 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
1085 it != prerender_list_.end(); 1092 it != prerender_list_.end();
1086 ++it) { 1093 ++it) {
1087 if (it->contents_->MatchesURL(url, NULL)) 1094 if (it->contents_->MatchesURL(url, NULL))
1088 return it->contents_; 1095 return it->contents_;
1089 } 1096 }
1090 // Entry not found. 1097 // Entry not found.
1091 return NULL; 1098 return NULL;
1092 } 1099 }
1093 1100
1094 std::list<PrerenderManager::PrerenderContentsData>::iterator 1101 PrerenderManager::PrerenderContentsDataList::iterator
1095 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( 1102 PrerenderManager::FindPrerenderContentsForChildRouteIdPair(
1096 const std::pair<int, int>& child_route_id_pair) { 1103 const std::pair<int, int>& child_route_id_pair) {
1097 PrerenderContentsDataList::iterator it = prerender_list_.begin(); 1104 PrerenderContentsDataList::iterator it = prerender_list_.begin();
1098 for (; it != prerender_list_.end(); ++it) { 1105 for (; it != prerender_list_.end(); ++it) {
1099 PrerenderContents* prerender_contents = it->contents_; 1106 PrerenderContents* prerender_contents = it->contents_;
1100 1107
1101 int child_id; 1108 int child_id;
1102 int route_id; 1109 int route_id;
1103 bool has_child_id = prerender_contents->GetChildId(&child_id); 1110 bool has_child_id = prerender_contents->GetChildId(&child_id);
1104 bool has_route_id = has_child_id && 1111 bool has_route_id = has_child_id &&
1105 prerender_contents->GetRouteId(&route_id); 1112 prerender_contents->GetRouteId(&route_id);
1106 1113
1107 if (has_child_id && has_route_id && 1114 if (has_child_id && has_route_id &&
1108 child_id == child_route_id_pair.first && 1115 child_id == child_route_id_pair.first &&
1109 route_id == child_route_id_pair.second) { 1116 route_id == child_route_id_pair.second) {
1110 break; 1117 break;
1111 } 1118 }
1112 } 1119 }
1113 return it; 1120 return it;
1114 } 1121 }
1115 1122
1123 PrerenderManager::PrerenderContentsDataList::iterator
1124 PrerenderManager::FindPrerenderContentsForURL(const GURL& url) {
1125 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
1126 it != prerender_list_.end(); ++it) {
1127 if (it->contents_->MatchesURL(url, NULL))
1128 return it;
1129 }
1130 return prerender_list_.end();
1131 }
1132
1116 bool PrerenderManager::DoesRateLimitAllowPrerender() const { 1133 bool PrerenderManager::DoesRateLimitAllowPrerender() const {
1117 DCHECK(CalledOnValidThread()); 1134 DCHECK(CalledOnValidThread());
1118 base::TimeDelta elapsed_time = 1135 base::TimeDelta elapsed_time =
1119 GetCurrentTimeTicks() - last_prerender_start_time_; 1136 GetCurrentTimeTicks() - last_prerender_start_time_;
1120 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); 1137 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time);
1121 if (!config_.rate_limit_enabled) 1138 if (!config_.rate_limit_enabled)
1122 return true; 1139 return true;
1123 return elapsed_time > 1140 return elapsed_time >
1124 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); 1141 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs);
1125 } 1142 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1240 if (!render_process_host || !render_process_host->GetBrowserContext()) 1257 if (!render_process_host || !render_process_host->GetBrowserContext())
1241 return NULL; 1258 return NULL;
1242 Profile* profile = Profile::FromBrowserContext( 1259 Profile* profile = Profile::FromBrowserContext(
1243 render_process_host->GetBrowserContext()); 1260 render_process_host->GetBrowserContext());
1244 if (!profile) 1261 if (!profile)
1245 return NULL; 1262 return NULL;
1246 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); 1263 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile);
1247 } 1264 }
1248 1265
1249 } // namespace prerender 1266 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698