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 <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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 |
OLD | NEW |