Chromium Code Reviews| 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 <set> |
| 8 #include <string> | 8 #include <string> |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/bind.h" | 11 #include "base/bind.h" |
| 12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
| 13 #include "base/logging.h" | 13 #include "base/logging.h" |
| 14 #include "base/memory/weak_ptr.h" | 14 #include "base/memory/weak_ptr.h" |
| 15 #include "base/metrics/histogram.h" | 15 #include "base/metrics/histogram.h" |
| 16 #include "base/stl_util.h" | 16 #include "base/stl_util.h" |
| 17 #include "base/time.h" | 17 #include "base/time.h" |
| 18 #include "base/utf_string_conversions.h" | 18 #include "base/utf_string_conversions.h" |
| 19 #include "base/values.h" | 19 #include "base/values.h" |
| 20 #include "chrome/browser/browser_process.h" | 20 #include "chrome/browser/browser_process.h" |
| 21 #include "chrome/browser/cancelable_request.h" | 21 #include "chrome/browser/cancelable_request.h" |
| 22 #include "chrome/browser/favicon/favicon_tab_helper.h" | 22 #include "chrome/browser/favicon/favicon_tab_helper.h" |
| 23 #include "chrome/browser/prerender/prerender_condition.h" | 23 #include "chrome/browser/prerender/prerender_condition.h" |
| 24 #include "chrome/browser/prerender/prerender_contents.h" | 24 #include "chrome/browser/prerender/prerender_contents.h" |
| 25 #include "chrome/browser/prerender/prerender_field_trial.h" | 25 #include "chrome/browser/prerender/prerender_field_trial.h" |
| 26 #include "chrome/browser/prerender/prerender_final_status.h" | 26 #include "chrome/browser/prerender/prerender_final_status.h" |
| 27 #include "chrome/browser/prerender/prerender_handle.h" | |
| 27 #include "chrome/browser/prerender/prerender_histograms.h" | 28 #include "chrome/browser/prerender/prerender_histograms.h" |
| 28 #include "chrome/browser/prerender/prerender_history.h" | 29 #include "chrome/browser/prerender/prerender_history.h" |
| 29 #include "chrome/browser/prerender/prerender_local_predictor.h" | 30 #include "chrome/browser/prerender/prerender_local_predictor.h" |
| 30 #include "chrome/browser/prerender/prerender_manager_factory.h" | 31 #include "chrome/browser/prerender/prerender_manager_factory.h" |
| 31 #include "chrome/browser/prerender/prerender_tab_helper.h" | 32 #include "chrome/browser/prerender/prerender_tab_helper.h" |
| 32 #include "chrome/browser/prerender/prerender_tracker.h" | 33 #include "chrome/browser/prerender/prerender_tracker.h" |
| 33 #include "chrome/browser/prerender/prerender_util.h" | 34 #include "chrome/browser/prerender/prerender_util.h" |
| 34 #include "chrome/browser/profiles/profile.h" | 35 #include "chrome/browser/profiles/profile.h" |
| 35 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" | 36 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" |
| 36 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" | 37 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 52 | 53 |
| 53 using content::BrowserThread; | 54 using content::BrowserThread; |
| 54 using content::RenderViewHost; | 55 using content::RenderViewHost; |
| 55 using content::SessionStorageNamespace; | 56 using content::SessionStorageNamespace; |
| 56 using content::WebContents; | 57 using content::WebContents; |
| 57 | 58 |
| 58 namespace prerender { | 59 namespace prerender { |
| 59 | 60 |
| 60 namespace { | 61 namespace { |
| 61 | 62 |
| 62 // Time window for which we will record windowed PLT's from the last | |
| 63 // observed link rel=prefetch tag. | |
| 64 const int kWindowDurationSeconds = 30; | |
| 65 | |
| 66 // Time interval at which periodic cleanups are performed. | |
| 67 const int kPeriodicCleanupIntervalMs = 1000; | |
| 68 | |
| 69 // Time interval before a new prerender is allowed. | |
| 70 const int kMinTimeBetweenPrerendersMs = 500; | |
| 71 | |
| 72 // Valid HTTP methods for prerendering. | |
| 73 const char* const kValidHttpMethods[] = { | |
| 74 "GET", | |
| 75 "HEAD", | |
| 76 "OPTIONS", | |
| 77 "POST", | |
| 78 "TRACE", | |
| 79 }; | |
| 80 | |
| 81 // Length of prerender history, for display in chrome://net-internals | |
| 82 const int kHistoryLength = 100; | |
| 83 | |
| 84 // Indicates whether a Prerender has been cancelled such that we need | 63 // Indicates whether a Prerender has been cancelled such that we need |
| 85 // a dummy replacement for the purpose of recording the correct PPLT for | 64 // a dummy replacement for the purpose of recording the correct PPLT for |
| 86 // the Match Complete case. | 65 // the Match Complete case. |
| 87 // Traditionally, "Match" means that a prerendered page was actually visited & | 66 // Traditionally, "Match" means that a prerendered page was actually visited & |
| 88 // the prerender was used. Our goal is to have "Match" cases line up in the | 67 // the prerender was used. Our goal is to have "Match" cases line up in the |
| 89 // control group & the experiment group, so that we can make meaningful | 68 // control group & the experiment group, so that we can make meaningful |
| 90 // comparisons of improvements. However, in the control group, since we don't | 69 // comparisons of improvements. However, in the control group, since we don't |
| 91 // actually perform prerenders, many of the cancellation reasons cannot be | 70 // actually perform prerenders, many of the cancellation reasons cannot be |
| 92 // detected. Therefore, in the Prerender group, when we cancel for one of these | 71 // detected. Therefore, in the Prerender group, when we cancel for one of these |
| 93 // reasons, we keep track of a dummy Prerender representing what we would | 72 // reasons, we keep track of a dummy Prerender representing what we would |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 106 final_status != FINAL_STATUS_APP_TERMINATING && | 85 final_status != FINAL_STATUS_APP_TERMINATING && |
| 107 final_status != FINAL_STATUS_WINDOW_OPENER && | 86 final_status != FINAL_STATUS_WINDOW_OPENER && |
| 108 final_status != FINAL_STATUS_FRAGMENT_MISMATCH && | 87 final_status != FINAL_STATUS_FRAGMENT_MISMATCH && |
| 109 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED && | 88 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED && |
| 110 final_status != FINAL_STATUS_CANCELLED && | 89 final_status != FINAL_STATUS_CANCELLED && |
| 111 final_status != FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH && | 90 final_status != FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH && |
| 112 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED && | 91 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED && |
| 113 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING; | 92 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING; |
| 114 } | 93 } |
| 115 | 94 |
| 95 // Time window for which we will record windowed PLT's from the last | |
| 96 // observed link rel=prefetch tag. | |
| 97 const int kWindowDurationSeconds = 30; | |
| 98 | |
| 99 // Time interval at which periodic cleanups are performed. | |
| 100 const int kPeriodicCleanupIntervalMs = 1000; | |
| 101 | |
| 102 // Time interval before a new prerender is allowed. | |
| 103 const int kMinTimeBetweenPrerendersMs = 500; | |
| 104 | |
| 105 // Valid HTTP methods for prerendering. | |
| 106 const char* const kValidHttpMethods[] = { | |
| 107 "GET", | |
| 108 "HEAD", | |
| 109 "OPTIONS", | |
| 110 "POST", | |
| 111 "TRACE", | |
| 112 }; | |
| 113 | |
| 114 // Length of prerender history, for display in chrome://net-internals | |
| 115 const int kHistoryLength = 100; | |
|
mmenke
2012/06/22 16:12:45
nit: In cc files, the general style is to put con
| |
| 116 | |
| 116 } // namespace | 117 } // namespace |
| 117 | 118 |
| 118 class PrerenderManager::OnCloseTabContentsDeleter | 119 class PrerenderManager::OnCloseTabContentsDeleter |
| 119 : public content::WebContentsDelegate, | 120 : public content::WebContentsDelegate, |
| 120 public base::SupportsWeakPtr< | 121 public base::SupportsWeakPtr< |
| 121 PrerenderManager::OnCloseTabContentsDeleter> { | 122 PrerenderManager::OnCloseTabContentsDeleter> { |
| 122 public: | 123 public: |
| 123 OnCloseTabContentsDeleter(PrerenderManager* manager, | 124 OnCloseTabContentsDeleter(PrerenderManager* manager, |
| 124 TabContents* tab) | 125 TabContents* tab) |
| 125 : manager_(manager), | 126 : manager_(manager), |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 163 // static | 164 // static |
| 164 bool PrerenderManager::is_prefetch_enabled_ = false; | 165 bool PrerenderManager::is_prefetch_enabled_ = false; |
| 165 | 166 |
| 166 // static | 167 // static |
| 167 int PrerenderManager::prerenders_per_session_count_ = 0; | 168 int PrerenderManager::prerenders_per_session_count_ = 0; |
| 168 | 169 |
| 169 // static | 170 // static |
| 170 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = | 171 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = |
| 171 PRERENDER_MODE_ENABLED; | 172 PRERENDER_MODE_ENABLED; |
| 172 | 173 |
| 173 struct PrerenderManager::PrerenderContentsData { | |
| 174 PrerenderContents* contents_; | |
| 175 base::Time start_time_; | |
| 176 int active_count_; | |
| 177 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) | |
| 178 : contents_(contents), | |
| 179 start_time_(start_time), | |
| 180 active_count_(1) { | |
| 181 CHECK(contents); | |
| 182 } | |
| 183 }; | |
| 184 | |
| 185 struct PrerenderManager::NavigationRecord { | 174 struct PrerenderManager::NavigationRecord { |
| 186 GURL url_; | 175 GURL url_; |
| 187 base::TimeTicks time_; | 176 base::TimeTicks time_; |
| 188 NavigationRecord(const GURL& url, base::TimeTicks time) | 177 NavigationRecord(const GURL& url, base::TimeTicks time) |
| 189 : url_(url), | 178 : url_(url), |
| 190 time_(time) { | 179 time_(time) { |
| 191 } | 180 } |
| 192 }; | 181 }; |
| 193 | 182 |
| 194 PrerenderManager::PrerenderManager(Profile* profile, | 183 PrerenderManager::PrerenderManager(Profile* profile, |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 209 } | 198 } |
| 210 | 199 |
| 211 PrerenderManager::~PrerenderManager() { | 200 PrerenderManager::~PrerenderManager() { |
| 212 } | 201 } |
| 213 | 202 |
| 214 void PrerenderManager::Shutdown() { | 203 void PrerenderManager::Shutdown() { |
| 215 DoShutdown(); | 204 DoShutdown(); |
| 216 } | 205 } |
| 217 | 206 |
| 218 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( | 207 base::WeakPtr<PrerenderHandle> PrerenderManager::AddPrerenderFromLinkRelPrerende r( |
| 219 int process_id, | 208 int process_id, |
| 220 int route_id, | 209 int route_id, |
| 221 const GURL& url, | 210 const GURL& url, |
| 222 const content::Referrer& referrer, | 211 const content::Referrer& referrer, |
| 223 const gfx::Size& size) { | 212 const gfx::Size& size) { |
| 224 #if defined(OS_ANDROID) | 213 #if defined(OS_ANDROID) |
| 225 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable | 214 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable |
| 226 // link-prerender and enable omnibox-prerender only. | 215 // link-prerender and enable omnibox-prerender only. |
| 227 return false; | 216 return false; |
| 228 #else | 217 #else |
| 229 std::pair<int, int> child_route_id_pair(process_id, route_id); | 218 if (PrerenderContents* parent_prerender_contents = |
| 230 PrerenderContentsDataList::iterator it = | 219 FindContentsForChildAndRoute(process_id, route_id)) { |
| 231 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); | |
| 232 if (it != prerender_list_.end()) { | |
| 233 // Instead of prerendering from inside of a running prerender, we will defer | 220 // Instead of prerendering from inside of a running prerender, we will defer |
| 234 // this request until its launcher is made visible. | 221 // this request until its launcher is made visible. |
| 235 it->contents_->AddPendingPrerender(url, referrer, size); | 222 scoped_ptr<PrerenderHandle> scoped_prerender_handle(new PrerenderHandle); |
|
dominich
2012/06/22 15:36:16
Expected implementation:
return parent_prerender_
| |
| 236 return true; | 223 base::WeakPtr<PrerenderHandle> prerender_handle = |
| 224 scoped_prerender_handle.get()->AsWeakPtr(); | |
| 225 parent_prerender_contents->AddPendingPrerender( | |
| 226 scoped_prerender_handle.Pass(), url, referrer, size); | |
| 227 return prerender_handle; | |
| 237 } | 228 } |
| 238 | 229 |
| 239 // Unit tests pass in a process_id == -1. | 230 // Unit tests pass in a process_id == -1. |
| 240 RenderViewHost* source_render_view_host = NULL; | 231 RenderViewHost* source_render_view_host = NULL; |
| 241 SessionStorageNamespace* session_storage_namespace = NULL; | 232 SessionStorageNamespace* session_storage_namespace = NULL; |
| 242 if (process_id != -1) { | 233 if (process_id != -1) { |
| 243 source_render_view_host = | 234 source_render_view_host = |
| 244 RenderViewHost::FromID(process_id, route_id); | 235 RenderViewHost::FromID(process_id, route_id); |
| 245 if (!source_render_view_host || !source_render_view_host->GetView()) | 236 if (!source_render_view_host || !source_render_view_host->GetView()) |
| 246 return false; | 237 return base::WeakPtr<PrerenderHandle>(); |
|
dominich
2012/06/22 15:36:16
return PrerenderHandle::kInvalidHandle;
where kIn
| |
| 247 session_storage_namespace = | 238 session_storage_namespace = |
| 248 source_render_view_host->GetSessionStorageNamespace(); | 239 source_render_view_host->GetSessionStorageNamespace(); |
| 249 } | 240 } |
| 250 | 241 |
| 251 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, | 242 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, |
| 252 process_id, url, referrer, size, | 243 process_id, url, referrer, size, |
| 253 session_storage_namespace); | 244 session_storage_namespace, |
| 245 scoped_ptr<PrerenderHandle>()); | |
| 254 #endif | 246 #endif |
| 255 } | 247 } |
| 256 | 248 |
| 257 bool PrerenderManager::AddPrerenderFromOmnibox( | 249 base::WeakPtr<PrerenderHandle> PrerenderManager::AddPrerenderFromOmnibox( |
| 258 const GURL& url, | 250 const GURL& url, |
| 259 SessionStorageNamespace* session_storage_namespace) { | 251 SessionStorageNamespace* session_storage_namespace) { |
| 260 if (!IsOmniboxEnabled(profile_)) | 252 if (!IsOmniboxEnabled(profile_)) |
| 261 return false; | 253 return base::WeakPtr<PrerenderHandle>(); |
| 262 return AddPrerender(ORIGIN_OMNIBOX, -1, url, | 254 return AddPrerender(ORIGIN_OMNIBOX, -1, url, |
| 263 content::Referrer(), gfx::Size(), | 255 content::Referrer(), gfx::Size(), |
| 264 session_storage_namespace); | 256 session_storage_namespace, |
| 257 scoped_ptr<PrerenderHandle>()); | |
| 265 } | 258 } |
| 266 | 259 |
| 267 void PrerenderManager::MaybeCancelPrerender(const GURL& url) { | 260 void PrerenderManager::StartPendingPrerender( |
| 268 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url); | 261 scoped_ptr<PrerenderHandle> existing_prerender_handle, |
| 269 if (it == prerender_list_.end()) | 262 int process_id, |
| 270 return; | 263 const GURL& url, |
| 271 PrerenderContentsData& prerender_contents_data = *it; | 264 const content::Referrer& referrer, |
| 272 if (--prerender_contents_data.active_count_ == 0) | 265 const gfx::Size& size, |
| 273 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED); | 266 content::SessionStorageNamespace* session_storage_namespace) { |
| 267 DCHECK(existing_prerender_handle.get()); | |
| 268 DCHECK(existing_prerender_handle->IsPending()); | |
| 269 DCHECK(session_storage_namespace); | |
| 270 AddPrerender(ORIGIN_LINK_REL_PRERENDER, | |
|
dominich
2012/06/22 15:36:16
origin should have been tracked. We might start pe
| |
| 271 process_id, url, referrer, size, session_storage_namespace, | |
| 272 existing_prerender_handle.Pass()); | |
|
dominich
2012/06/22 15:36:16
ahah! Now I see the need for the existing prerende
| |
| 274 } | 273 } |
| 275 | 274 |
| 276 void PrerenderManager::DestroyPrerenderForRenderView( | 275 void PrerenderManager::DestroyPrerenderForRenderView( |
| 277 int process_id, int view_id, FinalStatus final_status) { | 276 int process_id, int view_id, FinalStatus final_status) { |
| 278 DCHECK(CalledOnValidThread()); | 277 DCHECK(CalledOnValidThread()); |
| 279 PrerenderContentsDataList::iterator it = | 278 if (PrerenderContents* prerender_contents = |
| 280 FindPrerenderContentsForChildRouteIdPair( | 279 FindContentsForChildAndRoute(process_id, view_id)) { |
| 281 std::make_pair(process_id, view_id)); | |
| 282 if (it != prerender_list_.end()) { | |
| 283 PrerenderContents* prerender_contents = it->contents_; | |
| 284 prerender_contents->Destroy(final_status); | 280 prerender_contents->Destroy(final_status); |
| 285 } | 281 } |
| 286 } | 282 } |
| 287 | 283 |
| 288 void PrerenderManager::CancelAllPrerenders() { | 284 void PrerenderManager::CancelAllPrerenders() { |
| 289 DCHECK(CalledOnValidThread()); | 285 DCHECK(CalledOnValidThread()); |
| 290 while (!prerender_list_.empty()) { | 286 while (!prerender_map_.empty()) { |
| 291 PrerenderContentsData data = prerender_list_.front(); | 287 PrerenderContents* prerender_contents = prerender_map_.begin()->first; |
| 292 DCHECK(data.contents_); | 288 DCHECK_EQ(prerender_contents, prerender_map_.begin()->second->contents()); |
| 293 data.contents_->Destroy(FINAL_STATUS_CANCELLED); | 289 prerender_contents->Destroy(FINAL_STATUS_CANCELLED); |
| 294 } | 290 } |
| 295 } | 291 } |
| 296 | 292 |
| 297 void PrerenderManager::CancelOmniboxPrerenders() { | |
| 298 DCHECK(CalledOnValidThread()); | |
| 299 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | |
| 300 it != prerender_list_.end(); ) { | |
| 301 PrerenderContentsDataList::iterator cur = it++; | |
| 302 if (cur->contents_->origin() == ORIGIN_OMNIBOX) | |
| 303 cur->contents_->Destroy(FINAL_STATUS_CANCELLED); | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, | 293 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, |
| 308 const GURL& url) { | 294 const GURL& url) { |
| 309 DCHECK(CalledOnValidThread()); | 295 DCHECK(CalledOnValidThread()); |
| 310 DCHECK(!IsWebContentsPrerendering(web_contents)); | 296 DCHECK(!IsWebContentsPrerendering(web_contents)); |
| 311 | 297 |
| 312 scoped_ptr<PrerenderContents> prerender_contents( | 298 scoped_ptr<PrerenderContents> prerender_contents( |
| 313 GetEntryButNotSpecifiedWC(url, web_contents)); | 299 GetEntryButNotSpecifiedWC(url, web_contents)); |
| 314 if (prerender_contents.get() == NULL) | 300 if (prerender_contents.get() == NULL) |
| 315 return false; | 301 return false; |
| 316 | 302 |
| 317 // Do not use the prerendered version if there is an opener object. | 303 // Do not use the prerendered version if there is an opener object. |
| 318 if (web_contents->HasOpener()) { | 304 if (web_contents->HasOpener()) { |
| 319 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER); | 305 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER); |
| 320 return false; | 306 return false; |
| 321 } | 307 } |
| 322 | 308 |
| 323 // Even if we match, the location.hash might be different. Record this as a | |
|
dominich
2012/06/22 15:36:16
The problem with fragment mismatch is that we don'
| |
| 324 // separate final status. | |
| 325 GURL matching_url; | |
| 326 bool url_matches = prerender_contents->MatchesURL(url, &matching_url); | |
| 327 DCHECK(url_matches); | |
| 328 if (url_matches && url.ref() != matching_url.ref()) { | |
| 329 prerender_contents.release()->Destroy(FINAL_STATUS_FRAGMENT_MISMATCH); | |
| 330 return false; | |
| 331 } | |
| 332 | |
| 333 // If we are just in the control group (which can be detected by noticing | 309 // If we are just in the control group (which can be detected by noticing |
| 334 // that prerendering hasn't even started yet), record that |web_contents| now | 310 // that prerendering hasn't even started yet), record that |web_contents| now |
| 335 // would be showing a prerendered contents, but otherwise, don't do anything. | 311 // would be showing a prerendered contents, but otherwise, don't do anything. |
| 336 if (!prerender_contents->prerendering_has_started()) { | 312 if (!prerender_contents->prerendering_has_started()) { |
| 337 MarkWebContentsAsWouldBePrerendered(web_contents); | 313 MarkWebContentsAsWouldBePrerendered(web_contents); |
| 338 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); | 314 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); |
| 339 return false; | 315 return false; |
| 340 } | 316 } |
| 341 | 317 |
| 342 // Don't use prerendered pages if debugger is attached to the tab. | 318 // Don't use prerendered pages if debugger is attached to the tab. |
| 343 // See http://crbug.com/98541 | 319 // See http://crbug.com/98541 |
| 344 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { | 320 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { |
| 345 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(), | 321 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(), |
| 346 FINAL_STATUS_DEVTOOLS_ATTACHED); | 322 FINAL_STATUS_DEVTOOLS_ATTACHED); |
| 347 return false; | 323 return false; |
| 348 } | 324 } |
| 349 | 325 |
| 350 // If the prerendered page is in the middle of a cross-site navigation, | 326 // If the prerendered page is in the middle of a cross-site navigation, |
| 351 // don't swap it in because there isn't a good way to merge histories. | 327 // don't swap it in because there isn't a good way to merge histories. |
| 352 if (prerender_contents->IsCrossSiteNavigationPending()) { | 328 if (prerender_contents->IsCrossSiteNavigationPending()) { |
| 353 DestroyAndMarkMatchCompleteAsUsed( | 329 DestroyAndMarkMatchCompleteAsUsed( |
| 354 prerender_contents.release(), | 330 prerender_contents.release(), |
| 355 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); | 331 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); |
| 356 return false; | 332 return false; |
| 357 } | 333 } |
| 358 | 334 |
| 359 // If the session storage namespaces don't match, cancel the prerender. | |
| 360 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost(); | |
| 361 RenderViewHost* new_render_view_host = | |
| 362 prerender_contents->prerender_contents()->web_contents()-> | |
| 363 GetRenderViewHost(); | |
| 364 DCHECK(old_render_view_host); | |
| 365 DCHECK(new_render_view_host); | |
| 366 if (old_render_view_host->GetSessionStorageNamespace() != | |
| 367 new_render_view_host->GetSessionStorageNamespace()) { | |
| 368 DestroyAndMarkMatchCompleteAsUsed( | |
| 369 prerender_contents.release(), | |
| 370 FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH); | |
| 371 return false; | |
| 372 } | |
| 373 | |
| 374 // If we don't want to use prerenders at all, we are done. | |
| 375 // For bookkeeping purposes, we need to mark this WebContents to | 335 // For bookkeeping purposes, we need to mark this WebContents to |
| 376 // reflect that it would have been prerendered. | 336 // reflect that it would have been prerendered. |
| 377 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { | 337 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { |
| 378 MarkWebContentsAsWouldBePrerendered(web_contents); | 338 MarkWebContentsAsWouldBePrerendered(web_contents); |
| 379 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); | 339 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); |
| 380 return false; | 340 return false; |
| 381 } | 341 } |
| 382 | 342 |
| 383 int child_id, route_id; | 343 int child_id, route_id; |
| 384 CHECK(prerender_contents->GetChildId(&child_id)); | 344 CHECK(prerender_contents->GetChildId(&child_id)); |
| 385 CHECK(prerender_contents->GetRouteId(&route_id)); | 345 CHECK(prerender_contents->GetRouteId(&route_id)); |
| 386 | 346 |
| 387 // Try to set the prerendered page as used, so any subsequent attempts to | 347 // Try to set the prerendered page as used, so any subsequent attempts to |
| 388 // cancel on other threads will fail. If this fails because the prerender | 348 // cancel on other threads will fail. If this fails because the prerender |
| 389 // was already cancelled, possibly on another thread, fail. | 349 // was already cancelled, possibly on another thread, fail. |
| 390 if (!prerender_tracker_->TryUse(child_id, route_id)) | 350 if (!prerender_tracker_->TryUse(child_id, route_id)) |
| 391 return false; | 351 return false; |
| 392 | 352 |
| 393 if (!prerender_contents->load_start_time().is_null()) { | 353 if (!prerender_contents->load_start_time().is_null()) { |
| 394 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() - | 354 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() - |
| 395 prerender_contents->load_start_time(), | 355 prerender_contents->load_start_time(), |
| 396 GetMaxAge()); | 356 GetMaxAge()); |
| 397 } | 357 } |
| 398 | 358 |
| 399 histograms_->RecordPerSessionCount(++prerenders_per_session_count_); | 359 histograms_->RecordPerSessionCount(++prerenders_per_session_count_); |
| 400 histograms_->RecordUsedPrerender(prerender_contents->origin()); | 360 histograms_->RecordUsedPrerender(prerender_contents->origin()); |
| 401 prerender_contents->set_final_status(FINAL_STATUS_USED); | 361 prerender_contents->set_final_status(FINAL_STATUS_USED); |
| 402 | 362 |
| 363 RenderViewHost* new_render_view_host = | |
| 364 prerender_contents->prerender_contents()->web_contents()->GetRenderViewHos t(); | |
| 403 new_render_view_host->Send( | 365 new_render_view_host->Send( |
| 404 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), | 366 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), |
| 405 false)); | 367 false)); |
| 406 | 368 |
| 407 TabContents* new_tab_contents = | 369 TabContents* new_tab_contents = |
| 408 prerender_contents->ReleasePrerenderContents(); | 370 prerender_contents->ReleasePrerenderContents(); |
| 409 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); | 371 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); |
| 410 DCHECK(new_tab_contents); | 372 DCHECK(new_tab_contents); |
| 411 DCHECK(old_tab_contents); | 373 DCHECK(old_tab_contents); |
| 412 | 374 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 459 } | 421 } |
| 460 | 422 |
| 461 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry, | 423 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry, |
| 462 FinalStatus final_status) { | 424 FinalStatus final_status) { |
| 463 DCHECK(CalledOnValidThread()); | 425 DCHECK(CalledOnValidThread()); |
| 464 DCHECK(entry); | 426 DCHECK(entry); |
| 465 // Confirm this entry has not already been moved to the pending delete list. | 427 // Confirm this entry has not already been moved to the pending delete list. |
| 466 DCHECK_EQ(0, std::count(pending_delete_list_.begin(), | 428 DCHECK_EQ(0, std::count(pending_delete_list_.begin(), |
| 467 pending_delete_list_.end(), entry)); | 429 pending_delete_list_.end(), entry)); |
| 468 | 430 |
| 469 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | 431 PrerenderHandleMap::iterator it = prerender_map_.find(entry); |
| 470 it != prerender_list_.end(); | 432 if (it == prerender_map_.end()) |
| 471 ++it) { | 433 return; |
| 472 if (it->contents_ == entry) { | |
| 473 bool swapped_in_dummy_replacement = false; | |
| 474 | 434 |
| 475 // If this PrerenderContents is being deleted due to a cancellation, | 435 // If this PrerenderContents is being deleted due to a cancellation, |
| 476 // we need to create a dummy replacement for PPLT accounting purposes | 436 // we need to create a dummy replacement for PPLT accounting purposes |
| 477 // for the Match Complete group. | 437 // for the Match Complete group. |
| 478 // This is the case if the cancellation is for any reason that would not | 438 // This is the case if the cancellation is for any reason that would not |
| 479 // occur in the control group case. | 439 // occur in the control group case. |
| 480 if (entry->match_complete_status() == | 440 if (entry->match_complete_status() == |
| 481 PrerenderContents::MATCH_COMPLETE_DEFAULT && | 441 PrerenderContents::MATCH_COMPLETE_DEFAULT && |
| 482 NeedMatchCompleteDummyForFinalStatus(final_status) && | 442 NeedMatchCompleteDummyForFinalStatus(final_status) && |
| 483 ActuallyPrerendering()) { | 443 ActuallyPrerendering()) { |
| 484 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. | 444 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. |
| 485 // However, what if new conditions are added and | 445 // However, what if new conditions are added and |
| 486 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure | 446 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure |
| 487 // what's the best thing to do here. For now, I will just check whether | 447 // what's the best thing to do here. For now, I will just check whether |
| 488 // we are actually prerendering. | 448 // we are actually prerendering. |
| 489 entry->set_match_complete_status( | 449 entry->set_match_complete_status( |
| 490 PrerenderContents::MATCH_COMPLETE_REPLACED); | 450 PrerenderContents::MATCH_COMPLETE_REPLACED); |
| 491 if (PrerenderContents* dummy_replacement_prerender_contents = | 451 PrerenderContents* |
| 492 CreatePrerenderContents(entry->prerender_url(), | 452 dummy_replacement_prerender_contents = entry->CreateDummyReplacement(); |
| 493 entry->referrer(), | 453 DCHECK(dummy_replacement_prerender_contents); |
| 494 entry->origin(), | 454 |
| 495 entry->experiment_id())) { | 455 dummy_replacement_prerender_contents->set_match_complete_status( |
| 496 dummy_replacement_prerender_contents->set_match_complete_status( | 456 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING); |
| 497 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING); | 457 DCHECK(dummy_replacement_prerender_contents->Init()); |
| 498 if (!dummy_replacement_prerender_contents->Init()) | 458 dummy_replacement_prerender_contents-> |
| 499 break; | 459 AddAliasURLsFromOtherPrerenderContents(entry); |
| 500 dummy_replacement_prerender_contents-> | 460 dummy_replacement_prerender_contents->set_match_complete_status( |
| 501 AddAliasURLsFromOtherPrerenderContents(entry); | 461 PrerenderContents::MATCH_COMPLETE_REPLACEMENT); |
| 502 dummy_replacement_prerender_contents->set_match_complete_status( | 462 prerender_map_.insert(std::make_pair(dummy_replacement_prerender_contents, |
| 503 PrerenderContents::MATCH_COMPLETE_REPLACEMENT); | 463 it->second)); |
| 504 it->contents_ = dummy_replacement_prerender_contents; | |
| 505 swapped_in_dummy_replacement = true; | |
| 506 } | |
| 507 } | |
| 508 if (!swapped_in_dummy_replacement) | |
| 509 prerender_list_.erase(it); | |
| 510 break; | |
| 511 } | |
| 512 } | 464 } |
| 465 prerender_map_.erase(it); | |
| 466 | |
| 513 AddToHistory(entry); | 467 AddToHistory(entry); |
| 514 pending_delete_list_.push_back(entry); | 468 pending_delete_list_.push_back(entry); |
| 515 | 469 |
| 516 // Destroy the old WebContents relatively promptly to reduce resource usage, | 470 // Destroy the old WebContents relatively promptly to reduce resource usage, |
| 517 // and in the case of HTML5 media, reduce the change of playing any sound. | 471 // and in the case of HTML5 media, reduce the change of playing any sound. |
| 518 PostCleanupTask(); | 472 PostCleanupTask(); |
| 519 } | 473 } |
| 520 | 474 |
| 521 // static | 475 // static |
| 522 void PrerenderManager::RecordPerceivedPageLoadTime( | 476 void PrerenderManager::RecordPerceivedPageLoadTime( |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 613 } | 567 } |
| 614 | 568 |
| 615 // static | 569 // static |
| 616 bool PrerenderManager::IsNoUseGroup() { | 570 bool PrerenderManager::IsNoUseGroup() { |
| 617 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; | 571 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; |
| 618 } | 572 } |
| 619 | 573 |
| 620 bool PrerenderManager::IsWebContentsPrerendering( | 574 bool PrerenderManager::IsWebContentsPrerendering( |
| 621 WebContents* web_contents) const { | 575 WebContents* web_contents) const { |
| 622 DCHECK(CalledOnValidThread()); | 576 DCHECK(CalledOnValidThread()); |
| 623 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); | 577 for (PrerenderHandleMap::const_iterator it = prerender_map_.begin(); |
| 624 it != prerender_list_.end(); | 578 it != prerender_map_.end(); |
| 625 ++it) { | 579 ++it) { |
| 626 TabContents* prerender_tab_contents = it->contents_->prerender_contents(); | 580 TabContents* prerender_tab_contents = it->first->prerender_contents(); |
| 627 if (prerender_tab_contents && | 581 if (prerender_tab_contents && |
| 628 prerender_tab_contents->web_contents() == web_contents) { | 582 prerender_tab_contents->web_contents() == web_contents) { |
| 629 return true; | 583 return true; |
| 630 } | 584 } |
| 631 } | 585 } |
| 632 | 586 |
| 633 // Also look through the pending-deletion list. | 587 // Also look through the pending-deletion list. |
| 634 for (std::list<PrerenderContents*>::const_iterator it = | 588 for (std::list<PrerenderContents*>::const_iterator it = |
| 635 pending_delete_list_.begin(); | 589 pending_delete_list_.begin(); |
| 636 it != pending_delete_list_.end(); | 590 it != pending_delete_list_.end(); |
| 637 ++it) { | 591 ++it) { |
| 638 TabContents* prerender_tab_contents = (*it)->prerender_contents(); | 592 TabContents* prerender_tab_contents = (*it)->prerender_contents(); |
| 639 if (prerender_tab_contents && | 593 if (prerender_tab_contents && |
| 640 prerender_tab_contents->web_contents() == web_contents) | 594 prerender_tab_contents->web_contents() == web_contents) |
| 641 return true; | 595 return true; |
| 642 } | 596 } |
| 643 | 597 |
| 644 return false; | 598 return false; |
| 645 } | 599 } |
| 646 | 600 |
| 647 bool PrerenderManager::DidPrerenderFinishLoading(const GURL& url) const { | |
| 648 DCHECK(CalledOnValidThread()); | |
| 649 PrerenderContents* contents = FindEntry(url); | |
| 650 return contents ? contents->has_finished_loading() : false; | |
| 651 } | |
| 652 | |
| 653 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) { | 601 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) { |
| 654 DCHECK(CalledOnValidThread()); | 602 DCHECK(CalledOnValidThread()); |
| 655 prerendered_tab_contents_set_.insert(web_contents); | 603 prerendered_tab_contents_set_.insert(web_contents); |
| 656 } | 604 } |
| 657 | 605 |
| 658 void PrerenderManager::MarkWebContentsAsWouldBePrerendered( | 606 void PrerenderManager::MarkWebContentsAsWouldBePrerendered( |
| 659 WebContents* web_contents) { | 607 WebContents* web_contents) { |
| 660 DCHECK(CalledOnValidThread()); | 608 DCHECK(CalledOnValidThread()); |
| 661 would_be_prerendered_map_[web_contents] = true; | 609 would_be_prerendered_map_[web_contents] = true; |
| 662 } | 610 } |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 758 histograms_->RecordFinalStatus(origin, | 706 histograms_->RecordFinalStatus(origin, |
| 759 experiment_id, | 707 experiment_id, |
| 760 mc_status, | 708 mc_status, |
| 761 final_status); | 709 final_status); |
| 762 } | 710 } |
| 763 | 711 |
| 764 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { | 712 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { |
| 765 prerender_conditions_.push_back(condition); | 713 prerender_conditions_.push_back(condition); |
| 766 } | 714 } |
| 767 | 715 |
| 768 bool PrerenderManager::IsPendingEntry(const GURL& url) const { | |
| 769 DCHECK(CalledOnValidThread()); | |
| 770 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); | |
| 771 it != prerender_list_.end(); | |
| 772 ++it) { | |
| 773 if (it->contents_->IsPendingEntry(url)) | |
| 774 return true; | |
| 775 } | |
| 776 return false; | |
| 777 } | |
| 778 | |
| 779 bool PrerenderManager::IsPrerendering(const GURL& url) const { | |
| 780 DCHECK(CalledOnValidThread()); | |
| 781 return (FindEntry(url) != NULL); | |
| 782 } | |
| 783 | |
| 784 void PrerenderManager::RecordNavigation(const GURL& url) { | 716 void PrerenderManager::RecordNavigation(const GURL& url) { |
| 785 DCHECK(CalledOnValidThread()); | 717 DCHECK(CalledOnValidThread()); |
| 786 | 718 |
| 787 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); | 719 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); |
| 788 CleanUpOldNavigations(); | 720 CleanUpOldNavigations(); |
| 789 } | 721 } |
| 790 | 722 |
| 791 // protected | 723 // protected |
| 792 void PrerenderManager::SetPrerenderContentsFactory( | 724 void PrerenderManager::SetPrerenderContentsFactory( |
| 793 PrerenderContents::Factory* prerender_contents_factory) { | 725 PrerenderContents::Factory* prerender_contents_factory) { |
| 794 DCHECK(CalledOnValidThread()); | 726 DCHECK(CalledOnValidThread()); |
| 795 prerender_contents_factory_.reset(prerender_contents_factory); | 727 prerender_contents_factory_.reset(prerender_contents_factory); |
| 796 } | 728 } |
| 797 | 729 |
| 798 void PrerenderManager::DoShutdown() { | 730 void PrerenderManager::DoShutdown() { |
| 799 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); | 731 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); |
| 800 STLDeleteElements(&prerender_conditions_); | 732 STLDeleteElements(&prerender_conditions_); |
| 801 on_close_tab_contents_deleters_.reset(); | 733 on_close_tab_contents_deleters_.reset(); |
| 802 profile_ = NULL; | 734 profile_ = NULL; |
| 803 } | 735 } |
| 804 | 736 |
| 737 PrerenderContents* PrerenderManager::FindEntry( | |
| 738 const GURL& url) { | |
| 739 if (PrerenderHandle* handle = FindHandle(url, NULL)) | |
| 740 return handle->contents(); | |
| 741 return NULL; | |
| 742 } | |
| 743 | |
| 805 // private | 744 // private |
| 806 bool PrerenderManager::AddPrerender( | 745 base::WeakPtr<PrerenderHandle> PrerenderManager::AddPrerender( |
| 807 Origin origin, | 746 Origin origin, |
| 808 int process_id, | 747 int process_id, |
| 809 const GURL& url_arg, | 748 const GURL& url_arg, |
| 810 const content::Referrer& referrer, | 749 const content::Referrer& referrer, |
| 811 const gfx::Size& size, | 750 const gfx::Size& size, |
| 812 SessionStorageNamespace* session_storage_namespace) { | 751 SessionStorageNamespace* session_storage_namespace, |
| 752 scoped_ptr<PrerenderHandle> preexisting_prerender_handle) { | |
| 813 DCHECK(CalledOnValidThread()); | 753 DCHECK(CalledOnValidThread()); |
| 814 | 754 |
| 755 // Take ownership of preeexisting_prerender_handle immediately if it was | |
| 756 // provided, otherwise create a new PrerenderHandle to own so we don't have | |
| 757 // special cases for early exits depending on if preexisting_prerender_handle | |
| 758 // was provided. | |
| 759 scoped_ptr<PrerenderHandle> | |
| 760 scoped_prerender_handle = preexisting_prerender_handle.Pass(); | |
| 761 if (!scoped_prerender_handle.get()) | |
| 762 scoped_prerender_handle.reset(new PrerenderHandle); | |
| 763 DCHECK(!scoped_prerender_handle->contents()); | |
| 764 base::WeakPtr<PrerenderHandle> prerender_handle = | |
| 765 scoped_prerender_handle->AsWeakPtr(); | |
| 766 | |
| 815 if (!IsEnabled()) | 767 if (!IsEnabled()) |
| 816 return false; | 768 return base::WeakPtr<PrerenderHandle>(); |
| 817 | 769 |
| 818 if (origin == ORIGIN_LINK_REL_PRERENDER && | 770 if (origin == ORIGIN_LINK_REL_PRERENDER && |
| 819 IsGoogleSearchResultURL(referrer.url)) { | 771 IsGoogleSearchResultURL(referrer.url)) { |
| 820 origin = ORIGIN_GWS_PRERENDER; | 772 origin = ORIGIN_GWS_PRERENDER; |
| 821 } | 773 } |
| 822 | 774 |
| 823 DeleteOldEntries(); | 775 DeleteOldEntries(); |
| 824 DeletePendingDeleteEntries(); | 776 DeletePendingDeleteEntries(); |
| 825 | 777 |
| 826 GURL url = url_arg; | 778 GURL url = url_arg; |
| 827 GURL alias_url; | 779 GURL alias_url; |
| 828 uint8 experiment = GetQueryStringBasedExperiment(url_arg); | 780 uint8 experiment = GetQueryStringBasedExperiment(url_arg); |
| 829 bool control_group_behavior = | 781 bool control_group_behavior = |
| 830 IsControlGroup() || IsControlGroupExperiment(experiment); | 782 IsControlGroup() || IsControlGroupExperiment(experiment); |
| 831 if (control_group_behavior && | 783 if (control_group_behavior && |
| 832 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { | 784 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { |
| 833 url = alias_url; | 785 url = alias_url; |
| 834 } | 786 } |
| 835 | 787 |
| 836 // From here on, we will record a FinalStatus so we need to register with the | 788 // From here on, we will record a FinalStatus so we need to register with the |
| 837 // histogram tracking. | 789 // histogram tracking. |
| 838 histograms_->RecordPrerender(origin, url_arg); | 790 histograms_->RecordPrerender(origin, url_arg); |
| 839 | 791 |
| 840 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) { | 792 if (PrerenderHandle* preexisting_prerender_handle = |
| 841 ++prerender_contents_data->active_count_; | 793 FindHandle(url, session_storage_namespace)) { |
| 842 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); | 794 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); |
| 843 return true; | 795 preexisting_prerender_handle->AddDuplicate(scoped_prerender_handle.Pass()); |
| 796 return prerender_handle; | |
| 844 } | 797 } |
| 845 | 798 |
| 846 // Do not prerender if there are too many render processes, and we would | 799 // Do not prerender if there are too many render processes, and we would |
| 847 // have to use an existing one. We do not want prerendering to happen in | 800 // have to use an existing one. We do not want prerendering to happen in |
| 848 // a shared process, so that we can always reliably lower the CPU | 801 // a shared process, so that we can always reliably lower the CPU |
| 849 // priority for prerendering. | 802 // priority for prerendering. |
| 850 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns | 803 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns |
| 851 // true, so that case needs to be explicitly checked for. | 804 // true, so that case needs to be explicitly checked for. |
| 852 // TODO(tburkard): Figure out how to cancel prerendering in the opposite | 805 // TODO(tburkard): Figure out how to cancel prerendering in the opposite |
| 853 // case, when a new tab is added to a process used for prerendering. | 806 // case, when a new tab is added to a process used for prerendering. |
| 854 // On Android we do reuse processes as we have a limited number of them and we | 807 // On Android we do reuse processes as we have a limited number of them and we |
| 855 // still want the benefits of prerendering even when several tabs are open. | 808 // still want the benefits of prerendering even when several tabs are open. |
| 856 #if !defined(OS_ANDROID) | 809 #if !defined(OS_ANDROID) |
| 857 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost( | 810 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost( |
| 858 profile_, url) && | 811 profile_, url) && |
| 859 !content::RenderProcessHost::run_renderer_in_process()) { | 812 !content::RenderProcessHost::run_renderer_in_process()) { |
| 860 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); | 813 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); |
| 861 return false; | 814 // TODO: duplicates holding zone? |
| 815 return base::WeakPtr<PrerenderHandle>(); | |
| 862 } | 816 } |
| 863 #endif | 817 #endif |
| 864 | 818 |
| 865 // Check if enough time has passed since the last prerender. | 819 // Check if enough time has passed since the last prerender. |
| 866 if (!DoesRateLimitAllowPrerender()) { | 820 if (!DoesRateLimitAllowPrerender()) { |
| 867 // Cancel the prerender. We could add it to the pending prerender list but | 821 // Cancel the prerender. We could add it to the pending prerender list but |
| 868 // this doesn't make sense as the next prerender request will be triggered | 822 // this doesn't make sense as the next prerender request will be triggered |
| 869 // by a navigation and is unlikely to be the same site. | 823 // by a navigation and is unlikely to be the same site. |
| 870 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); | 824 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
| 871 return false; | 825 return base::WeakPtr<PrerenderHandle>(); |
| 872 } | 826 } |
| 873 | 827 |
| 874 PrerenderContents* prerender_contents = CreatePrerenderContents( | 828 PrerenderContents* prerender_contents = CreatePrerenderContents( |
| 875 url, referrer, origin, experiment); | 829 url, referrer, origin, experiment); |
| 876 if (!prerender_contents || !prerender_contents->Init()) | 830 if (!prerender_contents || !prerender_contents->Init()) |
| 877 return false; | 831 return base::WeakPtr<PrerenderHandle>(); |
| 878 | 832 |
| 879 histograms_->RecordPrerenderStarted(origin); | 833 histograms_->RecordPrerenderStarted(origin); |
| 880 | 834 |
| 881 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? | 835 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? |
| 882 PrerenderContentsData data(prerender_contents, GetCurrentTime()); | 836 scoped_prerender_handle->SetContents(prerender_contents); |
| 883 | 837 prerender_map_.insert( |
| 884 prerender_list_.push_back(data); | 838 std::make_pair(prerender_contents, |
| 839 make_linked_ptr(scoped_prerender_handle.release()))); | |
| 885 | 840 |
| 886 last_prerender_start_time_ = GetCurrentTimeTicks(); | 841 last_prerender_start_time_ = GetCurrentTimeTicks(); |
| 887 | 842 |
| 888 data.contents_->StartPrerendering(process_id, size, session_storage_namespace, | 843 prerender_contents->StartPrerendering(process_id, size, session_storage_namesp ace, |
| 889 control_group_behavior); | 844 control_group_behavior); |
| 890 | 845 |
| 891 while (prerender_list_.size() > config_.max_elements) { | 846 while (prerender_map_.size() > config_.max_elements) { |
| 892 data = prerender_list_.front(); | 847 prerender_contents = prerender_map_.begin()->first; |
| 893 prerender_list_.pop_front(); | 848 DCHECK(prerender_contents); |
| 894 data.contents_->Destroy(FINAL_STATUS_EVICTED); | 849 const size_t old_size = prerender_map_.size(); |
| 850 prerender_contents->Destroy(FINAL_STATUS_EVICTED); | |
| 851 DCHECK_GT(old_size, prerender_map_.size()); | |
| 895 } | 852 } |
| 853 | |
| 896 StartSchedulingPeriodicCleanups(); | 854 StartSchedulingPeriodicCleanups(); |
| 897 return true; | 855 return prerender_handle; |
| 898 } | 856 } |
| 899 | 857 |
| 900 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { | 858 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { |
| 901 return GetEntryButNotSpecifiedWC(url, NULL); | 859 return GetEntryButNotSpecifiedWC(url, NULL); |
| 902 } | 860 } |
| 903 | 861 |
| 904 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC( | 862 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC( |
| 905 const GURL& url, | 863 const GURL& url, |
| 906 WebContents* wc) { | 864 WebContents* web_contents) { |
| 907 DCHECK(CalledOnValidThread()); | 865 DCHECK(CalledOnValidThread()); |
| 908 DeleteOldEntries(); | 866 DeleteOldEntries(); |
| 909 DeletePendingDeleteEntries(); | 867 DeletePendingDeleteEntries(); |
| 910 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | 868 |
| 911 it != prerender_list_.end(); | 869 SessionStorageNamespace* session_storage_namespace = NULL; |
| 870 if (web_contents) { | |
| 871 DCHECK(web_contents->GetRenderViewHost()); | |
| 872 session_storage_namespace = | |
| 873 web_contents->GetRenderViewHost()->GetSessionStorageNamespace(); | |
| 874 DCHECK(session_storage_namespace); | |
| 875 } | |
| 876 | |
| 877 for (PrerenderHandleMap::iterator it = prerender_map_.begin(); | |
| 878 it != prerender_map_.end(); | |
| 912 ++it) { | 879 ++it) { |
| 913 PrerenderContents* prerender_contents = it->contents_; | 880 PrerenderContents* prerender_contents = it->first; |
| 914 if (prerender_contents->MatchesURL(url, NULL) && | 881 if (!prerender_contents->Matches(url, session_storage_namespace) || |
| 915 !IsNoSwapInExperiment(prerender_contents->experiment_id())) { | 882 IsNoSwapInExperiment(prerender_contents->experiment_id())) { |
| 916 if (!prerender_contents->prerender_contents() || | 883 break; |
| 917 !wc || | 884 } |
| 918 prerender_contents->prerender_contents()->web_contents() != wc) { | 885 |
| 919 prerender_list_.erase(it); | 886 TabContents* tab_contents = prerender_contents->prerender_contents(); |
| 920 return prerender_contents; | 887 if (!tab_contents || !web_contents || |
| 921 } | 888 tab_contents->web_contents() != web_contents) { |
| 889 PrerenderHandle* prerender_handle = it->second.get(); | |
| 890 prerender_handle->SetContents(NULL); | |
| 891 prerender_map_.erase(it); | |
| 892 return prerender_contents; | |
| 922 } | 893 } |
| 923 } | 894 } |
| 924 // Entry not found. | 895 // Entry not found. |
| 925 return NULL; | 896 return NULL; |
| 926 } | 897 } |
| 927 | 898 |
| 928 void PrerenderManager::StartSchedulingPeriodicCleanups() { | 899 void PrerenderManager::StartSchedulingPeriodicCleanups() { |
| 929 DCHECK(CalledOnValidThread()); | 900 DCHECK(CalledOnValidThread()); |
| 930 if (repeating_timer_.IsRunning()) | 901 if (repeating_timer_.IsRunning()) |
| 931 return; | 902 return; |
| 932 repeating_timer_.Start(FROM_HERE, | 903 repeating_timer_.Start(FROM_HERE, |
| 933 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), | 904 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), |
| 934 this, | 905 this, |
| 935 &PrerenderManager::PeriodicCleanup); | 906 &PrerenderManager::PeriodicCleanup); |
| 936 } | 907 } |
| 937 | 908 |
| 938 void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { | 909 void PrerenderManager::StopSchedulingPeriodicCleanups() { |
| 939 if (!prerender_list_.empty()) | |
| 940 return; | |
| 941 | |
| 942 DCHECK(CalledOnValidThread()); | 910 DCHECK(CalledOnValidThread()); |
| 943 repeating_timer_.Stop(); | 911 repeating_timer_.Stop(); |
| 944 } | 912 } |
| 945 | 913 |
| 946 void PrerenderManager::PeriodicCleanup() { | 914 void PrerenderManager::PeriodicCleanup() { |
| 947 DCHECK(CalledOnValidThread()); | 915 DCHECK(CalledOnValidThread()); |
| 948 DeleteOldTabContents(); | 916 DeleteOldTabContents(); |
| 949 DeleteOldEntries(); | 917 DeleteOldEntries(); |
| 918 if (prerender_map_.empty()) | |
| 919 StopSchedulingPeriodicCleanups(); | |
| 950 | 920 |
| 951 // Grab a copy of the current PrerenderContents pointers, so that we | 921 // Grab a copy of the current PrerenderContents pointers, so that we |
| 952 // will not interfere with potential deletions of the list. | 922 // will not interfere with potential deletions of the list. |
| 953 std::vector<PrerenderContents*> prerender_contents; | 923 std::vector<PrerenderContents*> prerender_contents; |
| 954 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | 924 for (PrerenderHandleMap::iterator it = prerender_map_.begin(); |
| 955 it != prerender_list_.end(); | 925 it != prerender_map_.end(); |
| 956 ++it) { | 926 ++it) { |
| 957 DCHECK(it->contents_); | 927 DCHECK(it->first); |
| 958 prerender_contents.push_back(it->contents_); | 928 prerender_contents.push_back(it->first); |
| 959 } | 929 } |
| 960 for (std::vector<PrerenderContents*>::iterator it = | 930 for (std::vector<PrerenderContents*>::iterator it = |
| 961 prerender_contents.begin(); | 931 prerender_contents.begin(); |
| 962 it != prerender_contents.end(); | 932 it != prerender_contents.end(); |
| 963 ++it) { | 933 ++it) { |
| 964 (*it)->DestroyWhenUsingTooManyResources(); | 934 (*it)->DestroyWhenUsingTooManyResources(); |
| 965 } | 935 } |
| 966 | 936 |
| 967 DeletePendingDeleteEntries(); | 937 DeletePendingDeleteEntries(); |
| 968 } | 938 } |
| 969 | 939 |
| 970 void PrerenderManager::PostCleanupTask() { | 940 void PrerenderManager::PostCleanupTask() { |
| 971 DCHECK(CalledOnValidThread()); | 941 DCHECK(CalledOnValidThread()); |
| 972 MessageLoop::current()->PostTask( | 942 MessageLoop::current()->PostTask( |
| 973 FROM_HERE, | 943 FROM_HERE, |
| 974 base::Bind(&PrerenderManager::PeriodicCleanup, | 944 base::Bind(&PrerenderManager::PeriodicCleanup, |
| 975 weak_factory_.GetWeakPtr())); | 945 weak_factory_.GetWeakPtr())); |
| 976 } | 946 } |
| 977 | 947 |
| 978 base::TimeDelta PrerenderManager::GetMaxAge() const { | 948 base::TimeDelta PrerenderManager::GetMaxAge() const { |
| 979 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ? | 949 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ? |
| 980 base::TimeDelta::FromSeconds(300) : config_.max_age); | 950 base::TimeDelta::FromSeconds(300) : config_.max_age); |
| 981 } | 951 } |
| 982 | 952 |
| 983 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { | 953 bool PrerenderManager::IsPrerenderFresh(base::TimeTicks start) const { |
| 984 DCHECK(CalledOnValidThread()); | 954 DCHECK(CalledOnValidThread()); |
| 985 base::Time now = GetCurrentTime(); | 955 base::TimeTicks now = GetCurrentTimeTicks(); |
| 986 return (now - start < GetMaxAge()); | 956 return now - start < GetMaxAge(); |
| 987 } | 957 } |
| 988 | 958 |
| 989 void PrerenderManager::DeleteOldEntries() { | 959 void PrerenderManager::DeleteOldEntries() { |
| 990 DCHECK(CalledOnValidThread()); | 960 DCHECK(CalledOnValidThread()); |
| 991 while (!prerender_list_.empty()) { | 961 |
| 992 PrerenderContentsData data = prerender_list_.front(); | 962 while (!prerender_map_.empty()) { |
| 993 if (IsPrerenderElementFresh(data.start_time_)) | 963 PrerenderContents* contents = prerender_map_.begin()->first; |
| 964 DCHECK(contents); | |
| 965 if (IsPrerenderFresh(contents->load_start_time())) | |
| 994 return; | 966 return; |
| 995 data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); | 967 contents->Destroy(FINAL_STATUS_TIMED_OUT); |
| 996 } | 968 } |
| 997 MaybeStopSchedulingPeriodicCleanups(); | |
| 998 } | 969 } |
| 999 | 970 |
| 1000 base::Time PrerenderManager::GetCurrentTime() const { | 971 base::Time PrerenderManager::GetCurrentTime() const { |
| 1001 return base::Time::Now(); | 972 return base::Time::Now(); |
| 1002 } | 973 } |
| 1003 | 974 |
| 1004 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { | 975 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { |
| 1005 return base::TimeTicks::Now(); | 976 return base::TimeTicks::Now(); |
| 1006 } | 977 } |
| 1007 | 978 |
| 1008 PrerenderContents* PrerenderManager::CreatePrerenderContents( | 979 PrerenderContents* PrerenderManager::CreatePrerenderContents( |
| 1009 const GURL& url, | 980 const GURL& url, |
| 1010 const content::Referrer& referrer, | 981 const content::Referrer& referrer, |
| 1011 Origin origin, | 982 Origin origin, |
| 1012 uint8 experiment_id) { | 983 uint8 experiment_id) { |
| 1013 DCHECK(CalledOnValidThread()); | 984 DCHECK(CalledOnValidThread()); |
| 1014 return prerender_contents_factory_->CreatePrerenderContents( | 985 return prerender_contents_factory_->CreatePrerenderContents( |
| 1015 this, prerender_tracker_, profile_, url, | 986 this, prerender_tracker_, profile_, url, |
| 1016 referrer, origin, experiment_id); | 987 referrer, origin, experiment_id); |
| 1017 } | 988 } |
| 1018 | 989 |
| 1019 void PrerenderManager::DeletePendingDeleteEntries() { | 990 void PrerenderManager::DeletePendingDeleteEntries() { |
| 1020 while (!pending_delete_list_.empty()) { | 991 while (!pending_delete_list_.empty()) { |
| 1021 PrerenderContents* contents = pending_delete_list_.front(); | 992 PrerenderContents* contents = pending_delete_list_.front(); |
| 1022 pending_delete_list_.pop_front(); | 993 pending_delete_list_.pop_front(); |
| 1023 delete contents; | 994 delete contents; |
| 1024 } | 995 } |
| 1025 } | 996 } |
| 1026 | 997 |
| 1027 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData( | 998 PrerenderHandle* PrerenderManager::FindHandle( |
| 1028 const GURL& url) { | 999 const GURL& url, |
| 1029 DCHECK(CalledOnValidThread()); | 1000 const SessionStorageNamespace* session_storage_namespace) { |
| 1030 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url); | 1001 for (PrerenderHandleMap::iterator it = prerender_map_.begin(); |
| 1031 if (it == prerender_list_.end()) | 1002 it != prerender_map_.end(); |
| 1032 return NULL; | |
| 1033 PrerenderContentsData& prerender_contents_data = *it; | |
| 1034 return &prerender_contents_data; | |
| 1035 } | |
| 1036 | |
| 1037 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const { | |
| 1038 DCHECK(CalledOnValidThread()); | |
| 1039 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); | |
| 1040 it != prerender_list_.end(); | |
| 1041 ++it) { | 1003 ++it) { |
| 1042 if (it->contents_->MatchesURL(url, NULL)) | 1004 PrerenderContents* prerender_contents = it->first; |
| 1043 return it->contents_; | 1005 if (prerender_contents->Matches(url, session_storage_namespace)) |
| 1006 return it->second.get(); | |
| 1044 } | 1007 } |
| 1045 // Entry not found. | |
| 1046 return NULL; | 1008 return NULL; |
| 1047 } | 1009 } |
| 1048 | 1010 |
| 1049 PrerenderManager::PrerenderContentsDataList::iterator | 1011 PrerenderContents* PrerenderManager::FindContentsForChildAndRoute( |
| 1050 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( | 1012 const int child_id, const int route_id) { |
| 1051 const std::pair<int, int>& child_route_id_pair) { | 1013 PrerenderHandleMap::iterator it = prerender_map_.begin(); |
| 1052 PrerenderContentsDataList::iterator it = prerender_list_.begin(); | 1014 for (; it != prerender_map_.end(); ++it) { |
| 1053 for (; it != prerender_list_.end(); ++it) { | 1015 PrerenderContents* prerender_contents = it->first; |
| 1054 PrerenderContents* prerender_contents = it->contents_; | |
| 1055 | 1016 |
| 1056 int child_id; | 1017 int contents_child_id; |
| 1057 int route_id; | 1018 if (!prerender_contents->GetChildId(&contents_child_id)) |
| 1058 bool has_child_id = prerender_contents->GetChildId(&child_id); | 1019 continue; |
| 1059 bool has_route_id = has_child_id && | 1020 int contents_route_id; |
| 1060 prerender_contents->GetRouteId(&route_id); | 1021 if (!prerender_contents->GetRouteId(&contents_route_id)) |
| 1022 continue; | |
| 1061 | 1023 |
| 1062 if (has_child_id && has_route_id && | 1024 if (contents_child_id == child_id && contents_route_id == route_id) |
| 1063 child_id == child_route_id_pair.first && | 1025 return it->first; |
| 1064 route_id == child_route_id_pair.second) { | |
| 1065 break; | |
| 1066 } | |
| 1067 } | 1026 } |
| 1068 return it; | 1027 return NULL; |
| 1069 } | |
| 1070 | |
| 1071 PrerenderManager::PrerenderContentsDataList::iterator | |
| 1072 PrerenderManager::FindPrerenderContentsForURL(const GURL& url) { | |
| 1073 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | |
| 1074 it != prerender_list_.end(); ++it) { | |
| 1075 if (it->contents_->MatchesURL(url, NULL)) | |
| 1076 return it; | |
| 1077 } | |
| 1078 return prerender_list_.end(); | |
| 1079 } | 1028 } |
| 1080 | 1029 |
| 1081 bool PrerenderManager::DoesRateLimitAllowPrerender() const { | 1030 bool PrerenderManager::DoesRateLimitAllowPrerender() const { |
| 1082 DCHECK(CalledOnValidThread()); | 1031 DCHECK(CalledOnValidThread()); |
| 1083 base::TimeDelta elapsed_time = | 1032 base::TimeDelta elapsed_time = |
| 1084 GetCurrentTimeTicks() - last_prerender_start_time_; | 1033 GetCurrentTimeTicks() - last_prerender_start_time_; |
| 1085 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); | 1034 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); |
| 1086 if (!config_.rate_limit_enabled) | 1035 if (!config_.rate_limit_enabled) |
| 1087 return true; | 1036 return true; |
| 1088 return elapsed_time > | 1037 return elapsed_time > |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1130 void PrerenderManager::AddToHistory(PrerenderContents* contents) { | 1079 void PrerenderManager::AddToHistory(PrerenderContents* contents) { |
| 1131 PrerenderHistory::Entry entry(contents->prerender_url(), | 1080 PrerenderHistory::Entry entry(contents->prerender_url(), |
| 1132 contents->final_status(), | 1081 contents->final_status(), |
| 1133 contents->origin(), | 1082 contents->origin(), |
| 1134 base::Time::Now()); | 1083 base::Time::Now()); |
| 1135 prerender_history_->AddEntry(entry); | 1084 prerender_history_->AddEntry(entry); |
| 1136 } | 1085 } |
| 1137 | 1086 |
| 1138 Value* PrerenderManager::GetActivePrerendersAsValue() const { | 1087 Value* PrerenderManager::GetActivePrerendersAsValue() const { |
| 1139 ListValue* list_value = new ListValue(); | 1088 ListValue* list_value = new ListValue(); |
| 1140 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); | 1089 for (PrerenderHandleMap::const_iterator it = prerender_map_.begin(); |
| 1141 it != prerender_list_.end(); | 1090 it != prerender_map_.end(); |
| 1142 ++it) { | 1091 ++it) { |
| 1143 Value* prerender_value = it->contents_->GetAsValue(); | 1092 Value* prerender_value = it->first->GetAsValue(); |
| 1144 if (!prerender_value) | 1093 if (prerender_value) |
| 1145 continue; | 1094 list_value->Append(prerender_value); |
| 1146 list_value->Append(prerender_value); | |
| 1147 } | 1095 } |
| 1148 return list_value; | 1096 return list_value; |
| 1149 } | 1097 } |
| 1150 | 1098 |
| 1151 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { | 1099 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { |
| 1152 DeleteOldTabContents(); | 1100 DeleteOldTabContents(); |
| 1153 while (!prerender_list_.empty()) { | 1101 while (!prerender_map_.empty()) { |
| 1154 PrerenderContentsData data = prerender_list_.front(); | 1102 PrerenderContents* contents = prerender_map_.begin()->first; |
| 1155 prerender_list_.pop_front(); | 1103 const size_t old_size = prerender_map_.size(); |
| 1156 data.contents_->Destroy(final_status); | 1104 contents->Destroy(final_status); |
| 1105 DCHECK_GT(old_size, prerender_map_.size()); | |
| 1157 } | 1106 } |
| 1158 DeletePendingDeleteEntries(); | 1107 DeletePendingDeleteEntries(); |
| 1159 } | 1108 } |
| 1160 | 1109 |
| 1161 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed( | 1110 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed( |
| 1162 PrerenderContents* prerender_contents, | 1111 PrerenderContents* prerender_contents, |
| 1163 FinalStatus final_status) { | 1112 FinalStatus final_status) { |
| 1164 prerender_contents->set_match_complete_status( | 1113 prerender_contents->set_match_complete_status( |
| 1165 PrerenderContents::MATCH_COMPLETE_REPLACED); | 1114 PrerenderContents::MATCH_COMPLETE_REPLACED); |
| 1166 histograms_->RecordFinalStatus(prerender_contents->origin(), | 1115 histograms_->RecordFinalStatus(prerender_contents->origin(), |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1205 if (!render_process_host || !render_process_host->GetBrowserContext()) | 1154 if (!render_process_host || !render_process_host->GetBrowserContext()) |
| 1206 return NULL; | 1155 return NULL; |
| 1207 Profile* profile = Profile::FromBrowserContext( | 1156 Profile* profile = Profile::FromBrowserContext( |
| 1208 render_process_host->GetBrowserContext()); | 1157 render_process_host->GetBrowserContext()); |
| 1209 if (!profile) | 1158 if (!profile) |
| 1210 return NULL; | 1159 return NULL; |
| 1211 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); | 1160 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); |
| 1212 } | 1161 } |
| 1213 | 1162 |
| 1214 } // namespace prerender | 1163 } // namespace prerender |
| OLD | NEW |