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

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: remediate to dominich review 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,
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);
mmenke 2012/04/30 18:35:22 Random comment: Should we track size as well? Si
gavinp 2012/04/30 23:55:39 Fair point. Done. I suspect this all changes a b
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(),
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.active_count_ == 0)
320 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED);
298 } 321 }
299 322
300 void PrerenderManager::DestroyPrerenderForRenderView( 323 void PrerenderManager::DestroyPrerenderForRenderView(
301 int process_id, int view_id, FinalStatus final_status) { 324 int process_id, int view_id, FinalStatus final_status) {
302 DCHECK(CalledOnValidThread()); 325 DCHECK(CalledOnValidThread());
303 PrerenderContentsDataList::iterator it = 326 PrerenderContentsDataList::iterator it =
304 FindPrerenderContentsForChildRouteIdPair( 327 FindPrerenderContentsForChildRouteIdPair(
305 std::make_pair(process_id, view_id)); 328 std::make_pair(process_id, view_id));
306 if (it != prerender_list_.end()) { 329 if (it != prerender_list_.end()) {
307 PrerenderContents* prerender_contents = it->contents_; 330 PrerenderContents* prerender_contents = it->contents_;
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after
816 void PrerenderManager::DoShutdown() { 839 void PrerenderManager::DoShutdown() {
817 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); 840 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN);
818 STLDeleteElements(&prerender_conditions_); 841 STLDeleteElements(&prerender_conditions_);
819 on_close_tab_contents_deleters_.reset(); 842 on_close_tab_contents_deleters_.reset();
820 profile_ = NULL; 843 profile_ = NULL;
821 } 844 }
822 845
823 // private 846 // private
824 bool PrerenderManager::AddPrerender( 847 bool PrerenderManager::AddPrerender(
825 Origin origin, 848 Origin origin,
826 const std::pair<int, int>& child_route_id_pair, 849 int process_id,
827 const GURL& url_arg, 850 const GURL& url_arg,
828 const content::Referrer& referrer, 851 const content::Referrer& referrer,
852 const gfx::Size& size,
829 SessionStorageNamespace* session_storage_namespace) { 853 SessionStorageNamespace* session_storage_namespace) {
830 DCHECK(CalledOnValidThread()); 854 DCHECK(CalledOnValidThread());
831 855
832 if (!IsEnabled()) 856 if (!IsEnabled())
833 return false; 857 return false;
834 858
835 if (origin == ORIGIN_LINK_REL_PRERENDER && 859 if (origin == ORIGIN_LINK_REL_PRERENDER &&
836 IsGoogleSearchResultURL(referrer.url)) { 860 IsGoogleSearchResultURL(referrer.url)) {
837 origin = ORIGIN_GWS_PRERENDER; 861 origin = ORIGIN_GWS_PRERENDER;
838 } 862 }
839 863
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(); 864 DeleteOldEntries();
850 DeletePendingDeleteEntries(); 865 DeletePendingDeleteEntries();
851 866
852 GURL url = url_arg; 867 GURL url = url_arg;
853 GURL alias_url; 868 GURL alias_url;
854 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) 869 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url))
855 url = alias_url; 870 url = alias_url;
856 871
857 // From here on, we will record a FinalStatus so we need to register with the 872 // From here on, we will record a FinalStatus so we need to register with the
858 // histogram tracking. 873 // histogram tracking.
859 histograms_->RecordPrerender(origin, url_arg); 874 histograms_->RecordPrerender(origin, url_arg);
860 875
861 uint8 experiment = GetQueryStringBasedExperiment(url_arg); 876 uint8 experiment = GetQueryStringBasedExperiment(url_arg);
862 877
863 if (FindEntry(url)) { 878 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) {
879 ++prerender_contents_data->active_count_;
864 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); 880 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE);
865 return false; 881 return true;
866 } 882 }
867 883
868 // Do not prerender if there are too many render processes, and we would 884 // 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 885 // 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 886 // a shared process, so that we can always reliably lower the CPU
871 // priority for prerendering. 887 // priority for prerendering.
872 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns 888 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns
873 // true, so that case needs to be explicitly checked for. 889 // true, so that case needs to be explicitly checked for.
874 // TODO(tburkard): Figure out how to cancel prerendering in the opposite 890 // 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. 891 // case, when a new tab is added to a process used for prerendering.
(...skipping 10 matching lines...) Expand all
886 902
887 // Check if enough time has passed since the last prerender. 903 // Check if enough time has passed since the last prerender.
888 if (!DoesRateLimitAllowPrerender()) { 904 if (!DoesRateLimitAllowPrerender()) {
889 // Cancel the prerender. We could add it to the pending prerender list but 905 // 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 906 // 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. 907 // by a navigation and is unlikely to be the same site.
892 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); 908 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED);
893 return false; 909 return false;
894 } 910 }
895 911
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( 912 PrerenderContents* prerender_contents = CreatePrerenderContents(
916 url, referrer, origin, experiment); 913 url, referrer, origin, experiment);
917 if (!prerender_contents || !prerender_contents->Init()) 914 if (!prerender_contents || !prerender_contents->Init())
918 return false; 915 return false;
919 916
920 histograms_->RecordPrerenderStarted(origin); 917 histograms_->RecordPrerenderStarted(origin);
921 918
922 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? 919 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
923 PrerenderContentsData data(prerender_contents, GetCurrentTime()); 920 PrerenderContentsData data(prerender_contents, GetCurrentTime());
924 921
925 prerender_list_.push_back(data); 922 prerender_list_.push_back(data);
926 923
927 last_prerender_start_time_ = GetCurrentTimeTicks(); 924 last_prerender_start_time_ = GetCurrentTimeTicks();
928 925
929 if (!IsControlGroup()) { 926 if (!IsControlGroup()) {
930 data.contents_->StartPrerendering(source_render_view_host, 927 data.contents_->StartPrerendering(process_id,
931 session_storage_namespace); 928 size, session_storage_namespace);
932 } 929 }
933 while (prerender_list_.size() > config_.max_elements) { 930 while (prerender_list_.size() > config_.max_elements) {
934 data = prerender_list_.front(); 931 data = prerender_list_.front();
935 prerender_list_.pop_front(); 932 prerender_list_.pop_front();
936 data.contents_->Destroy(FINAL_STATUS_EVICTED); 933 data.contents_->Destroy(FINAL_STATUS_EVICTED);
937 } 934 }
938 StartSchedulingPeriodicCleanups(); 935 StartSchedulingPeriodicCleanups();
939 return true; 936 return true;
940 } 937 }
941 938
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1072 } 1069 }
1073 1070
1074 void PrerenderManager::DeletePendingDeleteEntries() { 1071 void PrerenderManager::DeletePendingDeleteEntries() {
1075 while (!pending_delete_list_.empty()) { 1072 while (!pending_delete_list_.empty()) {
1076 PrerenderContents* contents = pending_delete_list_.front(); 1073 PrerenderContents* contents = pending_delete_list_.front();
1077 pending_delete_list_.pop_front(); 1074 pending_delete_list_.pop_front();
1078 delete contents; 1075 delete contents;
1079 } 1076 }
1080 } 1077 }
1081 1078
1079 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData(
1080 const GURL& url) {
1081 DCHECK(CalledOnValidThread());
1082 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
1083 if (it == prerender_list_.end())
1084 return NULL;
1085 return address_of(*it);
1086 }
1087
1082 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const { 1088 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const {
1083 DCHECK(CalledOnValidThread()); 1089 DCHECK(CalledOnValidThread());
1084 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 1090 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
1085 it != prerender_list_.end(); 1091 it != prerender_list_.end();
1086 ++it) { 1092 ++it) {
1087 if (it->contents_->MatchesURL(url, NULL)) 1093 if (it->contents_->MatchesURL(url, NULL))
1088 return it->contents_; 1094 return it->contents_;
1089 } 1095 }
1090 // Entry not found. 1096 // Entry not found.
1091 return NULL; 1097 return NULL;
1092 } 1098 }
1093 1099
1094 std::list<PrerenderManager::PrerenderContentsData>::iterator 1100 PrerenderManager::PrerenderContentsDataList::iterator
1095 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( 1101 PrerenderManager::FindPrerenderContentsForChildRouteIdPair(
1096 const std::pair<int, int>& child_route_id_pair) { 1102 const std::pair<int, int>& child_route_id_pair) {
1097 PrerenderContentsDataList::iterator it = prerender_list_.begin(); 1103 PrerenderContentsDataList::iterator it = prerender_list_.begin();
1098 for (; it != prerender_list_.end(); ++it) { 1104 for (; it != prerender_list_.end(); ++it) {
1099 PrerenderContents* prerender_contents = it->contents_; 1105 PrerenderContents* prerender_contents = it->contents_;
1100 1106
1101 int child_id; 1107 int child_id;
1102 int route_id; 1108 int route_id;
1103 bool has_child_id = prerender_contents->GetChildId(&child_id); 1109 bool has_child_id = prerender_contents->GetChildId(&child_id);
1104 bool has_route_id = has_child_id && 1110 bool has_route_id = has_child_id &&
1105 prerender_contents->GetRouteId(&route_id); 1111 prerender_contents->GetRouteId(&route_id);
1106 1112
1107 if (has_child_id && has_route_id && 1113 if (has_child_id && has_route_id &&
1108 child_id == child_route_id_pair.first && 1114 child_id == child_route_id_pair.first &&
1109 route_id == child_route_id_pair.second) { 1115 route_id == child_route_id_pair.second) {
1110 break; 1116 break;
1111 } 1117 }
1112 } 1118 }
1113 return it; 1119 return it;
1114 } 1120 }
1115 1121
1122 PrerenderManager::PrerenderContentsDataList::iterator
1123 PrerenderManager::FindPrerenderContentsForURL(const GURL& url) {
1124 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
1125 it != prerender_list_.end(); ++it) {
1126 if (it->contents_->MatchesURL(url, NULL))
1127 return it;
1128 }
1129 return prerender_list_.end();
1130 }
1131
1116 bool PrerenderManager::DoesRateLimitAllowPrerender() const { 1132 bool PrerenderManager::DoesRateLimitAllowPrerender() const {
1117 DCHECK(CalledOnValidThread()); 1133 DCHECK(CalledOnValidThread());
1118 base::TimeDelta elapsed_time = 1134 base::TimeDelta elapsed_time =
1119 GetCurrentTimeTicks() - last_prerender_start_time_; 1135 GetCurrentTimeTicks() - last_prerender_start_time_;
1120 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); 1136 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time);
1121 if (!config_.rate_limit_enabled) 1137 if (!config_.rate_limit_enabled)
1122 return true; 1138 return true;
1123 return elapsed_time > 1139 return elapsed_time >
1124 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); 1140 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs);
1125 } 1141 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1240 if (!render_process_host || !render_process_host->GetBrowserContext()) 1256 if (!render_process_host || !render_process_host->GetBrowserContext())
1241 return NULL; 1257 return NULL;
1242 Profile* profile = Profile::FromBrowserContext( 1258 Profile* profile = Profile::FromBrowserContext(
1243 render_process_host->GetBrowserContext()); 1259 render_process_host->GetBrowserContext());
1244 if (!profile) 1260 if (!profile)
1245 return NULL; 1261 return NULL;
1246 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); 1262 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile);
1247 } 1263 }
1248 1264
1249 } // namespace prerender 1265 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698