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