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

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: 80 columns 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 } 270 }
267 271
268 void PrerenderManager::Shutdown() { 272 void PrerenderManager::Shutdown() {
269 DoShutdown(); 273 DoShutdown();
270 } 274 }
271 275
272 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( 276 bool PrerenderManager::AddPrerenderFromLinkRelPrerender(
273 int process_id, 277 int process_id,
274 int route_id, 278 int route_id,
275 const GURL& url, 279 const GURL& url,
276 const content::Referrer& referrer) { 280 const content::Referrer& referrer,
281 const gfx::Size& size) {
277 #if defined(OS_ANDROID) 282 #if defined(OS_ANDROID)
278 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable 283 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable
279 // link-prerender and enable omnibox-prerender only. 284 // link-prerender and enable omnibox-prerender only.
280 return false; 285 return false;
281 #else 286 #else
282 std::pair<int, int> child_route_id_pair = std::make_pair(process_id, 287 std::pair<int, int> child_route_id_pair(process_id, route_id);
283 route_id); 288 PrerenderContentsDataList::iterator it =
289 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair);
290 if (it != prerender_list_.end()) {
291 // Instead of prerendering from inside of a running prerender, we will defer
292 // this request until its launcher is made visible.
293 it->contents_->AddPendingPrerender(url, referrer, size);
294 return true;
295 }
284 296
285 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, child_route_id_pair, 297 // Unit tests pass in a process_id == -1.
286 url, referrer, NULL); 298 RenderViewHost* source_render_view_host = NULL;
299 SessionStorageNamespace* session_storage_namespace = NULL;
300 if (process_id != -1) {
301 source_render_view_host =
302 RenderViewHost::FromID(process_id, route_id);
303 if (!source_render_view_host || !source_render_view_host->GetView())
304 return false;
305 session_storage_namespace =
306 source_render_view_host->GetSessionStorageNamespace();
307 }
308
309 return AddPrerender(ORIGIN_LINK_REL_PRERENDER,
310 process_id, url, referrer, size,
311 session_storage_namespace);
287 #endif 312 #endif
288 } 313 }
289 314
290 bool PrerenderManager::AddPrerenderFromOmnibox( 315 bool PrerenderManager::AddPrerenderFromOmnibox(
291 const GURL& url, 316 const GURL& url,
292 SessionStorageNamespace* session_storage_namespace) { 317 SessionStorageNamespace* session_storage_namespace) {
293 if (!IsOmniboxEnabled(profile_)) 318 if (!IsOmniboxEnabled(profile_))
294 return false; 319 return false;
295 return AddPrerender(ORIGIN_OMNIBOX, std::make_pair(-1, -1), url, 320 return AddPrerender(ORIGIN_OMNIBOX, -1, url,
296 content::Referrer(), session_storage_namespace); 321 content::Referrer(), gfx::Size(),
322 session_storage_namespace);
323 }
324
325 void PrerenderManager::MaybeCancelPrerender(const GURL& url) {
326 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
327 if (it == prerender_list_.end())
328 return;
329 PrerenderContentsData& prerender_contents_data = *it;
330 if (--prerender_contents_data.active_count_ == 0)
331 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED);
297 } 332 }
298 333
299 void PrerenderManager::DestroyPrerenderForRenderView( 334 void PrerenderManager::DestroyPrerenderForRenderView(
300 int process_id, int view_id, FinalStatus final_status) { 335 int process_id, int view_id, FinalStatus final_status) {
301 DCHECK(CalledOnValidThread()); 336 DCHECK(CalledOnValidThread());
302 PrerenderContentsDataList::iterator it = 337 PrerenderContentsDataList::iterator it =
303 FindPrerenderContentsForChildRouteIdPair( 338 FindPrerenderContentsForChildRouteIdPair(
304 std::make_pair(process_id, view_id)); 339 std::make_pair(process_id, view_id));
305 if (it != prerender_list_.end()) { 340 if (it != prerender_list_.end()) {
306 PrerenderContents* prerender_contents = it->contents_; 341 PrerenderContents* prerender_contents = it->contents_;
(...skipping 508 matching lines...) Expand 10 before | Expand all | Expand 10 after
815 void PrerenderManager::DoShutdown() { 850 void PrerenderManager::DoShutdown() {
816 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); 851 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN);
817 STLDeleteElements(&prerender_conditions_); 852 STLDeleteElements(&prerender_conditions_);
818 on_close_tab_contents_deleters_.reset(); 853 on_close_tab_contents_deleters_.reset();
819 profile_ = NULL; 854 profile_ = NULL;
820 } 855 }
821 856
822 // private 857 // private
823 bool PrerenderManager::AddPrerender( 858 bool PrerenderManager::AddPrerender(
824 Origin origin, 859 Origin origin,
825 const std::pair<int, int>& child_route_id_pair, 860 int process_id,
826 const GURL& url_arg, 861 const GURL& url_arg,
827 const content::Referrer& referrer, 862 const content::Referrer& referrer,
863 const gfx::Size& size,
828 SessionStorageNamespace* session_storage_namespace) { 864 SessionStorageNamespace* session_storage_namespace) {
829 DCHECK(CalledOnValidThread()); 865 DCHECK(CalledOnValidThread());
830 866
831 if (!IsEnabled()) 867 if (!IsEnabled())
832 return false; 868 return false;
833 869
834 if (origin == ORIGIN_LINK_REL_PRERENDER && 870 if (origin == ORIGIN_LINK_REL_PRERENDER &&
835 IsGoogleSearchResultURL(referrer.url)) { 871 IsGoogleSearchResultURL(referrer.url)) {
836 origin = ORIGIN_GWS_PRERENDER; 872 origin = ORIGIN_GWS_PRERENDER;
837 } 873 }
838 874
839 // If the referring page is prerendering, defer the prerender.
840 PrerenderContentsDataList::iterator source_prerender =
841 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair);
842 if (source_prerender != prerender_list_.end()) {
843 source_prerender->contents_->AddPendingPrerender(
844 origin, url_arg, referrer);
845 return true;
846 }
847
848 DeleteOldEntries(); 875 DeleteOldEntries();
849 DeletePendingDeleteEntries(); 876 DeletePendingDeleteEntries();
850 877
851 GURL url = url_arg; 878 GURL url = url_arg;
852 GURL alias_url; 879 GURL alias_url;
853 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) 880 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url))
854 url = alias_url; 881 url = alias_url;
855 882
856 // From here on, we will record a FinalStatus so we need to register with the 883 // From here on, we will record a FinalStatus so we need to register with the
857 // histogram tracking. 884 // histogram tracking.
858 histograms_->RecordPrerender(origin, url_arg); 885 histograms_->RecordPrerender(origin, url_arg);
859 886
860 uint8 experiment = GetQueryStringBasedExperiment(url_arg); 887 uint8 experiment = GetQueryStringBasedExperiment(url_arg);
861 888
862 if (FindEntry(url)) { 889 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) {
890 ++prerender_contents_data->active_count_;
863 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); 891 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE);
864 return false; 892 return true;
865 } 893 }
866 894
867 // Do not prerender if there are too many render processes, and we would 895 // Do not prerender if there are too many render processes, and we would
868 // have to use an existing one. We do not want prerendering to happen in 896 // have to use an existing one. We do not want prerendering to happen in
869 // a shared process, so that we can always reliably lower the CPU 897 // a shared process, so that we can always reliably lower the CPU
870 // priority for prerendering. 898 // priority for prerendering.
871 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns 899 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns
872 // true, so that case needs to be explicitly checked for. 900 // true, so that case needs to be explicitly checked for.
873 // TODO(tburkard): Figure out how to cancel prerendering in the opposite 901 // TODO(tburkard): Figure out how to cancel prerendering in the opposite
874 // case, when a new tab is added to a process used for prerendering. 902 // case, when a new tab is added to a process used for prerendering.
(...skipping 10 matching lines...) Expand all
885 913
886 // Check if enough time has passed since the last prerender. 914 // Check if enough time has passed since the last prerender.
887 if (!DoesRateLimitAllowPrerender()) { 915 if (!DoesRateLimitAllowPrerender()) {
888 // Cancel the prerender. We could add it to the pending prerender list but 916 // Cancel the prerender. We could add it to the pending prerender list but
889 // this doesn't make sense as the next prerender request will be triggered 917 // this doesn't make sense as the next prerender request will be triggered
890 // by a navigation and is unlikely to be the same site. 918 // by a navigation and is unlikely to be the same site.
891 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); 919 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED);
892 return false; 920 return false;
893 } 921 }
894 922
895 RenderViewHost* source_render_view_host = NULL;
896 if (child_route_id_pair.first != -1) {
897 source_render_view_host =
898 RenderViewHost::FromID(child_route_id_pair.first,
899 child_route_id_pair.second);
900 // Don't prerender page if parent RenderViewHost no longer exists, or it has
901 // no view. The latter should only happen when the RenderView has closed.
902 if (!source_render_view_host || !source_render_view_host->GetView()) {
903 RecordFinalStatus(origin, experiment,
904 FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED);
905 return false;
906 }
907 }
908
909 if (!session_storage_namespace && source_render_view_host) {
910 session_storage_namespace =
911 source_render_view_host->GetSessionStorageNamespace();
912 }
913
914 PrerenderContents* prerender_contents = CreatePrerenderContents( 923 PrerenderContents* prerender_contents = CreatePrerenderContents(
915 url, referrer, origin, experiment); 924 url, referrer, origin, experiment);
916 if (!prerender_contents || !prerender_contents->Init()) 925 if (!prerender_contents || !prerender_contents->Init())
917 return false; 926 return false;
918 927
919 histograms_->RecordPrerenderStarted(origin); 928 histograms_->RecordPrerenderStarted(origin);
920 929
921 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? 930 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
922 PrerenderContentsData data(prerender_contents, GetCurrentTime()); 931 PrerenderContentsData data(prerender_contents, GetCurrentTime());
923 932
924 prerender_list_.push_back(data); 933 prerender_list_.push_back(data);
925 934
926 last_prerender_start_time_ = GetCurrentTimeTicks(); 935 last_prerender_start_time_ = GetCurrentTimeTicks();
927 936
928 if (!IsControlGroup()) { 937 if (!IsControlGroup()) {
929 data.contents_->StartPrerendering(source_render_view_host, 938 data.contents_->StartPrerendering(process_id,
930 session_storage_namespace); 939 size, session_storage_namespace);
931 } 940 }
932 while (prerender_list_.size() > config_.max_elements) { 941 while (prerender_list_.size() > config_.max_elements) {
933 data = prerender_list_.front(); 942 data = prerender_list_.front();
934 prerender_list_.pop_front(); 943 prerender_list_.pop_front();
935 data.contents_->Destroy(FINAL_STATUS_EVICTED); 944 data.contents_->Destroy(FINAL_STATUS_EVICTED);
936 } 945 }
937 StartSchedulingPeriodicCleanups(); 946 StartSchedulingPeriodicCleanups();
938 return true; 947 return true;
939 } 948 }
940 949
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
1071 } 1080 }
1072 1081
1073 void PrerenderManager::DeletePendingDeleteEntries() { 1082 void PrerenderManager::DeletePendingDeleteEntries() {
1074 while (!pending_delete_list_.empty()) { 1083 while (!pending_delete_list_.empty()) {
1075 PrerenderContents* contents = pending_delete_list_.front(); 1084 PrerenderContents* contents = pending_delete_list_.front();
1076 pending_delete_list_.pop_front(); 1085 pending_delete_list_.pop_front();
1077 delete contents; 1086 delete contents;
1078 } 1087 }
1079 } 1088 }
1080 1089
1090 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData(
1091 const GURL& url) {
1092 DCHECK(CalledOnValidThread());
1093 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
1094 if (it == prerender_list_.end())
1095 return NULL;
1096 PrerenderContentsData& prerender_contents_data = *it;
1097 return &prerender_contents_data;
1098 }
1099
1081 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const { 1100 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const {
1082 DCHECK(CalledOnValidThread()); 1101 DCHECK(CalledOnValidThread());
1083 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 1102 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
1084 it != prerender_list_.end(); 1103 it != prerender_list_.end();
1085 ++it) { 1104 ++it) {
1086 if (it->contents_->MatchesURL(url, NULL)) 1105 if (it->contents_->MatchesURL(url, NULL))
1087 return it->contents_; 1106 return it->contents_;
1088 } 1107 }
1089 // Entry not found. 1108 // Entry not found.
1090 return NULL; 1109 return NULL;
1091 } 1110 }
1092 1111
1093 std::list<PrerenderManager::PrerenderContentsData>::iterator 1112 PrerenderManager::PrerenderContentsDataList::iterator
1094 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( 1113 PrerenderManager::FindPrerenderContentsForChildRouteIdPair(
1095 const std::pair<int, int>& child_route_id_pair) { 1114 const std::pair<int, int>& child_route_id_pair) {
1096 PrerenderContentsDataList::iterator it = prerender_list_.begin(); 1115 PrerenderContentsDataList::iterator it = prerender_list_.begin();
1097 for (; it != prerender_list_.end(); ++it) { 1116 for (; it != prerender_list_.end(); ++it) {
1098 PrerenderContents* prerender_contents = it->contents_; 1117 PrerenderContents* prerender_contents = it->contents_;
1099 1118
1100 int child_id; 1119 int child_id;
1101 int route_id; 1120 int route_id;
1102 bool has_child_id = prerender_contents->GetChildId(&child_id); 1121 bool has_child_id = prerender_contents->GetChildId(&child_id);
1103 bool has_route_id = has_child_id && 1122 bool has_route_id = has_child_id &&
1104 prerender_contents->GetRouteId(&route_id); 1123 prerender_contents->GetRouteId(&route_id);
1105 1124
1106 if (has_child_id && has_route_id && 1125 if (has_child_id && has_route_id &&
1107 child_id == child_route_id_pair.first && 1126 child_id == child_route_id_pair.first &&
1108 route_id == child_route_id_pair.second) { 1127 route_id == child_route_id_pair.second) {
1109 break; 1128 break;
1110 } 1129 }
1111 } 1130 }
1112 return it; 1131 return it;
1113 } 1132 }
1114 1133
1134 PrerenderManager::PrerenderContentsDataList::iterator
1135 PrerenderManager::FindPrerenderContentsForURL(const GURL& url) {
1136 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
1137 it != prerender_list_.end(); ++it) {
1138 if (it->contents_->MatchesURL(url, NULL))
1139 return it;
1140 }
1141 return prerender_list_.end();
1142 }
1143
1115 bool PrerenderManager::DoesRateLimitAllowPrerender() const { 1144 bool PrerenderManager::DoesRateLimitAllowPrerender() const {
1116 DCHECK(CalledOnValidThread()); 1145 DCHECK(CalledOnValidThread());
1117 base::TimeDelta elapsed_time = 1146 base::TimeDelta elapsed_time =
1118 GetCurrentTimeTicks() - last_prerender_start_time_; 1147 GetCurrentTimeTicks() - last_prerender_start_time_;
1119 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); 1148 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time);
1120 if (!config_.rate_limit_enabled) 1149 if (!config_.rate_limit_enabled)
1121 return true; 1150 return true;
1122 return elapsed_time > 1151 return elapsed_time >
1123 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); 1152 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs);
1124 } 1153 }
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
1239 if (!render_process_host || !render_process_host->GetBrowserContext()) 1268 if (!render_process_host || !render_process_host->GetBrowserContext())
1240 return NULL; 1269 return NULL;
1241 Profile* profile = Profile::FromBrowserContext( 1270 Profile* profile = Profile::FromBrowserContext(
1242 render_process_host->GetBrowserContext()); 1271 render_process_host->GetBrowserContext());
1243 if (!profile) 1272 if (!profile)
1244 return NULL; 1273 return NULL;
1245 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); 1274 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile);
1246 } 1275 }
1247 1276
1248 } // namespace prerender 1277 } // namespace prerender
OLDNEW
« no previous file with comments | « chrome/browser/prerender/prerender_manager.h ('k') | chrome/browser/prerender/prerender_manager_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698