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

Side by Side Diff: chrome/browser/prerender/prerender_manager.cc

Issue 10553029: Handle interface to prerenders. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/prerender/prerender_manager.h" 5 #include "chrome/browser/prerender/prerender_manager.h"
6 6
7 #include <set> 7 #include <set>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 // static 163 // static
164 bool PrerenderManager::is_prefetch_enabled_ = false; 164 bool PrerenderManager::is_prefetch_enabled_ = false;
165 165
166 // static 166 // static
167 int PrerenderManager::prerenders_per_session_count_ = 0; 167 int PrerenderManager::prerenders_per_session_count_ = 0;
168 168
169 // static 169 // static
170 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = 170 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ =
171 PRERENDER_MODE_ENABLED; 171 PRERENDER_MODE_ENABLED;
172 172
173 struct PrerenderManager::PrerenderContentsData { 173 // A PrerenderContentsData represents a running prerender. A list of WeakPtr
174 // to these objects is kept in prerender_list_ as the canonical list of running
175 // prerenders.
176 class PrerenderManager::PrerenderContentsData :
177 public PrerenderHandleInterface {
dominich 2012/06/18 15:32:44 I don't understand why this has a PrerenderHandle
gavinp 2012/06/18 16:40:48 Every other instance of Handle in our code base is
178 public:
179 // These STL predicates all operate on WeakPtrs, for compatibility with
180 // PrerenderManager::PrerenderContentsList, which contains
181 // base::WeakPtr<PrerenderContentsData>.
182
183 // This predicate tests if the weak-pointed to object has been deleted.
184 class DeletedPredicate;
185 // This predicate compares the object to another PrerenderHandle for equality.
186 class EqualsPredicate;
187 // Given a |base::Time|, is the current prerender expired?
188 class ExpiredPredicate;
189 // Given an |url| and a |session_storage_namespace|, This predicate tests if
190 // this PrerenderContentsData
191 class MatchPredicate;
dominich 2012/06/18 15:32:44 I smell over-engineering. These were already handl
gavinp 2012/06/18 16:40:48 Yes, I hate these and plan to remove them. On 201
192
193 // Creates a PrerenderContentsData for a prerender starting right now.
194 PrerenderContentsData(PrerenderManager* manager,
195 PrerenderContents* contents);
196
197 base::WeakPtr<PrerenderContentsData> AsWeakPtr() {
198 return weak_factory_.GetWeakPtr();
199 }
200
201 PrerenderContents* contents() { return contents_; }
202 const PrerenderContents* contents() const { return contents_; }
203
204 void set_contents(PrerenderContents* contents) { contents_ = contents; }
205
206 bool IsExpiredAt(base::Time time) const;
207 bool IsDestroyed() const;
208 bool IsStarted() const;
209
210 // from PrerenderHandleInterface
211 virtual bool DidFinishLoading() const OVERRIDE;
212 virtual bool IsPending() const OVERRIDE;
213 virtual void Destroy() OVERRIDE;
214
215 static PrerenderContentsData* FromPrerenderHandle(PrerenderHandleInterface* in terface);
216
217 private:
218 virtual ~PrerenderContentsData();
219
220 base::WeakPtrFactory<PrerenderContentsData> weak_factory_;
221 PrerenderManager const* manager_;
222 base::Time start_time_;
223 base::Time expiry_time_;
174 PrerenderContents* contents_; 224 PrerenderContents* contents_;
175 base::Time start_time_; 225 };
176 int active_count_; 226
177 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) 227 class PrerenderManager::PrerenderContentsData::DeletedPredicate {
178 : contents_(contents), 228 public:
179 start_time_(start_time), 229 bool operator()(base::WeakPtr<PrerenderContentsData> item) const {
180 active_count_(1) { 230 return !item;
181 CHECK(contents);
182 } 231 }
183 }; 232 };
184 233
234 class PrerenderManager::PrerenderContentsData::EqualsPredicate {
235 public:
236 EqualsPredicate(PrerenderHandle handle) : handle_(handle) {}
237
238 bool operator()(const base::WeakPtr<PrerenderContentsData>& item) const {
239 return handle_.get() == item.get();
240 }
241
242 private:
243 PrerenderHandle handle_;
244 };
245
246 class PrerenderManager::PrerenderContentsData::ExpiredPredicate {
247 public:
248 ExpiredPredicate(base::Time now) : now_(now) {}
249
250 bool operator()(base::WeakPtr<PrerenderContentsData> item) const {
251 return item && item->IsExpiredAt(now_);
252 }
253 private:
254 base::Time now_;
255 };
256
257 class PrerenderManager::PrerenderContentsData::MatchPredicate {
258 public:
259 MatchPredicate(const GURL& url,
260 content::SessionStorageNamespace* session_storage_namespace)
261 : url_(url),
262 session_storage_namespace_(session_storage_namespace) {
263 }
264
265 bool operator()(base::WeakPtr<PrerenderContentsData> item) const {
266 return item && item->contents_ &&
267 item->contents_->Matches(url_, session_storage_namespace_);
268 }
269
270 private:
271 GURL url_;
272 content::SessionStorageNamespace* session_storage_namespace_;
273 };
274
275 PrerenderManager::PrerenderContentsData::PrerenderContentsData(
276 PrerenderManager* manager,
277 PrerenderContents* contents) : weak_factory_(this),
278 manager_(manager),
279 start_time_(manager_->GetCurrentTime()),
dominich 2012/06/18 15:32:44 why is the manager the arbiter of what the time is
280 expiry_time_(start_time_ +
dominich 2012/06/18 15:32:44 if this can be inferred from the start_time_ there
281 manager_->GetMaxAge()),
282 contents_(contents) {
283 }
284
285 bool PrerenderManager::PrerenderContentsData::IsExpiredAt(
286 base::Time time) const {
287 return time > expiry_time_;
288 }
289
290 bool PrerenderManager::PrerenderContentsData::IsDestroyed() const {
291 return !manager_ && !contents_;
292 }
293
294 bool PrerenderManager::PrerenderContentsData::IsStarted() const {
295 return manager_ && contents_;
296 }
297
298 bool PrerenderManager::PrerenderContentsData::DidFinishLoading() const {
299 return contents_ ? contents_->has_finished_loading() : false;
300 }
301
302 bool PrerenderManager::PrerenderContentsData::IsPending() const {
303 DCHECK(!IsDestroyed());
304 return manager_ && !contents_;
305 }
306
307 // static
308 PrerenderManager::PrerenderContentsData*
309 PrerenderManager::PrerenderContentsData::FromPrerenderHandle(
310 PrerenderHandleInterface* interface) {
311 return static_cast<PrerenderContentsData*>(interface);
dominich 2012/06/18 15:32:44 Code smell. If you need a static method to cast fr
312 }
313
314 PrerenderManager::PrerenderContentsData::~PrerenderContentsData() {
315 DVLOG(4) << "PrerenderContentsData::~PrerenderContentsData()";
316 if (contents_)
317 contents_->Destroy(FINAL_STATUS_CANCELLED);
318 }
319
320 void PrerenderManager::PrerenderContentsData::Destroy() {
321 DCHECK(!IsDestroyed());
322 contents_ = NULL;
323 manager_ = NULL;
324 }
325
185 struct PrerenderManager::NavigationRecord { 326 struct PrerenderManager::NavigationRecord {
186 GURL url_; 327 GURL url_;
187 base::TimeTicks time_; 328 base::TimeTicks time_;
188 NavigationRecord(const GURL& url, base::TimeTicks time) 329 NavigationRecord(const GURL& url, base::TimeTicks time)
189 : url_(url), 330 : url_(url),
190 time_(time) { 331 time_(time) {
191 } 332 }
192 }; 333 };
193 334
194 PrerenderManager::PrerenderManager(Profile* profile, 335 PrerenderManager::PrerenderManager(Profile* profile,
(...skipping 13 matching lines...) Expand all
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 349 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
209 } 350 }
210 351
211 PrerenderManager::~PrerenderManager() { 352 PrerenderManager::~PrerenderManager() {
212 } 353 }
213 354
214 void PrerenderManager::Shutdown() { 355 void PrerenderManager::Shutdown() {
215 DoShutdown(); 356 DoShutdown();
216 } 357 }
217 358
218 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( 359 PrerenderHandle PrerenderManager::AddPrerenderFromLinkRelPrerender(
219 int process_id, 360 int process_id,
220 int route_id, 361 int route_id,
221 const GURL& url, 362 const GURL& url,
222 const content::Referrer& referrer, 363 const content::Referrer& referrer,
223 const gfx::Size& size) { 364 const gfx::Size& size) {
224 #if defined(OS_ANDROID) 365 #if defined(OS_ANDROID)
225 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable 366 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable
226 // link-prerender and enable omnibox-prerender only. 367 // link-prerender and enable omnibox-prerender only.
227 return false; 368 return PrerenderHandle();
228 #else 369 #else
229 std::pair<int, int> child_route_id_pair(process_id, route_id); 370 if (PrerenderContentsData* contents_data =
230 PrerenderContentsDataList::iterator it = 371 FindContentsDataForChildAndRouteId(process_id, route_id)) {
231 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); 372 // If we are attempting to prerender from inside of a prerender, make a
232 if (it != prerender_list_.end()) { 373 // pending prerender in the contents, which will launch again when the
233 // Instead of prerendering from inside of a running prerender, we will defer 374 // user navigates to the launcher.
234 // this request until its launcher is made visible. 375 return contents_data->contents()->AddPendingPrerender(url, referrer, size);
dominich 2012/06/18 15:32:44 Ah, now I see why you need this to return a valid
235 it->contents_->AddPendingPrerender(url, referrer, size);
236 return true;
237 } 376 }
238 377
239 // Unit tests pass in a process_id == -1. 378 // Unit tests pass in a process_id == -1.
240 RenderViewHost* source_render_view_host = NULL; 379 RenderViewHost* source_render_view_host = NULL;
241 SessionStorageNamespace* session_storage_namespace = NULL; 380 SessionStorageNamespace* session_storage_namespace = NULL;
242 if (process_id != -1) { 381 if (process_id != -1) {
243 source_render_view_host = 382 source_render_view_host =
244 RenderViewHost::FromID(process_id, route_id); 383 RenderViewHost::FromID(process_id, route_id);
245 if (!source_render_view_host || !source_render_view_host->GetView()) 384 if (!source_render_view_host || !source_render_view_host->GetView())
246 return false; 385 return PrerenderHandle();
247 session_storage_namespace = 386 session_storage_namespace =
248 source_render_view_host->GetSessionStorageNamespace(); 387 source_render_view_host->GetSessionStorageNamespace();
249 } 388 }
250 389
251 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, 390 return AddPrerender(ORIGIN_LINK_REL_PRERENDER,
252 process_id, url, referrer, size, 391 process_id, url, referrer, size,
253 session_storage_namespace); 392 session_storage_namespace);
254 #endif 393 #endif
255 } 394 }
256 395
257 bool PrerenderManager::AddPrerenderFromOmnibox( 396 PrerenderHandle PrerenderManager::AddPrerenderFromOmnibox(
258 const GURL& url, 397 const GURL& url,
259 SessionStorageNamespace* session_storage_namespace) { 398 SessionStorageNamespace* session_storage_namespace) {
260 if (!IsOmniboxEnabled(profile_)) 399 if (!IsOmniboxEnabled(profile_))
261 return false; 400 return PrerenderHandle();
262 return AddPrerender(ORIGIN_OMNIBOX, -1, url, 401 return AddPrerender(ORIGIN_OMNIBOX, -1, url,
263 content::Referrer(), gfx::Size(), 402 content::Referrer(), gfx::Size(),
264 session_storage_namespace); 403 session_storage_namespace);
265 } 404 }
266 405
267 void PrerenderManager::MaybeCancelPrerender(const GURL& url) {
268 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
269 if (it == prerender_list_.end())
270 return;
271 PrerenderContentsData& prerender_contents_data = *it;
272 if (--prerender_contents_data.active_count_ == 0)
273 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED);
274 }
275
276 void PrerenderManager::DestroyPrerenderForRenderView( 406 void PrerenderManager::DestroyPrerenderForRenderView(
277 int process_id, int view_id, FinalStatus final_status) { 407 int process_id, int view_id, FinalStatus final_status) {
278 DCHECK(CalledOnValidThread()); 408 DCHECK(CalledOnValidThread());
279 PrerenderContentsDataList::iterator it = 409 if (PrerenderContentsData* contents_data =
280 FindPrerenderContentsForChildRouteIdPair( 410 FindContentsDataForChildAndRouteId(process_id, view_id)) {
281 std::make_pair(process_id, view_id)); 411 contents_data->contents()->Destroy(final_status);
282 if (it != prerender_list_.end()) {
283 PrerenderContents* prerender_contents = it->contents_;
284 prerender_contents->Destroy(final_status);
285 } 412 }
286 } 413 }
287 414
288 void PrerenderManager::CancelAllPrerenders() { 415 void PrerenderManager::CancelAllPrerenders() {
289 DCHECK(CalledOnValidThread()); 416 DCHECK(CalledOnValidThread());
290 while (!prerender_list_.empty()) { 417 while (!prerender_list_.empty()) {
291 PrerenderContentsData data = prerender_list_.front(); 418 if (PrerenderContentsData* contents_data = prerender_list_.front()) {
292 DCHECK(data.contents_); 419 DCHECK(contents_data->contents());
293 data.contents_->Destroy(FINAL_STATUS_CANCELLED); 420 contents_data->contents()->Destroy(FINAL_STATUS_CANCELLED);
294 } 421 }
295 }
296
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 } 422 }
305 } 423 }
306 424
307 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, 425 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
308 const GURL& url) { 426 const GURL& url) {
427 DCHECK(web_contents);
309 DCHECK(CalledOnValidThread()); 428 DCHECK(CalledOnValidThread());
310 DCHECK(!IsWebContentsPrerendering(web_contents)); 429 DCHECK(!IsWebContentsPrerendering(web_contents));
311 430
431 DVLOG(6) << "entering MaybeUsePrerenderedPage...";
432
433 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost();
434 content::SessionStorageNamespace* old_session_storage_namespace =
435 old_render_view_host->GetSessionStorageNamespace();
436
312 scoped_ptr<PrerenderContents> prerender_contents( 437 scoped_ptr<PrerenderContents> prerender_contents(
313 GetEntryButNotSpecifiedWC(url, web_contents)); 438 ClaimPrerender(web_contents, url, old_session_storage_namespace));
439
314 if (prerender_contents.get() == NULL) 440 if (prerender_contents.get() == NULL)
315 return false; 441 return false;
316 442
443
444 DVLOG(2) << "MaybeUsePrerenderedPage claimed a prerender";
445
317 // Do not use the prerendered version if there is an opener object. 446 // Do not use the prerendered version if there is an opener object.
318 if (web_contents->HasOpener()) { 447 if (web_contents->HasOpener()) {
319 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER); 448 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER);
449 DVLOG(3) << "... but it's a window opener.";
320 return false; 450 return false;
321 } 451 }
322 452
323 // Even if we match, the location.hash might be different. Record this as a 453
324 // separate final status. 454
325 GURL matching_url; 455 if (!prerender_contents->Matches(url, old_session_storage_namespace)) {
326 bool url_matches = prerender_contents->MatchesURL(url, &matching_url); 456 NOTREACHED() << "Something didn't match.";
327 DCHECK(url_matches); 457 DVLOG(3) << "... but there's a bad session storage namespace";
328 if (url_matches && url.ref() != matching_url.ref()) {
329 prerender_contents.release()->Destroy(FINAL_STATUS_FRAGMENT_MISMATCH);
330 return false; 458 return false;
331 } 459 }
332 460
333 // If we are just in the control group (which can be detected by noticing 461 // 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 462 // 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. 463 // would be showing a prerendered contents, but otherwise, don't do anything.
336 if (!prerender_contents->prerendering_has_started()) { 464 if (!prerender_contents->prerendering_has_started()) {
337 MarkWebContentsAsWouldBePrerendered(web_contents); 465 MarkWebContentsAsWouldBePrerendered(web_contents);
338 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); 466 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED);
467 DVLOG(3) << "... but we're in the control group, so we'll destroy it unused. ";
339 return false; 468 return false;
340 } 469 }
341 470
342 // Don't use prerendered pages if debugger is attached to the tab. 471 // Don't use prerendered pages if debugger is attached to the tab.
343 // See http://crbug.com/98541 472 // See http://crbug.com/98541
344 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { 473 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) {
345 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(), 474 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(),
346 FINAL_STATUS_DEVTOOLS_ATTACHED); 475 FINAL_STATUS_DEVTOOLS_ATTACHED);
476 DVLOG(3) << "... but the dev tools are attached.";
347 return false; 477 return false;
348 } 478 }
349 479
350 // If the prerendered page is in the middle of a cross-site navigation, 480 // 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. 481 // don't swap it in because there isn't a good way to merge histories.
352 if (prerender_contents->IsCrossSiteNavigationPending()) { 482 if (prerender_contents->IsCrossSiteNavigationPending()) {
353 DestroyAndMarkMatchCompleteAsUsed( 483 DestroyAndMarkMatchCompleteAsUsed(
354 prerender_contents.release(), 484 prerender_contents.release(),
355 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); 485 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING);
486 DVLOG(3) << "... but cross site navigation is pending.";
356 return false; 487 return false;
357 } 488 }
358 489
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. 490 // If we don't want to use prerenders at all, we are done.
375 // For bookkeeping purposes, we need to mark this WebContents to 491 // For bookkeeping purposes, we need to mark this WebContents to
376 // reflect that it would have been prerendered. 492 // reflect that it would have been prerendered.
377 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { 493 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) {
378 MarkWebContentsAsWouldBePrerendered(web_contents); 494 MarkWebContentsAsWouldBePrerendered(web_contents);
379 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); 495 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED);
496 DVLOG(3) << "... we are in the no use experimental group...";
380 return false; 497 return false;
381 } 498 }
382 499
383 int child_id, route_id; 500 int child_id, route_id;
384 CHECK(prerender_contents->GetChildId(&child_id)); 501 DCHECK(prerender_contents->GetChildId(&child_id));
385 CHECK(prerender_contents->GetRouteId(&route_id)); 502 DCHECK(prerender_contents->GetRouteId(&route_id));
386 503
387 // Try to set the prerendered page as used, so any subsequent attempts to 504 // 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 505 // cancel on other threads will fail. If this fails because the prerender
389 // was already cancelled, possibly on another thread, fail. 506 // was already cancelled, possibly on another thread, fail.
390 if (!prerender_tracker_->TryUse(child_id, route_id)) 507 if (!prerender_tracker_->TryUse(child_id, route_id)) {
508 DVLOG(3) << "... prerender_tracker_->TryUse failed!";
391 return false; 509 return false;
510 }
392 511
393 if (!prerender_contents->load_start_time().is_null()) { 512 if (!prerender_contents->load_start_time().is_null()) {
394 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() - 513 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() -
395 prerender_contents->load_start_time(), 514 prerender_contents->load_start_time(),
396 GetMaxAge()); 515 GetMaxAge());
397 } 516 }
398 517
399 histograms_->RecordPerSessionCount(++prerenders_per_session_count_); 518 histograms_->RecordPerSessionCount(++prerenders_per_session_count_);
400 histograms_->RecordUsedPrerender(prerender_contents->origin()); 519 histograms_->RecordUsedPrerender(prerender_contents->origin());
401 prerender_contents->set_final_status(FINAL_STATUS_USED); 520 prerender_contents->set_final_status(FINAL_STATUS_USED);
402 521
522 RenderViewHost* new_render_view_host =
523 prerender_contents->prerender_contents()->web_contents()->
524 GetRenderViewHost();
525
403 new_render_view_host->Send( 526 new_render_view_host->Send(
404 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), 527 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(),
405 false)); 528 false));
406 529
407 TabContents* new_tab_contents = 530 TabContents* new_tab_contents =
408 prerender_contents->ReleasePrerenderContents(); 531 prerender_contents->ReleasePrerenderContents();
409 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); 532 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents);
410 DCHECK(new_tab_contents); 533 DCHECK(new_tab_contents);
411 DCHECK(old_tab_contents); 534 DCHECK(old_tab_contents);
412 535
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
448 FirePageBeforeUnload(false); 571 FirePageBeforeUnload(false);
449 } else { 572 } else {
450 // No unload handler to run, so delete asap. 573 // No unload handler to run, so delete asap.
451 ScheduleDeleteOldTabContents(old_tab_contents, NULL); 574 ScheduleDeleteOldTabContents(old_tab_contents, NULL);
452 } 575 }
453 576
454 // TODO(cbentzel): Should prerender_contents move to the pending delete 577 // TODO(cbentzel): Should prerender_contents move to the pending delete
455 // list, instead of deleting directly here? 578 // list, instead of deleting directly here?
456 AddToHistory(prerender_contents.get()); 579 AddToHistory(prerender_contents.get());
457 RecordNavigation(url); 580 RecordNavigation(url);
581 DVLOG(3) << "... success!";
458 return true; 582 return true;
459 } 583 }
460 584
461 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry, 585 void PrerenderManager::MoveEntryToPendingDelete(WeakPrerenderHandle prerender,
462 FinalStatus final_status) { 586 FinalStatus final_status) {
587 if (!prerender)
588 return;
463 DCHECK(CalledOnValidThread()); 589 DCHECK(CalledOnValidThread());
464 DCHECK(entry); 590
465 // Confirm this entry has not already been moved to the pending delete list. 591 DVLOG(2) << "MoveEntryToPendingDelete";
592 DVLOG(2) << "... final_status = \"" << NameFromFinalStatus(final_status) << "\ "";
593
594 PrerenderContentsData* contents_data =
595 PrerenderContentsData::FromPrerenderHandle(prerender.get());
596 DVLOG(3) << "... contents()->prerender_url() = "
597 << contents_data->contents()->prerender_url().spec();
598 DCHECK(contents_data->contents());
599 // Confirm this prerender has not already been moved to the pending delete
600 // list.
466 DCHECK_EQ(0, std::count(pending_delete_list_.begin(), 601 DCHECK_EQ(0, std::count(pending_delete_list_.begin(),
467 pending_delete_list_.end(), entry)); 602 pending_delete_list_.end(),
603 contents_data->contents()));
468 604
469 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 605 bool swapped_in_dummy_replacement = false;
470 it != prerender_list_.end();
471 ++it) {
472 if (it->contents_ == entry) {
473 bool swapped_in_dummy_replacement = false;
474 606
475 // If this PrerenderContents is being deleted due to a cancellation, 607 // If this PrerenderContents is being deleted due to a cancellation,
476 // we need to create a dummy replacement for PPLT accounting purposes 608 // we need to create a dummy replacement for PPLT accounting purposes
477 // for the Match Complete group. 609 // for the Match Complete group.
478 // This is the case if the cancellation is for any reason that would not 610 // This is the case if the cancellation is for any reason that would not
479 // occur in the control group case. 611 // occur in the control group case.
480 if (entry->match_complete_status() == 612 if (contents_data->contents()->match_complete_status() ==
dominich 2012/06/18 15:32:44 If you cache contents_data->contents() in a const
gavinp 2012/06/18 16:40:48 Yes on the minimized changes, but probably not so
481 PrerenderContents::MATCH_COMPLETE_DEFAULT && 613 PrerenderContents::MATCH_COMPLETE_DEFAULT &&
482 NeedMatchCompleteDummyForFinalStatus(final_status) && 614 NeedMatchCompleteDummyForFinalStatus(final_status) &&
483 ActuallyPrerendering()) { 615 ActuallyPrerendering()) {
484 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. 616 DVLOG(8) << "swapping!";
485 // However, what if new conditions are added and 617 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering.
486 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure 618 // However, what if new conditions are added and
487 // what's the best thing to do here. For now, I will just check whether 619 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure
488 // we are actually prerendering. 620 // what's the best thing to do here. For now, I will just check whether
489 entry->set_match_complete_status( 621 // we are actually prerendering.
490 PrerenderContents::MATCH_COMPLETE_REPLACED); 622 contents_data->contents()->set_match_complete_status(
491 if (PrerenderContents* dummy_replacement_prerender_contents = 623 PrerenderContents::MATCH_COMPLETE_REPLACED);
492 CreatePrerenderContents(entry->prerender_url(), 624 if (PrerenderContents* dummy_replacement_prerender_contents =
493 entry->referrer(), 625 CreatePrerenderContents(
494 entry->origin(), 626 contents_data->contents()->prerender_url(),
495 entry->experiment_id())) { 627 contents_data->contents()->referrer(),
496 dummy_replacement_prerender_contents->set_match_complete_status( 628 contents_data->contents()->origin(),
497 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING); 629 contents_data->contents()->experiment_id())) {
498 if (!dummy_replacement_prerender_contents->Init()) 630 DVLOG(8) << "really swapping";
499 break; 631 dummy_replacement_prerender_contents->set_match_complete_status(
500 dummy_replacement_prerender_contents-> 632 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING);
501 AddAliasURLsFromOtherPrerenderContents(entry); 633 if (dummy_replacement_prerender_contents->Init(prerender)) {
502 dummy_replacement_prerender_contents->set_match_complete_status( 634 DVLOG(8) << "i totally am going to swap";
503 PrerenderContents::MATCH_COMPLETE_REPLACEMENT); 635 dummy_replacement_prerender_contents->
504 it->contents_ = dummy_replacement_prerender_contents; 636 AddAliasURLsFromOtherPrerenderContents(contents_data->contents());
505 swapped_in_dummy_replacement = true; 637 dummy_replacement_prerender_contents->set_match_complete_status(
506 } 638 PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
639 contents_data->set_contents(dummy_replacement_prerender_contents);
640 swapped_in_dummy_replacement = true;
507 } 641 }
508 if (!swapped_in_dummy_replacement)
509 prerender_list_.erase(it);
510 break;
511 } 642 }
512 } 643 }
513 AddToHistory(entry); 644 if (!swapped_in_dummy_replacement) {
514 pending_delete_list_.push_back(entry); 645 DCHECK_EQ(1, std::count(prerender_list_.begin(), prerender_list_.end(),
646 contents_data));
647 prerender_list_.erase(
648 std::find(prerender_list_.begin(), prerender_list_.end(),
649 contents_data));
650 }
651
652 AddToHistory(contents_data->contents());
653 pending_delete_list_.push_back(contents_data->contents());
654 contents_data->Destroy();
515 655
516 // Destroy the old WebContents relatively promptly to reduce resource usage, 656 // 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. 657 // and in the case of HTML5 media, reduce the change of playing any sound.
518 PostCleanupTask(); 658 PostCleanupTask();
519 } 659 }
520 660
521 // static 661 // static
522 void PrerenderManager::RecordPerceivedPageLoadTime( 662 void PrerenderManager::RecordPerceivedPageLoadTime(
523 base::TimeDelta perceived_page_load_time, 663 base::TimeDelta perceived_page_load_time,
524 double fraction_plt_elapsed_at_swap_in, 664 double fraction_plt_elapsed_at_swap_in,
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
616 bool PrerenderManager::IsNoUseGroup() { 756 bool PrerenderManager::IsNoUseGroup() {
617 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; 757 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP;
618 } 758 }
619 759
620 bool PrerenderManager::IsWebContentsPrerendering( 760 bool PrerenderManager::IsWebContentsPrerendering(
621 WebContents* web_contents) const { 761 WebContents* web_contents) const {
622 DCHECK(CalledOnValidThread()); 762 DCHECK(CalledOnValidThread());
623 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 763 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
624 it != prerender_list_.end(); 764 it != prerender_list_.end();
625 ++it) { 765 ++it) {
626 TabContents* prerender_tab_contents = it->contents_->prerender_contents(); 766 const PrerenderContentsData* contents_data = *it;
627 if (prerender_tab_contents && 767 if (!contents_data) continue;
628 prerender_tab_contents->web_contents() == web_contents) { 768 TabContents* prerender_tab_contents =
769 contents_data->contents()->prerender_contents();
770 if (!prerender_tab_contents) continue;
771 if (prerender_tab_contents->web_contents() == web_contents)
629 return true; 772 return true;
630 }
631 } 773 }
632 774
633 // Also look through the pending-deletion list. 775 // Also look through the pending-deletion list.
634 for (std::list<PrerenderContents*>::const_iterator it = 776 for (std::list<PrerenderContents*>::const_iterator it =
635 pending_delete_list_.begin(); 777 pending_delete_list_.begin();
636 it != pending_delete_list_.end(); 778 it != pending_delete_list_.end();
637 ++it) { 779 ++it) {
638 TabContents* prerender_tab_contents = (*it)->prerender_contents(); 780 TabContents* prerender_tab_contents = (*it)->prerender_contents();
639 if (prerender_tab_contents && 781 if (prerender_tab_contents &&
640 prerender_tab_contents->web_contents() == web_contents) 782 prerender_tab_contents->web_contents() == web_contents)
641 return true; 783 return true;
642 } 784 }
643 785
644 return false; 786 return false;
645 } 787 }
646 788
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) { 789 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) {
654 DCHECK(CalledOnValidThread()); 790 DCHECK(CalledOnValidThread());
655 prerendered_tab_contents_set_.insert(web_contents); 791 prerendered_tab_contents_set_.insert(web_contents);
656 } 792 }
657 793
658 void PrerenderManager::MarkWebContentsAsWouldBePrerendered( 794 void PrerenderManager::MarkWebContentsAsWouldBePrerendered(
659 WebContents* web_contents) { 795 WebContents* web_contents) {
660 DCHECK(CalledOnValidThread()); 796 DCHECK(CalledOnValidThread());
661 would_be_prerendered_map_[web_contents] = true; 797 would_be_prerendered_map_[web_contents] = true;
662 } 798 }
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 histograms_->RecordFinalStatus(origin, 894 histograms_->RecordFinalStatus(origin,
759 experiment_id, 895 experiment_id,
760 mc_status, 896 mc_status,
761 final_status); 897 final_status);
762 } 898 }
763 899
764 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { 900 void PrerenderManager::AddCondition(const PrerenderCondition* condition) {
765 prerender_conditions_.push_back(condition); 901 prerender_conditions_.push_back(condition);
766 } 902 }
767 903
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) { 904 void PrerenderManager::RecordNavigation(const GURL& url) {
785 DCHECK(CalledOnValidThread()); 905 DCHECK(CalledOnValidThread());
786 906
787 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); 907 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks()));
788 CleanUpOldNavigations(); 908 CleanUpOldNavigations();
789 } 909 }
790 910
791 // protected 911 // protected
792 void PrerenderManager::SetPrerenderContentsFactory( 912 void PrerenderManager::SetPrerenderContentsFactory(
793 PrerenderContents::Factory* prerender_contents_factory) { 913 PrerenderContents::Factory* prerender_contents_factory) {
794 DCHECK(CalledOnValidThread()); 914 DCHECK(CalledOnValidThread());
795 prerender_contents_factory_.reset(prerender_contents_factory); 915 prerender_contents_factory_.reset(prerender_contents_factory);
796 } 916 }
797 917
798 void PrerenderManager::DoShutdown() { 918 void PrerenderManager::DoShutdown() {
799 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); 919 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN);
800 STLDeleteElements(&prerender_conditions_); 920 STLDeleteElements(&prerender_conditions_);
801 on_close_tab_contents_deleters_.reset(); 921 on_close_tab_contents_deleters_.reset();
802 profile_ = NULL; 922 profile_ = NULL;
803 } 923 }
804 924
805 // private 925 const PrerenderContents* PrerenderManager::FindPrerender(
806 bool PrerenderManager::AddPrerender( 926 const GURL& url) const {
927 DVLOG(4) << "PrerenderManager::FindPrerender";
928 DVLOG(5) << "... prerender_list_.size() = " << prerender_list_.size();
929
930 for (PrerenderContentsDataList::const_iterator
931 it = prerender_list_.begin(), end = prerender_list_.end();
932 it != end; ++it) {
933 if (!*it || !(*it)->contents()) continue;
934 if ((*it)->contents()->Matches(url, NULL))
dominich 2012/06/18 15:32:44 nit: if (*it && (*it)->contents() && (*it)->conten
935 return (*it)->contents();
936 }
937 return NULL;
938 }
939
940 PrerenderContents* PrerenderManager::ClaimPrerender(
941 content::WebContents* web_contents,
942 const GURL& url,
943 content::SessionStorageNamespace* session_storage_namespace) {
944 for (PrerenderContentsDataList::iterator
945 it = prerender_list_.begin(), end = prerender_list_.end();
946 it != end; ++it) {
947 if (!*it || !(*it)->contents()) continue;
948 PrerenderContents* contents = (*it)->contents();
949 if (contents->Matches(url, session_storage_namespace) &&
950 !IsNoSwapInExperiment(contents->experiment_id()) &&
951 contents->prerender_contents()->web_contents() != web_contents) {
952 (*it)->Destroy();
953 prerender_list_.erase(it);
954 return contents;
955 }
956 }
957 return NULL;
958 }
959
960 PrerenderHandle PrerenderManager::AddPrerender(
807 Origin origin, 961 Origin origin,
808 int process_id, 962 int process_id,
809 const GURL& url_arg, 963 const GURL& url_arg,
810 const content::Referrer& referrer, 964 const content::Referrer& referrer,
811 const gfx::Size& size, 965 const gfx::Size& size,
812 SessionStorageNamespace* session_storage_namespace) { 966 SessionStorageNamespace* session_storage_namespace) {
967 DVLOG(4) << "PrerenderManager::AddPrerender";
813 DCHECK(CalledOnValidThread()); 968 DCHECK(CalledOnValidThread());
814 969
815 if (!IsEnabled()) 970 if (!IsEnabled())
816 return false; 971 return PrerenderHandle();
817 972
818 if (origin == ORIGIN_LINK_REL_PRERENDER && 973 if (origin == ORIGIN_LINK_REL_PRERENDER &&
819 IsGoogleSearchResultURL(referrer.url)) { 974 IsGoogleSearchResultURL(referrer.url)) {
820 origin = ORIGIN_GWS_PRERENDER; 975 origin = ORIGIN_GWS_PRERENDER;
821 } 976 }
822 977
823 DeleteOldEntries(); 978 DeleteOldEntries();
824 DeletePendingDeleteEntries(); 979 DeletePendingDeleteEntries();
825 980
826 GURL url = url_arg; 981 GURL url = url_arg;
827 GURL alias_url; 982 GURL alias_url;
828 uint8 experiment = GetQueryStringBasedExperiment(url_arg); 983 uint8 experiment = GetQueryStringBasedExperiment(url_arg);
829 bool control_group_behavior = 984 bool control_group_behavior =
830 IsControlGroup() || IsControlGroupExperiment(experiment); 985 IsControlGroup() || IsControlGroupExperiment(experiment);
831 if (control_group_behavior && 986 if (control_group_behavior &&
832 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { 987 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) {
833 url = alias_url; 988 url = alias_url;
834 } 989 }
835 990
836 // From here on, we will record a FinalStatus so we need to register with the 991 // From here on, we will record a FinalStatus so we need to register with the
837 // histogram tracking. 992 // histogram tracking.
838 histograms_->RecordPrerender(origin, url_arg); 993 histograms_->RecordPrerender(origin, url_arg);
839 994
840 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) { 995 PrerenderContentsDataList::const_iterator duplicate =
841 ++prerender_contents_data->active_count_; 996 std::find_if(prerender_list_.begin(), prerender_list_.end(),
997 PrerenderContentsData::MatchPredicate(
998 url, session_storage_namespace));
999 if (duplicate != prerender_list_.end()) {
842 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); 1000 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE);
843 return true; 1001 return PrerenderHandle(duplicate->get());
844 } 1002 }
845 1003
846 // Do not prerender if there are too many render processes, and we would 1004 // 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 1005 // 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 1006 // a shared process, so that we can always reliably lower the CPU
849 // priority for prerendering. 1007 // priority for prerendering.
850 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns 1008 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns
851 // true, so that case needs to be explicitly checked for. 1009 // true, so that case needs to be explicitly checked for.
852 // TODO(tburkard): Figure out how to cancel prerendering in the opposite 1010 // 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. 1011 // 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 1012 // 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. 1013 // still want the benefits of prerendering even when several tabs are open.
856 #if !defined(OS_ANDROID) 1014 #if !defined(OS_ANDROID)
857 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost( 1015 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost(
858 profile_, url) && 1016 profile_, url) &&
859 !content::RenderProcessHost::run_renderer_in_process()) { 1017 !content::RenderProcessHost::run_renderer_in_process()) {
860 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); 1018 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES);
861 return false; 1019 return PrerenderHandle();
862 } 1020 }
863 #endif 1021 #endif
864 1022
865 // Check if enough time has passed since the last prerender. 1023 // Check if enough time has passed since the last prerender.
866 if (!DoesRateLimitAllowPrerender()) { 1024 if (!DoesRateLimitAllowPrerender()) {
867 // Cancel the prerender. We could add it to the pending prerender list but 1025 // 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 1026 // 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. 1027 // by a navigation and is unlikely to be the same site.
870 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); 1028 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED);
871 return false; 1029 return PrerenderHandle();
872 } 1030 }
873 1031
874 PrerenderContents* prerender_contents = CreatePrerenderContents( 1032 PrerenderContents* prerender_contents = CreatePrerenderContents(
875 url, referrer, origin, experiment); 1033 url, referrer, origin, experiment);
876 if (!prerender_contents || !prerender_contents->Init()) 1034
877 return false; 1035 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
1036 PrerenderContentsData* data;
dominich 2012/06/18 15:32:44 PrerenderContentsData* data = new PrerenderCon
1037 PrerenderHandle handle(
1038 data = new PrerenderContentsData(this, prerender_contents));
1039
1040 DVLOG(5) << "handle initial ref_count_ = " << handle->ref_count_;
1041
1042 if (!prerender_contents || !prerender_contents->Init(handle->AsWeakPtr()))
1043 return PrerenderHandle();
878 1044
879 histograms_->RecordPrerenderStarted(origin); 1045 histograms_->RecordPrerenderStarted(origin);
880 1046
881 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? 1047 prerender_list_.push_back(data->AsWeakPtr());
882 PrerenderContentsData data(prerender_contents, GetCurrentTime());
883
884 prerender_list_.push_back(data);
885 1048
886 last_prerender_start_time_ = GetCurrentTimeTicks(); 1049 last_prerender_start_time_ = GetCurrentTimeTicks();
887 1050
888 data.contents_->StartPrerendering(process_id, size, session_storage_namespace, 1051 data->contents()->StartPrerendering(
889 control_group_behavior); 1052 process_id, size, session_storage_namespace, control_group_behavior);
1053
1054 // Compact the list of prerenders by removing all of the deleted
1055 // PrerenderContentsData objects, so that the size() will equal the
1056 // number of running prerenders.
1057 prerender_list_.erase(
1058 std::remove_if(prerender_list_.begin(), prerender_list_.end(),
1059 PrerenderContentsData::DeletedPredicate()),
1060 prerender_list_.end());
890 1061
891 while (prerender_list_.size() > config_.max_elements) { 1062 while (prerender_list_.size() > config_.max_elements) {
892 data = prerender_list_.front(); 1063 data = prerender_list_.front();
893 prerender_list_.pop_front(); 1064 prerender_list_.pop_front();
894 data.contents_->Destroy(FINAL_STATUS_EVICTED); 1065 data->contents()->Destroy(FINAL_STATUS_EVICTED);
895 } 1066 }
896 StartSchedulingPeriodicCleanups(); 1067 StartSchedulingPeriodicCleanups();
897 return true; 1068 DVLOG(5) << "on exit ref_count_ = " << handle->ref_count_;
898 } 1069 return handle;
899
900 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) {
901 return GetEntryButNotSpecifiedWC(url, NULL);
902 }
903
904 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC(
905 const GURL& url,
906 WebContents* wc) {
907 DCHECK(CalledOnValidThread());
908 DeleteOldEntries();
909 DeletePendingDeleteEntries();
910 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
911 it != prerender_list_.end();
912 ++it) {
913 PrerenderContents* prerender_contents = it->contents_;
914 if (prerender_contents->MatchesURL(url, NULL) &&
915 !IsNoSwapInExperiment(prerender_contents->experiment_id())) {
916 if (!prerender_contents->prerender_contents() ||
917 !wc ||
918 prerender_contents->prerender_contents()->web_contents() != wc) {
919 prerender_list_.erase(it);
920 return prerender_contents;
921 }
922 }
923 }
924 // Entry not found.
925 return NULL;
926 } 1070 }
927 1071
928 void PrerenderManager::StartSchedulingPeriodicCleanups() { 1072 void PrerenderManager::StartSchedulingPeriodicCleanups() {
929 DCHECK(CalledOnValidThread()); 1073 DCHECK(CalledOnValidThread());
930 if (repeating_timer_.IsRunning()) 1074 if (repeating_timer_.IsRunning())
931 return; 1075 return;
932 repeating_timer_.Start(FROM_HERE, 1076 repeating_timer_.Start(FROM_HERE,
933 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), 1077 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs),
934 this, 1078 this,
935 &PrerenderManager::PeriodicCleanup); 1079 &PrerenderManager::PeriodicCleanup);
936 } 1080 }
937 1081
938 void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { 1082 void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() {
939 if (!prerender_list_.empty()) 1083 if (!prerender_list_.empty())
940 return; 1084 return;
941 1085
942 DCHECK(CalledOnValidThread()); 1086 DCHECK(CalledOnValidThread());
943 repeating_timer_.Stop(); 1087 repeating_timer_.Stop();
944 } 1088 }
945 1089
946 void PrerenderManager::PeriodicCleanup() { 1090 void PrerenderManager::PeriodicCleanup() {
947 DCHECK(CalledOnValidThread()); 1091 DCHECK(CalledOnValidThread());
948 DeleteOldTabContents(); 1092 DeleteOldTabContents();
949 DeleteOldEntries(); 1093 DeleteOldEntries();
950 1094
951 // Grab a copy of the current PrerenderContents pointers, so that we 1095 // Grab a copy of the current PrerenderContents pointers, so that we
952 // will not interfere with potential deletions of the list. 1096 // will not interfere with potential deletions of the list.
953 std::vector<PrerenderContents*> prerender_contents; 1097 typedef std::vector<PrerenderContents*> PrerenderContentsVector;
1098 PrerenderContentsVector prerender_contents;
1099 prerender_contents.reserve(prerender_list_.size());
954 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 1100 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
955 it != prerender_list_.end(); 1101 it != prerender_list_.end();
956 ++it) { 1102 ++it) {
957 DCHECK(it->contents_); 1103 if (!*it || !(*it)->contents()) continue;
958 prerender_contents.push_back(it->contents_); 1104 prerender_contents.push_back((*it)->contents());
959 } 1105 }
960 for (std::vector<PrerenderContents*>::iterator it = 1106 for (PrerenderContentsVector::iterator it = prerender_contents.begin();
961 prerender_contents.begin(); 1107 it != prerender_contents.end(); ++it) {
962 it != prerender_contents.end();
963 ++it) {
964 (*it)->DestroyWhenUsingTooManyResources(); 1108 (*it)->DestroyWhenUsingTooManyResources();
965 } 1109 }
966 1110
967 DeletePendingDeleteEntries(); 1111 DeletePendingDeleteEntries();
968 } 1112 }
969 1113
970 void PrerenderManager::PostCleanupTask() { 1114 void PrerenderManager::PostCleanupTask() {
971 DCHECK(CalledOnValidThread()); 1115 DCHECK(CalledOnValidThread());
972 MessageLoop::current()->PostTask( 1116 MessageLoop::current()->PostTask(
973 FROM_HERE, 1117 FROM_HERE,
974 base::Bind(&PrerenderManager::PeriodicCleanup, 1118 base::Bind(&PrerenderManager::PeriodicCleanup,
975 weak_factory_.GetWeakPtr())); 1119 weak_factory_.GetWeakPtr()));
976 } 1120 }
977 1121
978 base::TimeDelta PrerenderManager::GetMaxAge() const { 1122 base::TimeDelta PrerenderManager::GetMaxAge() const {
979 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ? 1123 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ?
980 base::TimeDelta::FromSeconds(300) : config_.max_age); 1124 base::TimeDelta::FromSeconds(300) : config_.max_age);
981 } 1125 }
982 1126
983 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const {
984 DCHECK(CalledOnValidThread());
985 base::Time now = GetCurrentTime();
986 return (now - start < GetMaxAge());
987 }
988
989 void PrerenderManager::DeleteOldEntries() { 1127 void PrerenderManager::DeleteOldEntries() {
990 DCHECK(CalledOnValidThread()); 1128 DCHECK(CalledOnValidThread());
991 while (!prerender_list_.empty()) { 1129 PrerenderContentsData::ExpiredPredicate expired_predicate(GetCurrentTime());
dominich 2012/06/18 15:32:44 this code is longer and more complicated than the
gavinp 2012/06/18 16:40:48 Yes. I hate the predicates too.
992 PrerenderContentsData data = prerender_list_.front(); 1130
993 if (IsPrerenderElementFresh(data.start_time_)) 1131 PrerenderContentsDataList::iterator it =
994 return; 1132 std::find_if(prerender_list_.begin(), prerender_list_.end(),
995 data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); 1133 expired_predicate);
1134 while (it != prerender_list_.end()) {
1135 (*it)->contents()->Destroy(FINAL_STATUS_TIMED_OUT);
1136
1137 ++it;
1138 it = std::find_if(it, prerender_list_.end(), expired_predicate);
996 } 1139 }
1140
997 MaybeStopSchedulingPeriodicCleanups(); 1141 MaybeStopSchedulingPeriodicCleanups();
998 } 1142 }
999 1143
1144 // virtual (to allow testing)
1000 base::Time PrerenderManager::GetCurrentTime() const { 1145 base::Time PrerenderManager::GetCurrentTime() const {
1001 return base::Time::Now(); 1146 return base::Time::Now();
1002 } 1147 }
1003 1148
1149 // virtual (to allow testing)
1004 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { 1150 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const {
1005 return base::TimeTicks::Now(); 1151 return base::TimeTicks::Now();
1006 } 1152 }
1007 1153
1154 // virtual (to allow testing)
1008 PrerenderContents* PrerenderManager::CreatePrerenderContents( 1155 PrerenderContents* PrerenderManager::CreatePrerenderContents(
1009 const GURL& url, 1156 const GURL& url,
1010 const content::Referrer& referrer, 1157 const content::Referrer& referrer,
1011 Origin origin, 1158 Origin origin,
1012 uint8 experiment_id) { 1159 uint8 experiment_id) {
1013 DCHECK(CalledOnValidThread()); 1160 DCHECK(CalledOnValidThread());
1014 return prerender_contents_factory_->CreatePrerenderContents( 1161 return prerender_contents_factory_->CreatePrerenderContents(
1015 this, prerender_tracker_, profile_, url, 1162 this, prerender_tracker_, profile_, url,
1016 referrer, origin, experiment_id); 1163 referrer, origin, experiment_id);
1017 } 1164 }
1018 1165
1019 void PrerenderManager::DeletePendingDeleteEntries() { 1166 void PrerenderManager::DeletePendingDeleteEntries() {
1020 while (!pending_delete_list_.empty()) { 1167 while (!pending_delete_list_.empty()) {
1021 PrerenderContents* contents = pending_delete_list_.front(); 1168 PrerenderContents* contents = pending_delete_list_.front();
1022 pending_delete_list_.pop_front(); 1169 pending_delete_list_.pop_front();
1023 delete contents; 1170 delete contents;
1024 } 1171 }
1025 } 1172 }
1026 1173
1027 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData( 1174 const PrerenderManager::PrerenderContentsData*
1028 const GURL& url) { 1175 PrerenderManager::FindContentsData(PrerenderHandle handle) const {
1029 DCHECK(CalledOnValidThread()); 1176 DCHECK(CalledOnValidThread());
1030 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url); 1177 // Confirm this handle occurs at most once in our prerender list.
1178 DCHECK_GE(1, std::count_if(prerender_list_.begin(), prerender_list_.end(),
dominich 2012/06/18 15:32:44 pointless test - find_if would return prerender_li
1179 PrerenderContentsData::EqualsPredicate(handle)));
1180 PrerenderContentsDataList::const_iterator it =
1181 std::find_if(prerender_list_.begin(), prerender_list_.end(),
1182 PrerenderContentsData::EqualsPredicate(handle));
1031 if (it == prerender_list_.end()) 1183 if (it == prerender_list_.end())
1032 return NULL; 1184 return NULL;
1033 PrerenderContentsData& prerender_contents_data = *it; 1185 // Make sure this WeakPtr is still dereferencable. This only needs to be a
1034 return &prerender_contents_data; 1186 // DCHECK because the in-scope PrerenderHandle should hold a ref which keeps
1187 // this WeakPtr as being valid.
1188 DCHECK(*it);
1189
1190 return *it;
1035 } 1191 }
1036 1192
1037 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const { 1193 PrerenderManager::PrerenderContentsData*
1038 DCHECK(CalledOnValidThread()); 1194 PrerenderManager::FindContentsDataMutable(PrerenderHandle handle) {
1039 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 1195 return const_cast<PrerenderManager::PrerenderContentsData*>(
dominich 2012/06/18 15:32:44 Code smell: const_cast?
1040 it != prerender_list_.end(); 1196 FindContentsData(handle));
1041 ++it) { 1197 }
1042 if (it->contents_->MatchesURL(url, NULL)) 1198
1043 return it->contents_; 1199 PrerenderManager::PrerenderContentsData*
1200 PrerenderManager::FindContentsDataForChildAndRouteId(const int child_id,
1201 const int route_id) {
1202 for (PrerenderContentsDataList::iterator
1203 it = prerender_list_.begin(), end = prerender_list_.end();
1204 it != end; ++it) {
1205 if (!*it) continue;
dominich 2012/06/18 15:32:44 nit: int contents_child_id, contents_route_id; if
1206 int contents_child_id;
1207 if (!(*it)->contents()->GetChildId(&contents_child_id)) continue;
1208 int contents_route_id;
1209 if (!(*it)->contents()->GetRouteId(&contents_route_id)) continue;
1210 if (child_id == contents_child_id && route_id == contents_route_id) {
1211 return *it;
1212 }
1044 } 1213 }
1045 // Entry not found.
1046 return NULL; 1214 return NULL;
1047 } 1215 }
1048 1216
1049 PrerenderManager::PrerenderContentsDataList::iterator
1050 PrerenderManager::FindPrerenderContentsForChildRouteIdPair(
1051 const std::pair<int, int>& child_route_id_pair) {
1052 PrerenderContentsDataList::iterator it = prerender_list_.begin();
1053 for (; it != prerender_list_.end(); ++it) {
1054 PrerenderContents* prerender_contents = it->contents_;
1055
1056 int child_id;
1057 int route_id;
1058 bool has_child_id = prerender_contents->GetChildId(&child_id);
1059 bool has_route_id = has_child_id &&
1060 prerender_contents->GetRouteId(&route_id);
1061
1062 if (has_child_id && has_route_id &&
1063 child_id == child_route_id_pair.first &&
1064 route_id == child_route_id_pair.second) {
1065 break;
1066 }
1067 }
1068 return it;
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 }
1080
1081 bool PrerenderManager::DoesRateLimitAllowPrerender() const { 1217 bool PrerenderManager::DoesRateLimitAllowPrerender() const {
1082 DCHECK(CalledOnValidThread()); 1218 DCHECK(CalledOnValidThread());
1083 base::TimeDelta elapsed_time = 1219 base::TimeDelta elapsed_time =
1084 GetCurrentTimeTicks() - last_prerender_start_time_; 1220 GetCurrentTimeTicks() - last_prerender_start_time_;
1085 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); 1221 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time);
1086 if (!config_.rate_limit_enabled) 1222 if (!config_.rate_limit_enabled)
1087 return true; 1223 return true;
1088 return elapsed_time > 1224 return elapsed_time >
1089 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); 1225 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs);
1090 } 1226 }
(...skipping 30 matching lines...) Expand all
1121 ScopedVector<OnCloseTabContentsDeleter>::iterator i = std::find( 1257 ScopedVector<OnCloseTabContentsDeleter>::iterator i = std::find(
1122 on_close_tab_contents_deleters_.begin(), 1258 on_close_tab_contents_deleters_.begin(),
1123 on_close_tab_contents_deleters_.end(), 1259 on_close_tab_contents_deleters_.end(),
1124 deleter); 1260 deleter);
1125 DCHECK(i != on_close_tab_contents_deleters_.end()); 1261 DCHECK(i != on_close_tab_contents_deleters_.end());
1126 on_close_tab_contents_deleters_.erase(i); 1262 on_close_tab_contents_deleters_.erase(i);
1127 } 1263 }
1128 } 1264 }
1129 1265
1130 void PrerenderManager::AddToHistory(PrerenderContents* contents) { 1266 void PrerenderManager::AddToHistory(PrerenderContents* contents) {
1267 DVLOG(4) << "PrerenderManager::AddToHistory";
1268 DVLOG(5) << "... contents = " << contents;
1269 DVLOG(5) << "... fs = " << contents->final_status();
1131 PrerenderHistory::Entry entry(contents->prerender_url(), 1270 PrerenderHistory::Entry entry(contents->prerender_url(),
1132 contents->final_status(), 1271 contents->final_status(),
1133 contents->origin(), 1272 contents->origin(),
1134 base::Time::Now()); 1273 base::Time::Now());
1135 prerender_history_->AddEntry(entry); 1274 prerender_history_->AddEntry(entry);
1136 } 1275 }
1137 1276
1138 Value* PrerenderManager::GetActivePrerendersAsValue() const { 1277 Value* PrerenderManager::GetActivePrerendersAsValue() const {
1139 ListValue* list_value = new ListValue(); 1278 ListValue* list_value = new ListValue();
1140 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 1279 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
1141 it != prerender_list_.end(); 1280 it != prerender_list_.end();
1142 ++it) { 1281 ++it) {
1143 Value* prerender_value = it->contents_->GetAsValue(); 1282 if (!*it || (*it)->IsStarted()) continue;
1144 if (!prerender_value) 1283 Value* prerender_value = (*it)->contents()->GetAsValue();
1145 continue; 1284 if (!prerender_value) continue;
1146 list_value->Append(prerender_value); 1285 list_value->Append(prerender_value);
1147 } 1286 }
1148 return list_value; 1287 return list_value;
1149 } 1288 }
1150 1289
1151 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { 1290 void PrerenderManager::DestroyAllContents(FinalStatus final_status) {
1152 DeleteOldTabContents(); 1291 DeleteOldTabContents();
1153 while (!prerender_list_.empty()) { 1292 while (!prerender_list_.empty()) {
1154 PrerenderContentsData data = prerender_list_.front(); 1293 if (PrerenderContentsData* data = prerender_list_.front()) {
1294 if (data->contents()) {
1295 DVLOG(4) << "destroy .. contents = " << data->contents();
1296 DVLOG(4) << "fs = " << data->contents()->final_status();
1297 }
1298 if (data->IsStarted())
1299 data->contents()->Destroy(final_status);
dominich 2012/06/18 15:32:44 We shouldn't have a valid contents if we haven't s
1300 }
1155 prerender_list_.pop_front(); 1301 prerender_list_.pop_front();
1156 data.contents_->Destroy(final_status);
1157 } 1302 }
1158 DeletePendingDeleteEntries(); 1303 DeletePendingDeleteEntries();
1159 } 1304 }
1160 1305
1161 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed( 1306 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed(
1162 PrerenderContents* prerender_contents, 1307 PrerenderContents* prerender_contents,
1163 FinalStatus final_status) { 1308 FinalStatus final_status) {
1164 prerender_contents->set_match_complete_status( 1309 prerender_contents->set_match_complete_status(
1165 PrerenderContents::MATCH_COMPLETE_REPLACED); 1310 PrerenderContents::MATCH_COMPLETE_REPLACED);
1166 histograms_->RecordFinalStatus(prerender_contents->origin(), 1311 histograms_->RecordFinalStatus(prerender_contents->origin(),
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1205 if (!render_process_host || !render_process_host->GetBrowserContext()) 1350 if (!render_process_host || !render_process_host->GetBrowserContext())
1206 return NULL; 1351 return NULL;
1207 Profile* profile = Profile::FromBrowserContext( 1352 Profile* profile = Profile::FromBrowserContext(
1208 render_process_host->GetBrowserContext()); 1353 render_process_host->GetBrowserContext());
1209 if (!profile) 1354 if (!profile)
1210 return NULL; 1355 return NULL;
1211 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); 1356 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile);
1212 } 1357 }
1213 1358
1214 } // namespace prerender 1359 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698