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 <algorithm> | |
8 #include <functional> | |
7 #include <set> | 9 #include <set> |
8 #include <string> | 10 #include <string> |
9 #include <vector> | 11 #include <vector> |
10 | 12 |
11 #include "base/bind.h" | 13 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 14 #include "base/bind_helpers.h" |
13 #include "base/logging.h" | 15 #include "base/logging.h" |
14 #include "base/memory/weak_ptr.h" | 16 #include "base/memory/weak_ptr.h" |
15 #include "base/metrics/histogram.h" | 17 #include "base/metrics/histogram.h" |
16 #include "base/stl_util.h" | 18 #include "base/stl_util.h" |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
99 // This ensures that there is no bias in terms of the page load times | 101 // This ensures that there is no bias in terms of the page load times |
100 // of the pages forming the difference between the two sets. | 102 // of the pages forming the difference between the two sets. |
101 | 103 |
102 bool NeedMatchCompleteDummyForFinalStatus(FinalStatus final_status) { | 104 bool NeedMatchCompleteDummyForFinalStatus(FinalStatus final_status) { |
103 return final_status != FINAL_STATUS_USED && | 105 return final_status != FINAL_STATUS_USED && |
104 final_status != FINAL_STATUS_TIMED_OUT && | 106 final_status != FINAL_STATUS_TIMED_OUT && |
105 final_status != FINAL_STATUS_EVICTED && | 107 final_status != FINAL_STATUS_EVICTED && |
106 final_status != FINAL_STATUS_MANAGER_SHUTDOWN && | 108 final_status != FINAL_STATUS_MANAGER_SHUTDOWN && |
107 final_status != FINAL_STATUS_APP_TERMINATING && | 109 final_status != FINAL_STATUS_APP_TERMINATING && |
108 final_status != FINAL_STATUS_WINDOW_OPENER && | 110 final_status != FINAL_STATUS_WINDOW_OPENER && |
109 final_status != FINAL_STATUS_FRAGMENT_MISMATCH && | |
110 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED && | 111 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED && |
111 final_status != FINAL_STATUS_CANCELLED && | 112 final_status != FINAL_STATUS_CANCELLED && |
112 final_status != FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH && | |
113 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED && | 113 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED && |
114 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING; | 114 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING; |
115 } | 115 } |
116 | 116 |
117 } // namespace | 117 } // namespace |
118 | 118 |
119 class PrerenderManager::OnCloseTabContentsDeleter | 119 class PrerenderManager::OnCloseTabContentsDeleter |
120 : public content::WebContentsDelegate, | 120 : public content::WebContentsDelegate, |
121 public base::SupportsWeakPtr< | 121 public base::SupportsWeakPtr< |
122 PrerenderManager::OnCloseTabContentsDeleter> { | 122 PrerenderManager::OnCloseTabContentsDeleter> { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
164 // static | 164 // static |
165 bool PrerenderManager::is_prefetch_enabled_ = false; | 165 bool PrerenderManager::is_prefetch_enabled_ = false; |
166 | 166 |
167 // static | 167 // static |
168 int PrerenderManager::prerenders_per_session_count_ = 0; | 168 int PrerenderManager::prerenders_per_session_count_ = 0; |
169 | 169 |
170 // static | 170 // static |
171 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = | 171 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = |
172 PRERENDER_MODE_ENABLED; | 172 PRERENDER_MODE_ENABLED; |
173 | 173 |
174 struct PrerenderManager::PrerenderContentsData { | |
175 PrerenderContents* contents_; | |
176 base::Time start_time_; | |
177 int active_count_; | |
178 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) | |
179 : contents_(contents), | |
180 start_time_(start_time), | |
181 active_count_(1) { | |
182 CHECK(contents); | |
183 } | |
184 }; | |
185 | |
186 struct PrerenderManager::NavigationRecord { | 174 struct PrerenderManager::NavigationRecord { |
187 GURL url_; | 175 GURL url_; |
188 base::TimeTicks time_; | 176 base::TimeTicks time_; |
189 NavigationRecord(const GURL& url, base::TimeTicks time) | 177 NavigationRecord(const GURL& url, base::TimeTicks time) |
190 : url_(url), | 178 : url_(url), |
191 time_(time) { | 179 time_(time) { |
192 } | 180 } |
193 }; | 181 }; |
194 | 182 |
195 PrerenderManager::PrerenderManager(Profile* profile, | 183 PrerenderManager::PrerenderManager(Profile* profile, |
(...skipping 14 matching lines...) Expand all Loading... | |
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
211 } | 199 } |
212 | 200 |
213 PrerenderManager::~PrerenderManager() { | 201 PrerenderManager::~PrerenderManager() { |
214 } | 202 } |
215 | 203 |
216 void PrerenderManager::Shutdown() { | 204 void PrerenderManager::Shutdown() { |
217 DoShutdown(); | 205 DoShutdown(); |
218 } | 206 } |
219 | 207 |
220 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( | 208 PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender( |
221 int process_id, | 209 int process_id, |
222 int route_id, | 210 int route_id, |
223 const GURL& url, | 211 const GURL& url, |
224 const content::Referrer& referrer, | 212 const content::Referrer& referrer, |
225 gfx::Size size) { | 213 gfx::Size size) { |
226 #if defined(OS_ANDROID) | 214 #if defined(OS_ANDROID) |
227 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable | 215 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable |
228 // link-prerender and enable omnibox-prerender only. | 216 // link-prerender and enable omnibox-prerender only. |
229 return false; | 217 return false; |
230 #else | 218 #else |
231 std::pair<int, int> child_route_id_pair(process_id, route_id); | 219 if (PrerenderData* parent_prerender_data = |
232 PrerenderContentsDataList::iterator it = | 220 FindPrerenderDataForChildAndRoute(process_id, route_id)) { |
233 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); | |
234 if (it != prerender_list_.end()) { | |
235 // Instead of prerendering from inside of a running prerender, we will defer | 221 // Instead of prerendering from inside of a running prerender, we will defer |
236 // this request until its launcher is made visible. | 222 // this request until its launcher is made visible. |
237 it->contents_->AddPendingPrerender(url, referrer, size); | 223 if (PrerenderContents* contents = parent_prerender_data->contents) { |
238 return true; | 224 pending_prerender_list_.push_back(PrerenderData(this)); |
225 PrerenderHandle* prerender_handle = CreatePrerenderHandleForPrerenderData( | |
226 &pending_prerender_list_.back()); | |
227 contents->AddPendingPrerender(prerender_handle->AsWeakPtr(), | |
228 url, referrer, size); | |
229 return prerender_handle; | |
230 } | |
239 } | 231 } |
240 | 232 |
241 // Unit tests pass in a process_id == -1. | 233 // Unit tests pass in a process_id == -1. |
242 SessionStorageNamespace* session_storage_namespace = NULL; | 234 SessionStorageNamespace* session_storage_namespace = NULL; |
243 if (process_id != -1) { | 235 if (process_id != -1) { |
244 RenderViewHost* source_render_view_host = | 236 RenderViewHost* source_render_view_host = |
245 RenderViewHost::FromID(process_id, route_id); | 237 RenderViewHost::FromID(process_id, route_id); |
246 if (!source_render_view_host || !source_render_view_host->GetView()) | 238 if (!source_render_view_host || !source_render_view_host->GetView()) |
247 return false; | 239 return NULL; |
248 session_storage_namespace = | 240 session_storage_namespace = |
249 source_render_view_host->GetSessionStorageNamespace(); | 241 source_render_view_host->GetSessionStorageNamespace(); |
250 | 242 |
251 if (size.IsEmpty()) { | 243 if (size.IsEmpty()) { |
252 // Use the size of the tab requesting the prerendering. | 244 // Use the size of the tab requesting the prerendering. |
253 WebContents* web_contents = | 245 WebContents* web_contents = |
254 WebContents::FromRenderViewHost(source_render_view_host); | 246 WebContents::FromRenderViewHost(source_render_view_host); |
255 if (web_contents && web_contents->GetView()) { | 247 if (web_contents && web_contents->GetView()) { |
256 gfx::Rect container_bounds; | 248 gfx::Rect container_bounds; |
257 web_contents->GetView()->GetContainerBounds(&container_bounds); | 249 web_contents->GetView()->GetContainerBounds(&container_bounds); |
258 size = container_bounds.size(); | 250 size = container_bounds.size(); |
259 } | 251 } |
260 } | 252 } |
261 } | 253 } |
262 | 254 |
263 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, | 255 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, |
264 process_id, url, referrer, size, | 256 process_id, url, referrer, size, |
265 session_storage_namespace); | 257 session_storage_namespace); |
266 #endif | 258 #endif |
267 } | 259 } |
268 | 260 |
269 bool PrerenderManager::AddPrerenderFromOmnibox( | 261 PrerenderHandle* PrerenderManager::AddPrerenderFromOmnibox( |
270 const GURL& url, | 262 const GURL& url, |
271 SessionStorageNamespace* session_storage_namespace, | 263 SessionStorageNamespace* session_storage_namespace, |
272 gfx::Size size) { | 264 gfx::Size size) { |
273 if (!IsOmniboxEnabled(profile_)) | 265 if (!IsOmniboxEnabled(profile_)) |
274 return false; | 266 return NULL; |
275 return AddPrerender(ORIGIN_OMNIBOX, -1, url, | 267 return AddPrerender(ORIGIN_OMNIBOX, -1, url, content::Referrer(), size, |
276 content::Referrer(), size, | |
277 session_storage_namespace); | 268 session_storage_namespace); |
278 } | 269 } |
279 | 270 |
280 void PrerenderManager::MaybeCancelPrerender(const GURL& url) { | 271 void PrerenderManager::StartPendingPrerender( |
281 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url); | 272 PrerenderHandle* existing_prerender_handle, |
282 if (it == prerender_list_.end()) | 273 Origin origin, |
283 return; | 274 int process_id, |
284 PrerenderContentsData& prerender_contents_data = *it; | 275 const GURL& url, |
285 if (--prerender_contents_data.active_count_ == 0) | 276 const content::Referrer& referrer, |
286 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED); | 277 const gfx::Size& size, |
278 content::SessionStorageNamespace* session_storage_namespace) { | |
279 DCHECK(existing_prerender_handle); | |
280 DCHECK(existing_prerender_handle->IsValid()); | |
281 DCHECK(existing_prerender_handle->IsPending()); | |
282 | |
283 DCHECK(process_id == -1 || session_storage_namespace); | |
284 | |
285 scoped_ptr<PrerenderHandle> | |
286 new_prerender_handle(AddPrerender(origin, process_id, url, referrer, | |
287 size, session_storage_namespace)); | |
288 | |
289 existing_prerender_handle->SwapPrerenderDataWith(new_prerender_handle.get()); | |
290 } | |
291 | |
292 void PrerenderManager::DestroyPendingPrerenderData( | |
293 PrerenderHandle::PrerenderData* pending_prerender_data) { | |
294 for (std::list<PrerenderData>::iterator it = pending_prerender_list_.begin(); | |
295 it != pending_prerender_list_.end(); | |
296 ++it) { | |
297 if (&(*it) == pending_prerender_data) { | |
dominich
2012/07/02 20:43:03
Is it worth checking the contents of the pending_p
gavinp
2012/07/03 16:41:02
Done.
| |
298 DCHECK_EQ(0, it->client_count); | |
299 InvalidatePrerenderHandlesForPrerenderData(*it); | |
300 pending_prerender_list_.erase(it); | |
301 return; | |
302 } | |
303 } | |
304 NOTREACHED(); | |
287 } | 305 } |
288 | 306 |
289 void PrerenderManager::DestroyPrerenderForRenderView( | 307 void PrerenderManager::DestroyPrerenderForRenderView( |
290 int process_id, int view_id, FinalStatus final_status) { | 308 int process_id, int view_id, FinalStatus final_status) { |
291 DCHECK(CalledOnValidThread()); | 309 DCHECK(CalledOnValidThread()); |
292 PrerenderContentsDataList::iterator it = | 310 if (PrerenderData* prerender_data = |
293 FindPrerenderContentsForChildRouteIdPair( | 311 FindPrerenderDataForChildAndRoute(process_id, view_id)) { |
294 std::make_pair(process_id, view_id)); | 312 prerender_data->contents->Destroy(final_status); |
295 if (it != prerender_list_.end()) { | |
296 PrerenderContents* prerender_contents = it->contents_; | |
297 prerender_contents->Destroy(final_status); | |
298 } | 313 } |
299 } | 314 } |
300 | 315 |
301 void PrerenderManager::CancelAllPrerenders() { | 316 void PrerenderManager::CancelAllPrerenders() { |
302 DCHECK(CalledOnValidThread()); | 317 DCHECK(CalledOnValidThread()); |
303 while (!prerender_list_.empty()) { | 318 while (!active_prerender_list_.empty()) { |
304 PrerenderContentsData data = prerender_list_.front(); | 319 PrerenderContents* prerender_contents = |
305 DCHECK(data.contents_); | 320 active_prerender_list_.front().contents; |
306 data.contents_->Destroy(FINAL_STATUS_CANCELLED); | 321 prerender_contents->Destroy(FINAL_STATUS_CANCELLED); |
307 } | 322 } |
308 } | 323 } |
309 | 324 |
310 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, | 325 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, |
311 const GURL& url) { | 326 const GURL& url) { |
312 DCHECK(CalledOnValidThread()); | 327 DCHECK(CalledOnValidThread()); |
313 DCHECK(!IsWebContentsPrerendering(web_contents)); | 328 DCHECK(!IsWebContentsPrerendering(web_contents)); |
314 | 329 |
315 scoped_ptr<PrerenderContents> prerender_contents( | 330 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost(); |
316 GetEntryButNotSpecifiedWC(url, web_contents)); | 331 |
317 if (prerender_contents.get() == NULL) | 332 DeleteOldEntries(); |
333 DeletePendingDeleteEntries(); | |
334 PrerenderData* prerender_data = | |
335 FindPrerenderData(url, | |
336 old_render_view_host->GetSessionStorageNamespace()); | |
337 if (!prerender_data) | |
318 return false; | 338 return false; |
339 DCHECK(prerender_data->contents); | |
340 if (IsNoSwapInExperiment(prerender_data->contents->experiment_id())) | |
341 return false; | |
342 | |
343 if (TabContents* new_tab_contents = | |
344 prerender_data->contents->prerender_contents()) { | |
345 if (web_contents == new_tab_contents->web_contents()) | |
346 return false; // Do not swap in to ourself. | |
dominich
2012/07/02 20:43:03
does this actually happen? Does it cause problems?
gavinp
2012/07/03 16:41:02
Yes. See http://avclub.ytz.ca/~gavin/testing/prere
dominich
2012/07/03 17:08:39
Doesn't seem to cause problems.
gavinp
2012/07/03 18:45:40
You're right, my test doesn't.
But I was just cop
| |
347 } | |
348 | |
349 scoped_ptr<PrerenderContents> prerender_contents(prerender_data->contents); | |
350 std::list<PrerenderData>::iterator to_erase = | |
351 FindIteratorForPrerenderContents(prerender_contents.get()); | |
352 DCHECK(active_prerender_list_.end() != to_erase); | |
353 DCHECK(&(*to_erase) == prerender_data); | |
354 InvalidatePrerenderHandlesForPrerenderData(*prerender_data); | |
355 active_prerender_list_.erase(to_erase); | |
319 | 356 |
320 // Do not use the prerendered version if there is an opener object. | 357 // Do not use the prerendered version if there is an opener object. |
321 if (web_contents->HasOpener()) { | 358 if (web_contents->HasOpener()) { |
322 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER); | 359 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER); |
323 return false; | 360 return false; |
324 } | 361 } |
325 | 362 |
326 // Even if we match, the location.hash might be different. Record this as a | |
327 // separate final status. | |
328 GURL matching_url; | |
329 bool url_matches = prerender_contents->MatchesURL(url, &matching_url); | |
330 DCHECK(url_matches); | |
331 if (url_matches && url.ref() != matching_url.ref()) { | |
332 prerender_contents.release()->Destroy(FINAL_STATUS_FRAGMENT_MISMATCH); | |
333 return false; | |
334 } | |
335 | |
336 // If we are just in the control group (which can be detected by noticing | 363 // If we are just in the control group (which can be detected by noticing |
337 // that prerendering hasn't even started yet), record that |web_contents| now | 364 // that prerendering hasn't even started yet), record that |web_contents| now |
338 // would be showing a prerendered contents, but otherwise, don't do anything. | 365 // would be showing a prerendered contents, but otherwise, don't do anything. |
339 if (!prerender_contents->prerendering_has_started()) { | 366 if (!prerender_contents->prerendering_has_started()) { |
340 MarkWebContentsAsWouldBePrerendered(web_contents); | 367 MarkWebContentsAsWouldBePrerendered(web_contents); |
341 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); | 368 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); |
342 return false; | 369 return false; |
343 } | 370 } |
344 | 371 |
345 // Don't use prerendered pages if debugger is attached to the tab. | 372 // Don't use prerendered pages if debugger is attached to the tab. |
346 // See http://crbug.com/98541 | 373 // See http://crbug.com/98541 |
347 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { | 374 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { |
348 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(), | 375 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(), |
349 FINAL_STATUS_DEVTOOLS_ATTACHED); | 376 FINAL_STATUS_DEVTOOLS_ATTACHED); |
350 return false; | 377 return false; |
351 } | 378 } |
352 | 379 |
353 // If the prerendered page is in the middle of a cross-site navigation, | 380 // If the prerendered page is in the middle of a cross-site navigation, |
354 // don't swap it in because there isn't a good way to merge histories. | 381 // don't swap it in because there isn't a good way to merge histories. |
355 if (prerender_contents->IsCrossSiteNavigationPending()) { | 382 if (prerender_contents->IsCrossSiteNavigationPending()) { |
356 DestroyAndMarkMatchCompleteAsUsed( | 383 DestroyAndMarkMatchCompleteAsUsed( |
357 prerender_contents.release(), | 384 prerender_contents.release(), |
358 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); | 385 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); |
359 return false; | 386 return false; |
360 } | 387 } |
361 | 388 |
362 // If the session storage namespaces don't match, cancel the prerender. | |
363 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost(); | |
364 RenderViewHost* new_render_view_host = | |
365 prerender_contents->prerender_contents()->web_contents()-> | |
366 GetRenderViewHost(); | |
367 DCHECK(old_render_view_host); | |
368 DCHECK(new_render_view_host); | |
369 if (old_render_view_host->GetSessionStorageNamespace() != | |
370 new_render_view_host->GetSessionStorageNamespace()) { | |
371 DestroyAndMarkMatchCompleteAsUsed( | |
372 prerender_contents.release(), | |
373 FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH); | |
374 return false; | |
375 } | |
376 | |
377 // If we don't want to use prerenders at all, we are done. | |
378 // For bookkeeping purposes, we need to mark this WebContents to | 389 // For bookkeeping purposes, we need to mark this WebContents to |
379 // reflect that it would have been prerendered. | 390 // reflect that it would have been prerendered. |
380 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { | 391 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { |
381 MarkWebContentsAsWouldBePrerendered(web_contents); | 392 MarkWebContentsAsWouldBePrerendered(web_contents); |
382 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); | 393 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); |
383 return false; | 394 return false; |
384 } | 395 } |
385 | 396 |
386 int child_id, route_id; | 397 int child_id, route_id; |
387 CHECK(prerender_contents->GetChildId(&child_id)); | 398 CHECK(prerender_contents->GetChildId(&child_id)); |
388 CHECK(prerender_contents->GetRouteId(&route_id)); | 399 CHECK(prerender_contents->GetRouteId(&route_id)); |
389 | 400 |
390 // Try to set the prerendered page as used, so any subsequent attempts to | 401 // Try to set the prerendered page as used, so any subsequent attempts to |
391 // cancel on other threads will fail. If this fails because the prerender | 402 // cancel on other threads will fail. If this fails because the prerender |
392 // was already cancelled, possibly on another thread, fail. | 403 // was already cancelled, possibly on another thread, fail. |
393 if (!prerender_tracker_->TryUse(child_id, route_id)) | 404 if (!prerender_tracker_->TryUse(child_id, route_id)) |
394 return false; | 405 return false; |
395 | 406 |
407 // At this point, we've determined that we will use the prerender. | |
408 | |
396 if (!prerender_contents->load_start_time().is_null()) { | 409 if (!prerender_contents->load_start_time().is_null()) { |
397 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() - | 410 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() - |
398 prerender_contents->load_start_time(), | 411 prerender_contents->load_start_time(), |
399 GetMaxAge()); | 412 GetMaxAge()); |
400 } | 413 } |
401 | 414 |
402 histograms_->RecordPerSessionCount(++prerenders_per_session_count_); | 415 histograms_->RecordPerSessionCount(++prerenders_per_session_count_); |
403 histograms_->RecordUsedPrerender(prerender_contents->origin()); | 416 histograms_->RecordUsedPrerender(prerender_contents->origin()); |
404 prerender_contents->set_final_status(FINAL_STATUS_USED); | 417 prerender_contents->set_final_status(FINAL_STATUS_USED); |
405 | 418 |
419 RenderViewHost* new_render_view_host = | |
420 prerender_contents->prerender_contents()->web_contents()-> | |
421 GetRenderViewHost(); | |
406 new_render_view_host->Send( | 422 new_render_view_host->Send( |
407 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), | 423 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), |
408 false)); | 424 false)); |
409 | 425 |
426 // Start pending prerender requests from the PrerenderContents, if there are | |
427 // any. | |
428 prerender_contents->StartPendingPrerenders(); | |
429 | |
410 TabContents* new_tab_contents = | 430 TabContents* new_tab_contents = |
411 prerender_contents->ReleasePrerenderContents(); | 431 prerender_contents->ReleasePrerenderContents(); |
412 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); | 432 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); |
413 DCHECK(new_tab_contents); | 433 DCHECK(new_tab_contents); |
414 DCHECK(old_tab_contents); | 434 DCHECK(old_tab_contents); |
415 | 435 |
416 MarkWebContentsAsPrerendered(new_tab_contents->web_contents()); | 436 MarkWebContentsAsPrerendered(new_tab_contents->web_contents()); |
417 | 437 |
418 // Merge the browsing history. | 438 // Merge the browsing history. |
419 new_tab_contents->web_contents()->GetController().CopyStateFromAndPrune( | 439 new_tab_contents->web_contents()->GetController().CopyStateFromAndPrune( |
(...skipping 12 matching lines...) Expand all Loading... | |
432 } | 452 } |
433 | 453 |
434 // Update PPLT metrics: | 454 // Update PPLT metrics: |
435 // If the tab has finished loading, record a PPLT of 0. | 455 // If the tab has finished loading, record a PPLT of 0. |
436 // If the tab is still loading, reset its start time to the current time. | 456 // If the tab is still loading, reset its start time to the current time. |
437 PrerenderTabHelper* prerender_tab_helper = | 457 PrerenderTabHelper* prerender_tab_helper = |
438 new_tab_contents->prerender_tab_helper(); | 458 new_tab_contents->prerender_tab_helper(); |
439 DCHECK(prerender_tab_helper != NULL); | 459 DCHECK(prerender_tab_helper != NULL); |
440 prerender_tab_helper->PrerenderSwappedIn(); | 460 prerender_tab_helper->PrerenderSwappedIn(); |
441 | 461 |
442 // Start pending prerender requests from the PrerenderContents, if there are | |
443 // any. | |
444 prerender_contents->StartPendingPrerenders(); | |
445 | |
446 if (old_tab_contents->web_contents()->NeedToFireBeforeUnload()) { | 462 if (old_tab_contents->web_contents()->NeedToFireBeforeUnload()) { |
447 // Schedule the delete to occur after the tab has run its unload handlers. | 463 // Schedule the delete to occur after the tab has run its unload handlers. |
448 on_close_tab_contents_deleters_.push_back( | 464 on_close_tab_contents_deleters_.push_back( |
449 new OnCloseTabContentsDeleter(this, old_tab_contents)); | 465 new OnCloseTabContentsDeleter(this, old_tab_contents)); |
450 old_tab_contents->web_contents()->GetRenderViewHost()-> | 466 old_tab_contents->web_contents()->GetRenderViewHost()-> |
451 FirePageBeforeUnload(false); | 467 FirePageBeforeUnload(false); |
452 } else { | 468 } else { |
453 // No unload handler to run, so delete asap. | 469 // No unload handler to run, so delete asap. |
454 ScheduleDeleteOldTabContents(old_tab_contents, NULL); | 470 ScheduleDeleteOldTabContents(old_tab_contents, NULL); |
455 } | 471 } |
456 | 472 |
457 // TODO(cbentzel): Should prerender_contents move to the pending delete | 473 // TODO(cbentzel): Should prerender_contents move to the pending delete |
458 // list, instead of deleting directly here? | 474 // list, instead of deleting directly here? |
459 AddToHistory(prerender_contents.get()); | 475 AddToHistory(prerender_contents.get()); |
460 RecordNavigation(url); | 476 RecordNavigation(url); |
461 return true; | 477 return true; |
462 } | 478 } |
463 | 479 |
464 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry, | 480 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry, |
465 FinalStatus final_status) { | 481 FinalStatus final_status) { |
466 DCHECK(CalledOnValidThread()); | 482 DCHECK(CalledOnValidThread()); |
467 DCHECK(entry); | 483 DCHECK(entry); |
468 // Confirm this entry has not already been moved to the pending delete list. | 484 // Confirm this entry has not already been moved to the pending delete list. |
469 DCHECK_EQ(0, std::count(pending_delete_list_.begin(), | 485 DCHECK_EQ(0, std::count(pending_delete_list_.begin(), |
470 pending_delete_list_.end(), entry)); | 486 pending_delete_list_.end(), entry)); |
471 | 487 |
472 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | 488 std::list<PrerenderData>::iterator it = |
473 it != prerender_list_.end(); | 489 FindIteratorForPrerenderContents(entry); |
474 ++it) { | |
475 if (it->contents_ == entry) { | |
476 bool swapped_in_dummy_replacement = false; | |
477 | 490 |
478 // If this PrerenderContents is being deleted due to a cancellation, | 491 // If this PrerenderContents is being deleted due to a cancellation, |
479 // we need to create a dummy replacement for PPLT accounting purposes | 492 // we need to create a dummy replacement for PPLT accounting purposes |
480 // for the Match Complete group. | 493 // for the Match Complete group. |
481 // This is the case if the cancellation is for any reason that would not | 494 // This is the case if the cancellation is for any reason that would not |
482 // occur in the control group case. | 495 // occur in the control group case. |
483 if (entry->match_complete_status() == | 496 if (it != active_prerender_list_.end()) { |
484 PrerenderContents::MATCH_COMPLETE_DEFAULT && | 497 if (entry->match_complete_status() == |
485 NeedMatchCompleteDummyForFinalStatus(final_status) && | 498 PrerenderContents::MATCH_COMPLETE_DEFAULT && |
486 ActuallyPrerendering()) { | 499 NeedMatchCompleteDummyForFinalStatus(final_status) && |
487 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. | 500 ActuallyPrerendering()) { |
488 // However, what if new conditions are added and | 501 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. |
489 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure | 502 // However, what if new conditions are added and |
490 // what's the best thing to do here. For now, I will just check whether | 503 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure |
491 // we are actually prerendering. | 504 // what's the best thing to do here. For now, I will just check whether |
492 entry->set_match_complete_status( | 505 // we are actually prerendering. |
493 PrerenderContents::MATCH_COMPLETE_REPLACED); | 506 entry->set_match_complete_status( |
494 if (PrerenderContents* dummy_replacement_prerender_contents = | 507 PrerenderContents::MATCH_COMPLETE_REPLACED); |
495 CreatePrerenderContents(entry->prerender_url(), | 508 PrerenderContents* dummy_replacement_prerender_contents = |
496 entry->referrer(), | 509 CreatePrerenderContents(entry->prerender_url(), entry->referrer(), |
497 entry->origin(), | 510 entry->origin(), entry->experiment_id()); |
498 entry->experiment_id())) { | 511 dummy_replacement_prerender_contents->MakeIntoDummyReplacementOf(entry); |
499 dummy_replacement_prerender_contents->set_match_complete_status( | 512 DCHECK(dummy_replacement_prerender_contents); |
500 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING); | 513 |
501 if (!dummy_replacement_prerender_contents->Init()) | 514 dummy_replacement_prerender_contents->set_match_complete_status( |
502 break; | 515 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING); |
503 dummy_replacement_prerender_contents-> | 516 DCHECK(dummy_replacement_prerender_contents->Init()); |
504 AddAliasURLsFromOtherPrerenderContents(entry); | 517 dummy_replacement_prerender_contents-> |
505 dummy_replacement_prerender_contents->set_match_complete_status( | 518 AddAliasURLsFromOtherPrerenderContents(entry); |
506 PrerenderContents::MATCH_COMPLETE_REPLACEMENT); | 519 dummy_replacement_prerender_contents->set_match_complete_status( |
507 it->contents_ = dummy_replacement_prerender_contents; | 520 PrerenderContents::MATCH_COMPLETE_REPLACEMENT); |
508 swapped_in_dummy_replacement = true; | 521 |
509 } | 522 it->contents = dummy_replacement_prerender_contents; |
510 } | 523 } else { |
511 if (!swapped_in_dummy_replacement) | 524 InvalidatePrerenderHandlesForPrerenderData(*it); |
512 prerender_list_.erase(it); | 525 active_prerender_list_.erase(it); |
513 break; | |
514 } | 526 } |
515 } | 527 } |
528 | |
516 AddToHistory(entry); | 529 AddToHistory(entry); |
517 pending_delete_list_.push_back(entry); | 530 pending_delete_list_.push_back(entry); |
518 | 531 |
519 // Destroy the old WebContents relatively promptly to reduce resource usage, | 532 // Destroy the old WebContents relatively promptly to reduce resource usage, |
520 // and in the case of HTML5 media, reduce the change of playing any sound. | 533 // and in the case of HTML5 media, reduce the change of playing any sound. |
521 PostCleanupTask(); | 534 PostCleanupTask(); |
522 } | 535 } |
523 | 536 |
524 // static | 537 // static |
525 void PrerenderManager::RecordPerceivedPageLoadTime( | 538 void PrerenderManager::RecordPerceivedPageLoadTime( |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
616 } | 629 } |
617 | 630 |
618 // static | 631 // static |
619 bool PrerenderManager::IsNoUseGroup() { | 632 bool PrerenderManager::IsNoUseGroup() { |
620 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; | 633 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; |
621 } | 634 } |
622 | 635 |
623 bool PrerenderManager::IsWebContentsPrerendering( | 636 bool PrerenderManager::IsWebContentsPrerendering( |
624 WebContents* web_contents) const { | 637 WebContents* web_contents) const { |
625 DCHECK(CalledOnValidThread()); | 638 DCHECK(CalledOnValidThread()); |
626 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); | 639 for (std::list<PrerenderData>::const_iterator it = |
627 it != prerender_list_.end(); | 640 active_prerender_list_.begin(); |
641 it != active_prerender_list_.end(); | |
628 ++it) { | 642 ++it) { |
629 TabContents* prerender_tab_contents = it->contents_->prerender_contents(); | 643 TabContents* prerender_tab_contents = |
dominich
2012/07/02 20:43:03
You removed a character and now it doesn't fit on
gavinp
2012/07/03 16:41:02
Done.
| |
644 it->contents->prerender_contents(); | |
630 if (prerender_tab_contents && | 645 if (prerender_tab_contents && |
631 prerender_tab_contents->web_contents() == web_contents) { | 646 prerender_tab_contents->web_contents() == web_contents) { |
632 return true; | 647 return true; |
633 } | 648 } |
634 } | 649 } |
635 | 650 |
636 // Also look through the pending-deletion list. | 651 // Also look through the pending-deletion list. |
637 for (std::list<PrerenderContents*>::const_iterator it = | 652 for (std::list<PrerenderContents*>::const_iterator it = |
638 pending_delete_list_.begin(); | 653 pending_delete_list_.begin(); |
639 it != pending_delete_list_.end(); | 654 it != pending_delete_list_.end(); |
640 ++it) { | 655 ++it) { |
641 TabContents* prerender_tab_contents = (*it)->prerender_contents(); | 656 TabContents* prerender_tab_contents = (*it)->prerender_contents(); |
642 if (prerender_tab_contents && | 657 if (prerender_tab_contents && |
643 prerender_tab_contents->web_contents() == web_contents) | 658 prerender_tab_contents->web_contents() == web_contents) |
644 return true; | 659 return true; |
645 } | 660 } |
646 | 661 |
647 return false; | 662 return false; |
648 } | 663 } |
649 | 664 |
650 bool PrerenderManager::DidPrerenderFinishLoading(const GURL& url) const { | |
651 DCHECK(CalledOnValidThread()); | |
652 PrerenderContents* contents = FindEntry(url); | |
653 return contents ? contents->has_finished_loading() : false; | |
654 } | |
655 | |
656 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) { | 665 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) { |
657 DCHECK(CalledOnValidThread()); | 666 DCHECK(CalledOnValidThread()); |
658 prerendered_tab_contents_set_.insert(web_contents); | 667 prerendered_tab_contents_set_.insert(web_contents); |
659 } | 668 } |
660 | 669 |
661 void PrerenderManager::MarkWebContentsAsWouldBePrerendered( | 670 void PrerenderManager::MarkWebContentsAsWouldBePrerendered( |
662 WebContents* web_contents) { | 671 WebContents* web_contents) { |
663 DCHECK(CalledOnValidThread()); | 672 DCHECK(CalledOnValidThread()); |
664 would_be_prerendered_map_[web_contents] = true; | 673 would_be_prerendered_map_[web_contents] = true; |
665 } | 674 } |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
761 histograms_->RecordFinalStatus(origin, | 770 histograms_->RecordFinalStatus(origin, |
762 experiment_id, | 771 experiment_id, |
763 mc_status, | 772 mc_status, |
764 final_status); | 773 final_status); |
765 } | 774 } |
766 | 775 |
767 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { | 776 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { |
768 prerender_conditions_.push_back(condition); | 777 prerender_conditions_.push_back(condition); |
769 } | 778 } |
770 | 779 |
771 bool PrerenderManager::IsPendingEntry(const GURL& url) const { | |
772 DCHECK(CalledOnValidThread()); | |
773 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); | |
774 it != prerender_list_.end(); | |
775 ++it) { | |
776 if (it->contents_->IsPendingEntry(url)) | |
777 return true; | |
778 } | |
779 return false; | |
780 } | |
781 | |
782 bool PrerenderManager::IsPrerendering(const GURL& url) const { | |
783 DCHECK(CalledOnValidThread()); | |
784 return (FindEntry(url) != NULL); | |
785 } | |
786 | |
787 void PrerenderManager::RecordNavigation(const GURL& url) { | 780 void PrerenderManager::RecordNavigation(const GURL& url) { |
788 DCHECK(CalledOnValidThread()); | 781 DCHECK(CalledOnValidThread()); |
789 | 782 |
790 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); | 783 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); |
791 CleanUpOldNavigations(); | 784 CleanUpOldNavigations(); |
792 } | 785 } |
793 | 786 |
794 // protected | 787 // protected |
795 void PrerenderManager::SetPrerenderContentsFactory( | 788 void PrerenderManager::SetPrerenderContentsFactory( |
796 PrerenderContents::Factory* prerender_contents_factory) { | 789 PrerenderContents::Factory* prerender_contents_factory) { |
797 DCHECK(CalledOnValidThread()); | 790 DCHECK(CalledOnValidThread()); |
798 prerender_contents_factory_.reset(prerender_contents_factory); | 791 prerender_contents_factory_.reset(prerender_contents_factory); |
799 } | 792 } |
800 | 793 |
801 void PrerenderManager::DoShutdown() { | 794 void PrerenderManager::DoShutdown() { |
802 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); | 795 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); |
803 STLDeleteElements(&prerender_conditions_); | 796 STLDeleteElements(&prerender_conditions_); |
804 on_close_tab_contents_deleters_.reset(); | 797 on_close_tab_contents_deleters_.reset(); |
805 profile_ = NULL; | 798 profile_ = NULL; |
799 | |
800 DCHECK(active_prerender_list_.empty()); | |
801 DCHECK(pending_prerender_list_.empty()); | |
802 DCHECK(prerender_weak_ptr_factory_map_.empty()); | |
806 } | 803 } |
807 | 804 |
808 // private | 805 // private |
809 bool PrerenderManager::AddPrerender( | 806 PrerenderHandle* PrerenderManager::AddPrerender( |
810 Origin origin, | 807 Origin origin, |
811 int process_id, | 808 int process_id, |
812 const GURL& url_arg, | 809 const GURL& url_arg, |
813 const content::Referrer& referrer, | 810 const content::Referrer& referrer, |
814 gfx::Size size, | 811 gfx::Size size, |
815 SessionStorageNamespace* session_storage_namespace) { | 812 SessionStorageNamespace* session_storage_namespace) { |
816 DCHECK(CalledOnValidThread()); | 813 DCHECK(CalledOnValidThread()); |
817 | 814 |
818 if (!IsEnabled()) | 815 if (!IsEnabled()) |
819 return false; | 816 return NULL; |
820 | 817 |
821 if (origin == ORIGIN_LINK_REL_PRERENDER && | 818 if (origin == ORIGIN_LINK_REL_PRERENDER && |
822 IsGoogleSearchResultURL(referrer.url)) { | 819 IsGoogleSearchResultURL(referrer.url)) { |
823 origin = ORIGIN_GWS_PRERENDER; | 820 origin = ORIGIN_GWS_PRERENDER; |
824 } | 821 } |
825 | 822 |
826 DeleteOldEntries(); | 823 DeleteOldEntries(); |
827 DeletePendingDeleteEntries(); | 824 DeletePendingDeleteEntries(); |
828 | 825 |
829 GURL url = url_arg; | 826 GURL url = url_arg; |
830 GURL alias_url; | 827 GURL alias_url; |
831 uint8 experiment = GetQueryStringBasedExperiment(url_arg); | 828 uint8 experiment = GetQueryStringBasedExperiment(url_arg); |
832 bool control_group_behavior = | 829 bool control_group_behavior = |
833 IsControlGroup() || IsControlGroupExperiment(experiment); | 830 IsControlGroup() || IsControlGroupExperiment(experiment); |
834 if (control_group_behavior && | 831 if (control_group_behavior && |
835 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { | 832 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { |
836 url = alias_url; | 833 url = alias_url; |
837 } | 834 } |
838 | 835 |
839 // From here on, we will record a FinalStatus so we need to register with the | 836 // From here on, we will record a FinalStatus so we need to register with the |
840 // histogram tracking. | 837 // histogram tracking. |
841 histograms_->RecordPrerender(origin, url_arg); | 838 histograms_->RecordPrerender(origin, url_arg); |
842 | 839 |
843 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) { | 840 if (PrerenderData* preexisting_prerender_data = |
844 ++prerender_contents_data->active_count_; | 841 FindPrerenderData(url, session_storage_namespace)) { |
845 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); | 842 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); |
846 return true; | 843 ++preexisting_prerender_data->client_count; |
844 return CreatePrerenderHandleForPrerenderData(preexisting_prerender_data); | |
847 } | 845 } |
848 | 846 |
849 // Do not prerender if there are too many render processes, and we would | 847 // Do not prerender if there are too many render processes, and we would |
850 // have to use an existing one. We do not want prerendering to happen in | 848 // have to use an existing one. We do not want prerendering to happen in |
851 // a shared process, so that we can always reliably lower the CPU | 849 // a shared process, so that we can always reliably lower the CPU |
852 // priority for prerendering. | 850 // priority for prerendering. |
853 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns | 851 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns |
854 // true, so that case needs to be explicitly checked for. | 852 // true, so that case needs to be explicitly checked for. |
855 // TODO(tburkard): Figure out how to cancel prerendering in the opposite | 853 // TODO(tburkard): Figure out how to cancel prerendering in the opposite |
856 // case, when a new tab is added to a process used for prerendering. | 854 // case, when a new tab is added to a process used for prerendering. |
857 // On Android we do reuse processes as we have a limited number of them and we | 855 // On Android we do reuse processes as we have a limited number of them and we |
858 // still want the benefits of prerendering even when several tabs are open. | 856 // still want the benefits of prerendering even when several tabs are open. |
859 #if !defined(OS_ANDROID) | 857 #if !defined(OS_ANDROID) |
860 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost( | 858 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost( |
861 profile_, url) && | 859 profile_, url) && |
862 !content::RenderProcessHost::run_renderer_in_process()) { | 860 !content::RenderProcessHost::run_renderer_in_process()) { |
863 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); | 861 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); |
864 return false; | 862 return NULL; |
865 } | 863 } |
866 #endif | 864 #endif |
867 | 865 |
868 // Check if enough time has passed since the last prerender. | 866 // Check if enough time has passed since the last prerender. |
869 if (!DoesRateLimitAllowPrerender()) { | 867 if (!DoesRateLimitAllowPrerender()) { |
870 // Cancel the prerender. We could add it to the pending prerender list but | 868 // Cancel the prerender. We could add it to the pending prerender list but |
871 // this doesn't make sense as the next prerender request will be triggered | 869 // this doesn't make sense as the next prerender request will be triggered |
872 // by a navigation and is unlikely to be the same site. | 870 // by a navigation and is unlikely to be the same site. |
873 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); | 871 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
874 return false; | 872 return NULL; |
875 } | 873 } |
876 | 874 |
877 PrerenderContents* prerender_contents = CreatePrerenderContents( | 875 PrerenderContents* prerender_contents = CreatePrerenderContents( |
878 url, referrer, origin, experiment); | 876 url, referrer, origin, experiment); |
879 if (!prerender_contents || !prerender_contents->Init()) | 877 if (!prerender_contents || !prerender_contents->Init()) |
880 return false; | 878 return NULL; |
881 | 879 |
882 histograms_->RecordPrerenderStarted(origin); | 880 histograms_->RecordPrerenderStarted(origin); |
883 | 881 |
884 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? | 882 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? |
885 PrerenderContentsData data(prerender_contents, GetCurrentTime()); | 883 active_prerender_list_.push_back(PrerenderData(this, prerender_contents)); |
886 | 884 |
887 prerender_list_.push_back(data); | 885 scoped_ptr<PrerenderHandle> prerender_handle( |
dominich
2012/07/02 20:43:03
why scoped_ptr here? You're going to release in a
gavinp
2012/07/03 16:41:02
Done.
| |
886 CreatePrerenderHandleForPrerenderData(&active_prerender_list_.back())); | |
888 | 887 |
889 last_prerender_start_time_ = GetCurrentTimeTicks(); | 888 last_prerender_start_time_ = GetCurrentTimeTicks(); |
890 | 889 |
891 if (size.IsEmpty()) | 890 if (size.IsEmpty()) |
892 size = config_.default_tab_bounds.size(); | 891 size = config_.default_tab_bounds.size(); |
893 | 892 |
894 data.contents_->StartPrerendering(process_id, size, session_storage_namespace, | 893 prerender_contents->StartPrerendering(process_id, size, |
895 control_group_behavior); | 894 session_storage_namespace, |
895 control_group_behavior); | |
896 | 896 |
897 while (prerender_list_.size() > config_.max_elements) { | 897 while (active_prerender_list_.size() > config_.max_elements) { |
898 data = prerender_list_.front(); | 898 prerender_contents = active_prerender_list_.front().contents; |
899 prerender_list_.pop_front(); | 899 DCHECK(prerender_contents); |
900 data.contents_->Destroy(FINAL_STATUS_EVICTED); | 900 prerender_contents->Destroy(FINAL_STATUS_EVICTED); |
dominich
2012/07/02 20:43:03
Did you add a unit test to ensure that Destroy rem
gavinp
2012/07/03 16:41:02
All of the existing unit tests should test this, s
| |
901 } | 901 } |
902 | |
902 StartSchedulingPeriodicCleanups(); | 903 StartSchedulingPeriodicCleanups(); |
903 return true; | 904 return prerender_handle.release(); |
904 } | |
905 | |
906 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { | |
907 return GetEntryButNotSpecifiedWC(url, NULL); | |
908 } | |
909 | |
910 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC( | |
911 const GURL& url, | |
912 WebContents* wc) { | |
913 DCHECK(CalledOnValidThread()); | |
914 DeleteOldEntries(); | |
915 DeletePendingDeleteEntries(); | |
916 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | |
917 it != prerender_list_.end(); | |
918 ++it) { | |
919 PrerenderContents* prerender_contents = it->contents_; | |
920 if (prerender_contents->MatchesURL(url, NULL) && | |
921 !IsNoSwapInExperiment(prerender_contents->experiment_id())) { | |
922 if (!prerender_contents->prerender_contents() || | |
923 !wc || | |
924 prerender_contents->prerender_contents()->web_contents() != wc) { | |
925 prerender_list_.erase(it); | |
926 return prerender_contents; | |
927 } | |
928 } | |
929 } | |
930 // Entry not found. | |
931 return NULL; | |
932 } | 905 } |
933 | 906 |
934 void PrerenderManager::StartSchedulingPeriodicCleanups() { | 907 void PrerenderManager::StartSchedulingPeriodicCleanups() { |
935 DCHECK(CalledOnValidThread()); | 908 DCHECK(CalledOnValidThread()); |
936 if (repeating_timer_.IsRunning()) | 909 if (repeating_timer_.IsRunning()) |
937 return; | 910 return; |
938 repeating_timer_.Start(FROM_HERE, | 911 repeating_timer_.Start(FROM_HERE, |
939 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), | 912 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), |
940 this, | 913 this, |
941 &PrerenderManager::PeriodicCleanup); | 914 &PrerenderManager::PeriodicCleanup); |
942 } | 915 } |
943 | 916 |
944 void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { | 917 void PrerenderManager::StopSchedulingPeriodicCleanups() { |
945 if (!prerender_list_.empty()) | |
946 return; | |
947 | |
948 DCHECK(CalledOnValidThread()); | 918 DCHECK(CalledOnValidThread()); |
949 repeating_timer_.Stop(); | 919 repeating_timer_.Stop(); |
950 } | 920 } |
951 | 921 |
952 void PrerenderManager::PeriodicCleanup() { | 922 void PrerenderManager::PeriodicCleanup() { |
953 DCHECK(CalledOnValidThread()); | 923 DCHECK(CalledOnValidThread()); |
954 DeleteOldTabContents(); | 924 DeleteOldTabContents(); |
955 DeleteOldEntries(); | 925 DeleteOldEntries(); |
926 if (active_prerender_list_.empty()) | |
927 StopSchedulingPeriodicCleanups(); | |
956 | 928 |
957 // Grab a copy of the current PrerenderContents pointers, so that we | 929 // Grab a copy of the current PrerenderContents pointers, so that we |
958 // will not interfere with potential deletions of the list. | 930 // will not interfere with potential deletions of the list. |
959 std::vector<PrerenderContents*> prerender_contents; | 931 std::vector<PrerenderContents*> |
960 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | 932 prerender_contents(active_prerender_list_.size()); |
dominich
2012/07/02 20:43:03
+100 for sizing the vector correctly.
-5 for not f
gavinp
2012/07/03 16:41:02
Now removed, as get_contents is dead.
| |
961 it != prerender_list_.end(); | 933 std::transform(active_prerender_list_.begin(), active_prerender_list_.end(), |
962 ++it) { | 934 prerender_contents.begin(), |
963 DCHECK(it->contents_); | 935 std::mem_fun_ref(&PrerenderData::get_contents)); |
964 prerender_contents.push_back(it->contents_); | 936 std::for_each(prerender_contents.begin(), prerender_contents.end(), |
965 } | 937 std::mem_fun( |
966 for (std::vector<PrerenderContents*>::iterator it = | 938 &PrerenderContents::DestroyWhenUsingTooManyResources)); |
967 prerender_contents.begin(); | |
968 it != prerender_contents.end(); | |
969 ++it) { | |
970 (*it)->DestroyWhenUsingTooManyResources(); | |
971 } | |
972 | 939 |
973 DeletePendingDeleteEntries(); | 940 DeletePendingDeleteEntries(); |
974 } | 941 } |
975 | 942 |
976 void PrerenderManager::PostCleanupTask() { | 943 void PrerenderManager::PostCleanupTask() { |
977 DCHECK(CalledOnValidThread()); | 944 DCHECK(CalledOnValidThread()); |
978 MessageLoop::current()->PostTask( | 945 MessageLoop::current()->PostTask( |
979 FROM_HERE, | 946 FROM_HERE, |
980 base::Bind(&PrerenderManager::PeriodicCleanup, | 947 base::Bind(&PrerenderManager::PeriodicCleanup, |
981 weak_factory_.GetWeakPtr())); | 948 weak_factory_.GetWeakPtr())); |
982 } | 949 } |
983 | 950 |
984 base::TimeDelta PrerenderManager::GetMaxAge() const { | 951 base::TimeDelta PrerenderManager::GetMaxAge() const { |
985 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ? | 952 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ? |
986 base::TimeDelta::FromSeconds(300) : config_.max_age); | 953 base::TimeDelta::FromSeconds(300) : config_.max_age); |
987 } | 954 } |
988 | 955 |
989 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { | 956 bool PrerenderManager::IsPrerenderFresh(base::TimeTicks start) const { |
dominich
2012/07/02 20:43:03
Y U NO const base::TimeTicks start?
gavinp
2012/07/03 16:41:02
Done.
| |
990 DCHECK(CalledOnValidThread()); | 957 DCHECK(CalledOnValidThread()); |
991 base::Time now = GetCurrentTime(); | 958 base::TimeTicks now = GetCurrentTimeTicks(); |
gavinp
2012/07/03 16:41:02
Adeed bonus: const base::TimeTicks now.
dominich
2012/07/03 17:08:39
Even better, return GetCurrentTimeTicks() - start
gavinp
2012/07/03 18:45:40
Done.
| |
992 return (now - start < GetMaxAge()); | 959 return now - start < GetMaxAge(); |
993 } | 960 } |
994 | 961 |
995 void PrerenderManager::DeleteOldEntries() { | 962 void PrerenderManager::DeleteOldEntries() { |
996 DCHECK(CalledOnValidThread()); | 963 DCHECK(CalledOnValidThread()); |
997 while (!prerender_list_.empty()) { | 964 while (!active_prerender_list_.empty()) { |
998 PrerenderContentsData data = prerender_list_.front(); | 965 PrerenderContents* contents = active_prerender_list_.front().contents; |
999 if (IsPrerenderElementFresh(data.start_time_)) | 966 DCHECK(contents); |
967 if (IsPrerenderFresh(contents->load_start_time())) | |
1000 return; | 968 return; |
1001 data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); | 969 contents->Destroy(FINAL_STATUS_TIMED_OUT); |
1002 } | 970 } |
1003 MaybeStopSchedulingPeriodicCleanups(); | |
1004 } | 971 } |
1005 | 972 |
1006 base::Time PrerenderManager::GetCurrentTime() const { | 973 base::Time PrerenderManager::GetCurrentTime() const { |
1007 return base::Time::Now(); | 974 return base::Time::Now(); |
1008 } | 975 } |
1009 | 976 |
1010 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { | 977 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { |
1011 return base::TimeTicks::Now(); | 978 return base::TimeTicks::Now(); |
1012 } | 979 } |
1013 | 980 |
1014 PrerenderContents* PrerenderManager::CreatePrerenderContents( | 981 PrerenderContents* PrerenderManager::CreatePrerenderContents( |
1015 const GURL& url, | 982 const GURL& url, |
1016 const content::Referrer& referrer, | 983 const content::Referrer& referrer, |
1017 Origin origin, | 984 Origin origin, |
1018 uint8 experiment_id) { | 985 uint8 experiment_id) { |
1019 DCHECK(CalledOnValidThread()); | 986 DCHECK(CalledOnValidThread()); |
1020 return prerender_contents_factory_->CreatePrerenderContents( | 987 return prerender_contents_factory_->CreatePrerenderContents( |
1021 this, prerender_tracker_, profile_, url, | 988 this, prerender_tracker_, profile_, url, |
1022 referrer, origin, experiment_id); | 989 referrer, origin, experiment_id); |
1023 } | 990 } |
1024 | 991 |
1025 void PrerenderManager::DeletePendingDeleteEntries() { | 992 void PrerenderManager::DeletePendingDeleteEntries() { |
1026 while (!pending_delete_list_.empty()) { | 993 while (!pending_delete_list_.empty()) { |
1027 PrerenderContents* contents = pending_delete_list_.front(); | 994 PrerenderContents* contents = pending_delete_list_.front(); |
1028 pending_delete_list_.pop_front(); | 995 pending_delete_list_.pop_front(); |
1029 delete contents; | 996 delete contents; |
1030 } | 997 } |
1031 } | 998 } |
1032 | 999 |
1033 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData( | 1000 PrerenderHandle* PrerenderManager::CreatePrerenderHandleForPrerenderData( |
1034 const GURL& url) { | 1001 PrerenderData* prerender_data) { |
1035 DCHECK(CalledOnValidThread()); | 1002 PrerenderWeakPtrFactoryMap::value_type map_value(prerender_data, NULL); |
dominich
2012/07/02 20:43:03
base::WeakPtrFactory<PrerenderData> prerender_data
| |
1036 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url); | 1003 std::pair<PrerenderWeakPtrFactoryMap::iterator, bool> |
1037 if (it == prerender_list_.end()) | 1004 insert_result = prerender_weak_ptr_factory_map_.insert(map_value); |
1038 return NULL; | 1005 if (insert_result.second) |
1039 PrerenderContentsData& prerender_contents_data = *it; | 1006 insert_result.first->second = |
1040 return &prerender_contents_data; | 1007 new base::WeakPtrFactory<PrerenderData>(prerender_data); |
1008 base::WeakPtr<PrerenderData> weak_prerender_data = | |
1009 insert_result.first->second->GetWeakPtr(); | |
dominich
2012/07/02 20:43:03
if insert fails this will be NULL. See my version
gavinp
2012/07/03 16:41:02
If insert fails, then there was a pre-existing ele
| |
1010 return new PrerenderHandle(weak_prerender_data); | |
1041 } | 1011 } |
1042 | 1012 |
1043 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const { | 1013 void PrerenderManager::InvalidatePrerenderHandlesForPrerenderData( |
1044 DCHECK(CalledOnValidThread()); | 1014 const PrerenderData& prerender_data) { |
1045 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); | 1015 PrerenderWeakPtrFactoryMap::iterator it = |
1046 it != prerender_list_.end(); | 1016 prerender_weak_ptr_factory_map_.find(&prerender_data); |
1017 if (it != prerender_weak_ptr_factory_map_.end()) { | |
1018 delete it->second; | |
1019 prerender_weak_ptr_factory_map_.erase(it); | |
1020 } | |
1021 } | |
1022 | |
1023 PrerenderManager::PrerenderData* PrerenderManager::FindPrerenderData( | |
1024 const GURL& url, | |
1025 const SessionStorageNamespace* session_storage_namespace) { | |
1026 for (std::list<PrerenderData>::iterator it = active_prerender_list_.begin(); | |
dominich
2012/07/02 20:43:03
Why did you remove the typedef for std::list<Prere
gavinp
2012/07/03 16:41:02
I didn't think it saved much space; mmenke is not
dominich
2012/07/03 17:08:39
so much more readable though
| |
1027 it != active_prerender_list_.end(); | |
1047 ++it) { | 1028 ++it) { |
1048 if (it->contents_->MatchesURL(url, NULL)) | 1029 PrerenderContents* prerender_contents = it->contents; |
1049 return it->contents_; | 1030 if (prerender_contents->Matches(url, session_storage_namespace)) |
1031 return &(*it); | |
1050 } | 1032 } |
1051 // Entry not found. | |
1052 return NULL; | 1033 return NULL; |
1053 } | 1034 } |
1054 | 1035 |
1055 PrerenderManager::PrerenderContentsDataList::iterator | 1036 PrerenderManager::PrerenderData* |
1056 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( | 1037 PrerenderManager::FindPrerenderDataForChildAndRoute( |
1057 const std::pair<int, int>& child_route_id_pair) { | 1038 const int child_id, const int route_id) { |
1058 PrerenderContentsDataList::iterator it = prerender_list_.begin(); | 1039 for (std::list<PrerenderData>::iterator it = active_prerender_list_.begin(); |
1059 for (; it != prerender_list_.end(); ++it) { | 1040 it != active_prerender_list_.end(); |
1060 PrerenderContents* prerender_contents = it->contents_; | 1041 ++it) { |
1042 PrerenderContents* prerender_contents = it->contents; | |
1061 | 1043 |
1062 int child_id; | 1044 int contents_child_id; |
1063 int route_id; | 1045 if (!prerender_contents->GetChildId(&contents_child_id)) |
1064 bool has_child_id = prerender_contents->GetChildId(&child_id); | 1046 continue; |
1065 bool has_route_id = has_child_id && | 1047 int contents_route_id; |
1066 prerender_contents->GetRouteId(&route_id); | 1048 if (!prerender_contents->GetRouteId(&contents_route_id)) |
1049 continue; | |
1067 | 1050 |
1068 if (has_child_id && has_route_id && | 1051 if (contents_child_id == child_id && contents_route_id == route_id) |
1069 child_id == child_route_id_pair.first && | 1052 return &(*it); |
1070 route_id == child_route_id_pair.second) { | |
1071 break; | |
1072 } | |
1073 } | 1053 } |
1074 return it; | 1054 return NULL; |
1075 } | 1055 } |
1076 | 1056 |
1077 PrerenderManager::PrerenderContentsDataList::iterator | 1057 std::list<PrerenderManager::PrerenderData>::iterator |
1078 PrerenderManager::FindPrerenderContentsForURL(const GURL& url) { | 1058 PrerenderManager::FindIteratorForPrerenderContents( |
1079 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); | 1059 PrerenderContents* prerender_contents) { |
1080 it != prerender_list_.end(); ++it) { | 1060 for (std::list<PrerenderData>::iterator it = active_prerender_list_.begin(); |
1081 if (it->contents_->MatchesURL(url, NULL)) | 1061 it != active_prerender_list_.end(); |
1062 ++it) { | |
1063 if (prerender_contents == it->contents) | |
1082 return it; | 1064 return it; |
1083 } | 1065 } |
1084 return prerender_list_.end(); | 1066 return active_prerender_list_.end(); |
1085 } | 1067 } |
1086 | 1068 |
1087 bool PrerenderManager::DoesRateLimitAllowPrerender() const { | 1069 bool PrerenderManager::DoesRateLimitAllowPrerender() const { |
1088 DCHECK(CalledOnValidThread()); | 1070 DCHECK(CalledOnValidThread()); |
1089 base::TimeDelta elapsed_time = | 1071 base::TimeDelta elapsed_time = |
1090 GetCurrentTimeTicks() - last_prerender_start_time_; | 1072 GetCurrentTimeTicks() - last_prerender_start_time_; |
1091 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); | 1073 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); |
1092 if (!config_.rate_limit_enabled) | 1074 if (!config_.rate_limit_enabled) |
1093 return true; | 1075 return true; |
1094 return elapsed_time > | 1076 return elapsed_time > |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1136 void PrerenderManager::AddToHistory(PrerenderContents* contents) { | 1118 void PrerenderManager::AddToHistory(PrerenderContents* contents) { |
1137 PrerenderHistory::Entry entry(contents->prerender_url(), | 1119 PrerenderHistory::Entry entry(contents->prerender_url(), |
1138 contents->final_status(), | 1120 contents->final_status(), |
1139 contents->origin(), | 1121 contents->origin(), |
1140 base::Time::Now()); | 1122 base::Time::Now()); |
1141 prerender_history_->AddEntry(entry); | 1123 prerender_history_->AddEntry(entry); |
1142 } | 1124 } |
1143 | 1125 |
1144 Value* PrerenderManager::GetActivePrerendersAsValue() const { | 1126 Value* PrerenderManager::GetActivePrerendersAsValue() const { |
1145 ListValue* list_value = new ListValue(); | 1127 ListValue* list_value = new ListValue(); |
1146 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); | 1128 for (std::list<PrerenderData>::const_iterator it = |
1147 it != prerender_list_.end(); | 1129 active_prerender_list_.begin(); |
1130 it != active_prerender_list_.end(); | |
1148 ++it) { | 1131 ++it) { |
1149 Value* prerender_value = it->contents_->GetAsValue(); | 1132 if (Value* prerender_value = it->contents->GetAsValue()) |
1150 if (!prerender_value) | 1133 list_value->Append(prerender_value); |
1151 continue; | |
1152 list_value->Append(prerender_value); | |
1153 } | 1134 } |
1154 return list_value; | 1135 return list_value; |
1155 } | 1136 } |
1156 | 1137 |
1157 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { | 1138 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { |
1158 DeleteOldTabContents(); | 1139 DeleteOldTabContents(); |
1159 while (!prerender_list_.empty()) { | 1140 while (!active_prerender_list_.empty()) { |
1160 PrerenderContentsData data = prerender_list_.front(); | 1141 PrerenderContents* contents = active_prerender_list_.front().contents; |
1161 prerender_list_.pop_front(); | 1142 contents->Destroy(final_status); |
1162 data.contents_->Destroy(final_status); | |
1163 } | 1143 } |
1164 DeletePendingDeleteEntries(); | 1144 DeletePendingDeleteEntries(); |
1165 } | 1145 } |
1166 | 1146 |
1167 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed( | 1147 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed( |
1168 PrerenderContents* prerender_contents, | 1148 PrerenderContents* prerender_contents, |
1169 FinalStatus final_status) { | 1149 FinalStatus final_status) { |
1170 prerender_contents->set_match_complete_status( | 1150 prerender_contents->set_match_complete_status( |
1171 PrerenderContents::MATCH_COMPLETE_REPLACED); | 1151 PrerenderContents::MATCH_COMPLETE_REPLACED); |
1172 histograms_->RecordFinalStatus(prerender_contents->origin(), | 1152 histograms_->RecordFinalStatus(prerender_contents->origin(), |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1211 if (!render_process_host || !render_process_host->GetBrowserContext()) | 1191 if (!render_process_host || !render_process_host->GetBrowserContext()) |
1212 return NULL; | 1192 return NULL; |
1213 Profile* profile = Profile::FromBrowserContext( | 1193 Profile* profile = Profile::FromBrowserContext( |
1214 render_process_host->GetBrowserContext()); | 1194 render_process_host->GetBrowserContext()); |
1215 if (!profile) | 1195 if (!profile) |
1216 return NULL; | 1196 return NULL; |
1217 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); | 1197 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); |
1218 } | 1198 } |
1219 | 1199 |
1220 } // namespace prerender | 1200 } // namespace prerender |
1201 | |
OLD | NEW |