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 <string> | 7 #include <string> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
146 DISALLOW_COPY_AND_ASSIGN(OnCloseTabContentsDeleter); | 146 DISALLOW_COPY_AND_ASSIGN(OnCloseTabContentsDeleter); |
147 }; | 147 }; |
148 | 148 |
149 // static | 149 // static |
150 int PrerenderManager::prerenders_per_session_count_ = 0; | 150 int PrerenderManager::prerenders_per_session_count_ = 0; |
151 | 151 |
152 // static | 152 // static |
153 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = | 153 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = |
154 PRERENDER_MODE_ENABLED; | 154 PRERENDER_MODE_ENABLED; |
155 | 155 |
156 // static | |
157 PrerenderManager::PrerenderManagerMode PrerenderManager::GetMode() { | |
158 return mode_; | |
159 } | |
160 | |
161 // static | |
162 void PrerenderManager::SetMode(PrerenderManagerMode mode) { | |
163 mode_ = mode; | |
164 } | |
165 | |
166 // static | |
167 bool PrerenderManager::IsPrerenderingPossible() { | |
168 return GetMode() == PRERENDER_MODE_ENABLED || | |
169 GetMode() == PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP || | |
170 GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP || | |
171 GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; | |
172 } | |
173 | |
174 // static | |
175 bool PrerenderManager::ActuallyPrerendering() { | |
176 return IsPrerenderingPossible() && !IsControlGroup(); | |
177 } | |
178 | |
179 // static | |
180 bool PrerenderManager::IsControlGroup() { | |
181 return GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP; | |
182 } | |
183 | |
184 // static | |
185 bool PrerenderManager::IsNoUseGroup() { | |
186 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; | |
187 } | |
188 | |
189 // static | |
190 bool PrerenderManager::IsValidHttpMethod(const std::string& method) { | |
191 // method has been canonicalized to upper case at this point so we can just | |
192 // compare them. | |
193 DCHECK_EQ(method, StringToUpperASCII(method)); | |
194 for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) { | |
195 if (method.compare(kValidHttpMethods[i]) == 0) | |
196 return true; | |
197 } | |
198 | |
199 return false; | |
200 } | |
201 | |
202 struct PrerenderManager::PrerenderContentsData { | 156 struct PrerenderManager::PrerenderContentsData { |
203 PrerenderContents* contents_; | 157 PrerenderContents* contents_; |
204 base::Time start_time_; | 158 base::Time start_time_; |
205 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) | 159 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) |
206 : contents_(contents), | 160 : contents_(contents), |
207 start_time_(start_time) { | 161 start_time_(start_time) { |
208 CHECK(contents); | 162 CHECK(contents); |
209 } | 163 } |
210 }; | 164 }; |
211 | 165 |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
265 return profile_->GetTopSites(); | 219 return profile_->GetTopSites(); |
266 return NULL; | 220 return NULL; |
267 } | 221 } |
268 | 222 |
269 CancelableRequestConsumer topsites_consumer_; | 223 CancelableRequestConsumer topsites_consumer_; |
270 Profile* profile_; | 224 Profile* profile_; |
271 content::NotificationRegistrar registrar_; | 225 content::NotificationRegistrar registrar_; |
272 std::set<GURL> urls_; | 226 std::set<GURL> urls_; |
273 }; | 227 }; |
274 | 228 |
275 bool PrerenderManager::IsTopSite(const GURL& url) { | |
276 if (!most_visited_.get()) | |
277 most_visited_.reset(new MostVisitedSites(profile_)); | |
278 return most_visited_->IsTopSite(url); | |
279 } | |
280 | |
281 bool PrerenderManager::IsPendingEntry(const GURL& url) const { | |
282 DCHECK(CalledOnValidThread()); | |
283 for (std::list<PrerenderContentsData>::const_iterator it = | |
284 prerender_list_.begin(); | |
285 it != prerender_list_.end(); | |
286 ++it) { | |
287 if (it->contents_->IsPendingEntry(url)) | |
288 return true; | |
289 } | |
290 return false; | |
291 } | |
292 | |
293 PrerenderManager::PrerenderManager(Profile* profile, | 229 PrerenderManager::PrerenderManager(Profile* profile, |
294 PrerenderTracker* prerender_tracker) | 230 PrerenderTracker* prerender_tracker) |
295 : enabled_(true), | 231 : enabled_(true), |
296 profile_(profile), | 232 profile_(profile), |
297 prerender_tracker_(prerender_tracker), | 233 prerender_tracker_(prerender_tracker), |
298 prerender_contents_factory_(PrerenderContents::CreateFactory()), | 234 prerender_contents_factory_(PrerenderContents::CreateFactory()), |
299 last_prerender_start_time_(GetCurrentTimeTicks() - | 235 last_prerender_start_time_(GetCurrentTimeTicks() - |
300 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)), | 236 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)), |
301 weak_factory_(this), | 237 weak_factory_(this), |
302 prerender_history_(new PrerenderHistory(kHistoryLength)), | 238 prerender_history_(new PrerenderHistory(kHistoryLength)), |
303 histograms_(new PrerenderHistograms()) { | 239 histograms_(new PrerenderHistograms()) { |
304 // There are some assumptions that the PrerenderManager is on the UI thread. | 240 // There are some assumptions that the PrerenderManager is on the UI thread. |
305 // Any other checks simply make sure that the PrerenderManager is accessed on | 241 // Any other checks simply make sure that the PrerenderManager is accessed on |
306 // the same thread that it was created on. | 242 // the same thread that it was created on. |
307 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
308 } | 244 } |
309 | 245 |
310 PrerenderManager::~PrerenderManager() { | 246 PrerenderManager::~PrerenderManager() { |
311 } | 247 } |
312 | 248 |
313 void PrerenderManager::Shutdown() { | 249 void PrerenderManager::Shutdown() { |
314 DoShutdown(); | 250 DoShutdown(); |
315 } | 251 } |
316 | 252 |
317 void PrerenderManager::SetPrerenderContentsFactory( | |
318 PrerenderContents::Factory* prerender_contents_factory) { | |
319 DCHECK(CalledOnValidThread()); | |
320 prerender_contents_factory_.reset(prerender_contents_factory); | |
321 } | |
322 | |
323 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( | 253 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( |
324 int process_id, | 254 int process_id, |
325 int route_id, | 255 int route_id, |
326 const GURL& url, | 256 const GURL& url, |
327 const content::Referrer& referrer) { | 257 const content::Referrer& referrer) { |
328 std::pair<int, int> child_route_id_pair = std::make_pair(process_id, | 258 std::pair<int, int> child_route_id_pair = std::make_pair(process_id, |
329 route_id); | 259 route_id); |
330 | 260 |
331 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, child_route_id_pair, | 261 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, child_route_id_pair, |
332 url, referrer, NULL); | 262 url, referrer, NULL); |
333 } | 263 } |
334 | 264 |
335 bool PrerenderManager::AddPrerenderFromOmnibox( | 265 bool PrerenderManager::AddPrerenderFromOmnibox( |
336 const GURL& url, | 266 const GURL& url, |
337 SessionStorageNamespace* session_storage_namespace) { | 267 SessionStorageNamespace* session_storage_namespace) { |
338 DCHECK(session_storage_namespace); | |
cbentzel
2012/01/25 12:14:01
Why was this removed?
| |
339 if (!IsOmniboxEnabled(profile_)) | 268 if (!IsOmniboxEnabled(profile_)) |
340 return false; | 269 return false; |
341 return AddPrerender(ORIGIN_OMNIBOX, std::make_pair(-1, -1), url, | 270 return AddPrerender(ORIGIN_OMNIBOX, std::make_pair(-1, -1), url, |
342 content::Referrer(), session_storage_namespace); | 271 content::Referrer(), session_storage_namespace); |
343 } | 272 } |
344 | 273 |
345 bool PrerenderManager::AddPrerender( | |
346 Origin origin, | |
347 const std::pair<int, int>& child_route_id_pair, | |
348 const GURL& url_arg, | |
349 const content::Referrer& referrer, | |
350 SessionStorageNamespace* session_storage_namespace) { | |
351 DCHECK(CalledOnValidThread()); | |
352 | |
353 if (origin == ORIGIN_LINK_REL_PRERENDER && | |
354 IsGoogleSearchResultURL(referrer.url)) { | |
355 origin = ORIGIN_GWS_PRERENDER; | |
356 } | |
357 | |
358 // If the referring page is prerendering, defer the prerender. | |
359 std::list<PrerenderContentsData>::iterator source_prerender = | |
360 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); | |
361 if (source_prerender != prerender_list_.end()) { | |
362 source_prerender->contents_->AddPendingPrerender( | |
363 origin, url_arg, referrer); | |
364 return true; | |
365 } | |
366 | |
367 DeleteOldEntries(); | |
368 DeletePendingDeleteEntries(); | |
369 | |
370 GURL url = url_arg; | |
371 GURL alias_url; | |
372 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) | |
373 url = alias_url; | |
374 | |
375 // From here on, we will record a FinalStatus so we need to register with the | |
376 // histogram tracking. | |
377 histograms_->RecordPrerender(origin, url_arg); | |
378 | |
379 uint8 experiment = GetQueryStringBasedExperiment(url_arg); | |
380 | |
381 if (FindEntry(url)) { | |
382 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); | |
383 return false; | |
384 } | |
385 | |
386 // Do not prerender if there are too many render processes, and we would | |
387 // have to use an existing one. We do not want prerendering to happen in | |
388 // a shared process, so that we can always reliably lower the CPU | |
389 // priority for prerendering. | |
390 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns | |
391 // true, so that case needs to be explicitly checked for. | |
392 // TODO(tburkard): Figure out how to cancel prerendering in the opposite | |
393 // case, when a new tab is added to a process used for prerendering. | |
394 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost() && | |
395 !content::RenderProcessHost::run_renderer_in_process()) { | |
396 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); | |
397 return false; | |
398 } | |
399 | |
400 // Check if enough time has passed since the last prerender. | |
401 if (!DoesRateLimitAllowPrerender()) { | |
402 // Cancel the prerender. We could add it to the pending prerender list but | |
403 // this doesn't make sense as the next prerender request will be triggered | |
404 // by a navigation and is unlikely to be the same site. | |
405 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); | |
406 return false; | |
407 } | |
408 | |
409 RenderViewHost* source_render_view_host = NULL; | |
410 if (child_route_id_pair.first != -1) { | |
411 source_render_view_host = | |
412 RenderViewHost::FromID(child_route_id_pair.first, | |
413 child_route_id_pair.second); | |
414 // Don't prerender page if parent RenderViewHost no longer exists, or it has | |
415 // no view. The latter should only happen when the RenderView has closed. | |
416 if (!source_render_view_host || !source_render_view_host->view()) { | |
417 RecordFinalStatus(origin, experiment, | |
418 FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED); | |
419 return false; | |
420 } | |
421 } | |
422 | |
423 if (!session_storage_namespace && source_render_view_host) { | |
424 session_storage_namespace = | |
425 source_render_view_host->session_storage_namespace(); | |
426 } | |
427 | |
428 PrerenderContents* prerender_contents = CreatePrerenderContents( | |
429 url, referrer, origin, experiment); | |
430 if (!prerender_contents || !prerender_contents->Init()) | |
431 return false; | |
432 | |
433 histograms_->RecordPrerenderStarted(origin); | |
434 | |
435 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? | |
436 PrerenderContentsData data(prerender_contents, GetCurrentTime()); | |
437 | |
438 prerender_list_.push_back(data); | |
439 | |
440 if (IsControlGroup()) { | |
441 data.contents_->set_final_status(FINAL_STATUS_CONTROL_GROUP); | |
442 } else { | |
443 last_prerender_start_time_ = GetCurrentTimeTicks(); | |
444 data.contents_->StartPrerendering(source_render_view_host, | |
445 session_storage_namespace); | |
446 } | |
447 while (prerender_list_.size() > config_.max_elements) { | |
448 data = prerender_list_.front(); | |
449 prerender_list_.pop_front(); | |
450 data.contents_->Destroy(FINAL_STATUS_EVICTED); | |
451 } | |
452 StartSchedulingPeriodicCleanups(); | |
453 return true; | |
454 } | |
455 | |
456 std::list<PrerenderManager::PrerenderContentsData>::iterator | |
457 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( | |
458 const std::pair<int, int>& child_route_id_pair) { | |
459 std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
460 for (; it != prerender_list_.end(); ++it) { | |
461 PrerenderContents* prerender_contents = it->contents_; | |
462 | |
463 int child_id; | |
464 int route_id; | |
465 bool has_child_id = prerender_contents->GetChildId(&child_id); | |
466 bool has_route_id = has_child_id && | |
467 prerender_contents->GetRouteId(&route_id); | |
468 | |
469 if (has_child_id && has_route_id && | |
470 child_id == child_route_id_pair.first && | |
471 route_id == child_route_id_pair.second) { | |
472 break; | |
473 } | |
474 } | |
475 return it; | |
476 } | |
477 | |
478 void PrerenderManager::DestroyPrerenderForRenderView( | 274 void PrerenderManager::DestroyPrerenderForRenderView( |
479 int process_id, int view_id, FinalStatus final_status) { | 275 int process_id, int view_id, FinalStatus final_status) { |
480 DCHECK(CalledOnValidThread()); | 276 DCHECK(CalledOnValidThread()); |
481 std::list<PrerenderContentsData>::iterator it = | 277 std::list<PrerenderContentsData>::iterator it = |
482 FindPrerenderContentsForChildRouteIdPair( | 278 FindPrerenderContentsForChildRouteIdPair( |
483 std::make_pair(process_id, view_id)); | 279 std::make_pair(process_id, view_id)); |
484 if (it != prerender_list_.end()) { | 280 if (it != prerender_list_.end()) { |
485 PrerenderContents* prerender_contents = it->contents_; | 281 PrerenderContents* prerender_contents = it->contents_; |
486 prerender_contents->Destroy(final_status); | 282 prerender_contents->Destroy(final_status); |
487 } | 283 } |
488 } | 284 } |
489 | 285 |
490 void PrerenderManager::CancelAllPrerenders() { | 286 void PrerenderManager::CancelAllPrerenders() { |
491 DCHECK(CalledOnValidThread()); | 287 DCHECK(CalledOnValidThread()); |
492 while (!prerender_list_.empty()) { | 288 while (!prerender_list_.empty()) { |
493 PrerenderContentsData data = prerender_list_.front(); | 289 PrerenderContentsData data = prerender_list_.front(); |
494 DCHECK(data.contents_); | 290 DCHECK(data.contents_); |
495 data.contents_->Destroy(FINAL_STATUS_CANCELLED); | 291 data.contents_->Destroy(FINAL_STATUS_CANCELLED); |
496 } | 292 } |
497 } | 293 } |
498 | 294 |
499 void PrerenderManager::DeleteOldEntries() { | 295 void PrerenderManager::CancelOmniboxPrerenders() { |
500 DCHECK(CalledOnValidThread()); | 296 DCHECK(CalledOnValidThread()); |
501 while (!prerender_list_.empty()) { | 297 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
Peter Kasting
2012/01/24 03:36:59
Nit: I wonder if a typedef for this might be usefu
| |
502 PrerenderContentsData data = prerender_list_.front(); | 298 it != prerender_list_.end(); ) { |
503 if (IsPrerenderElementFresh(data.start_time_)) | 299 std::list<PrerenderContentsData>::iterator cur = it++; |
504 return; | 300 if (cur->contents_->origin() == ORIGIN_OMNIBOX) |
505 data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); | 301 cur->contents_->Destroy(FINAL_STATUS_CANCELLED); |
506 } | 302 } |
507 MaybeStopSchedulingPeriodicCleanups(); | |
508 } | |
509 | |
510 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC( | |
511 const GURL& url, | |
512 WebContents* wc) { | |
513 DCHECK(CalledOnValidThread()); | |
514 DeleteOldEntries(); | |
515 DeletePendingDeleteEntries(); | |
516 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
517 it != prerender_list_.end(); | |
518 ++it) { | |
519 PrerenderContents* prerender_contents = it->contents_; | |
520 if (prerender_contents->MatchesURL(url, NULL)) { | |
521 if (!prerender_contents->prerender_contents() || | |
522 !wc || | |
523 prerender_contents->prerender_contents()->web_contents() != wc) { | |
524 prerender_list_.erase(it); | |
525 return prerender_contents; | |
526 } | |
527 } | |
528 } | |
529 // Entry not found. | |
530 return NULL; | |
531 } | |
532 | |
533 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { | |
534 return GetEntryButNotSpecifiedWC(url, NULL); | |
535 } | 303 } |
536 | 304 |
537 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, | 305 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, |
538 const GURL& url, | 306 const GURL& url, |
539 const GURL& opener_url) { | 307 const GURL& opener_url) { |
540 DCHECK(CalledOnValidThread()); | 308 DCHECK(CalledOnValidThread()); |
541 RecordNavigation(url); | 309 RecordNavigation(url); |
542 | 310 |
543 scoped_ptr<PrerenderContents> prerender_contents( | 311 scoped_ptr<PrerenderContents> prerender_contents( |
544 GetEntryButNotSpecifiedWC(url, web_contents)); | 312 GetEntryButNotSpecifiedWC(url, web_contents)); |
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
734 } | 502 } |
735 } | 503 } |
736 AddToHistory(entry); | 504 AddToHistory(entry); |
737 pending_delete_list_.push_back(entry); | 505 pending_delete_list_.push_back(entry); |
738 | 506 |
739 // Destroy the old TabContents relatively promptly to reduce resource usage, | 507 // Destroy the old TabContents relatively promptly to reduce resource usage, |
740 // and in the case of HTML5 media, reduce the change of playing any sound. | 508 // and in the case of HTML5 media, reduce the change of playing any sound. |
741 PostCleanupTask(); | 509 PostCleanupTask(); |
742 } | 510 } |
743 | 511 |
744 base::Time PrerenderManager::GetCurrentTime() const { | |
745 return base::Time::Now(); | |
746 } | |
747 | |
748 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { | |
749 return base::TimeTicks::Now(); | |
750 } | |
751 | |
752 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { | |
753 DCHECK(CalledOnValidThread()); | |
754 base::Time now = GetCurrentTime(); | |
755 return (now - start < config_.max_age); | |
756 } | |
757 | |
758 PrerenderContents* PrerenderManager::CreatePrerenderContents( | |
759 const GURL& url, | |
760 const content::Referrer& referrer, | |
761 Origin origin, | |
762 uint8 experiment_id) { | |
763 DCHECK(CalledOnValidThread()); | |
764 return prerender_contents_factory_->CreatePrerenderContents( | |
765 this, prerender_tracker_, profile_, url, | |
766 referrer, origin, experiment_id); | |
767 } | |
768 | |
769 bool PrerenderManager::IsPendingDelete(PrerenderContents* entry) const { | |
770 DCHECK(CalledOnValidThread()); | |
771 for (std::list<PrerenderContents*>::const_iterator it = | |
772 pending_delete_list_.begin(); | |
773 it != pending_delete_list_.end(); | |
774 ++it) { | |
775 if (*it == entry) | |
776 return true; | |
777 } | |
778 | |
779 return false; | |
780 } | |
781 | |
782 void PrerenderManager::DeletePendingDeleteEntries() { | |
783 while (!pending_delete_list_.empty()) { | |
784 PrerenderContents* contents = pending_delete_list_.front(); | |
785 pending_delete_list_.pop_front(); | |
786 delete contents; | |
787 } | |
788 } | |
789 | |
790 // static | 512 // static |
791 void PrerenderManager::RecordPerceivedPageLoadTime( | 513 void PrerenderManager::RecordPerceivedPageLoadTime( |
792 base::TimeDelta perceived_page_load_time, | 514 base::TimeDelta perceived_page_load_time, |
793 WebContents* web_contents, | 515 WebContents* web_contents, |
794 const GURL& url) { | 516 const GURL& url) { |
795 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 517 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
796 PrerenderManager* prerender_manager = | 518 PrerenderManager* prerender_manager = |
797 PrerenderManagerFactory::GetForProfile( | 519 PrerenderManagerFactory::GetForProfile( |
798 Profile::FromBrowserContext(web_contents->GetBrowserContext())); | 520 Profile::FromBrowserContext(web_contents->GetBrowserContext())); |
799 if (!prerender_manager) | 521 if (!prerender_manager) |
(...skipping 21 matching lines...) Expand all Loading... | |
821 return false; | 543 return false; |
822 } | 544 } |
823 return true; | 545 return true; |
824 } | 546 } |
825 | 547 |
826 void PrerenderManager::set_enabled(bool enabled) { | 548 void PrerenderManager::set_enabled(bool enabled) { |
827 DCHECK(CalledOnValidThread()); | 549 DCHECK(CalledOnValidThread()); |
828 enabled_ = enabled; | 550 enabled_ = enabled; |
829 } | 551 } |
830 | 552 |
831 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { | 553 // static |
832 prerender_conditions_.push_back(condition); | 554 PrerenderManager::PrerenderManagerMode PrerenderManager::GetMode() { |
555 return mode_; | |
833 } | 556 } |
834 | 557 |
835 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) { | 558 // static |
836 DCHECK(CalledOnValidThread()); | 559 void PrerenderManager::SetMode(PrerenderManagerMode mode) { |
837 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | 560 mode_ = mode; |
838 it != prerender_list_.end(); | |
839 ++it) { | |
840 if (it->contents_->MatchesURL(url, NULL)) | |
841 return it->contents_; | |
842 } | |
843 // Entry not found. | |
844 return NULL; | |
845 } | 561 } |
846 | 562 |
847 void PrerenderManager::DoShutdown() { | 563 // static |
848 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); | 564 bool PrerenderManager::IsPrerenderingPossible() { |
849 STLDeleteElements(&prerender_conditions_); | 565 return GetMode() == PRERENDER_MODE_ENABLED || |
850 profile_ = NULL; | 566 GetMode() == PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP || |
567 GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP || | |
568 GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; | |
851 } | 569 } |
852 | 570 |
853 bool PrerenderManager::DoesRateLimitAllowPrerender() const { | 571 // static |
854 DCHECK(CalledOnValidThread()); | 572 bool PrerenderManager::ActuallyPrerendering() { |
855 base::TimeDelta elapsed_time = | 573 return IsPrerenderingPossible() && !IsControlGroup(); |
856 GetCurrentTimeTicks() - last_prerender_start_time_; | |
857 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); | |
858 if (!config_.rate_limit_enabled) | |
859 return true; | |
860 return elapsed_time > | |
861 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); | |
862 } | 574 } |
863 | 575 |
864 void PrerenderManager::StartSchedulingPeriodicCleanups() { | 576 // static |
865 DCHECK(CalledOnValidThread()); | 577 bool PrerenderManager::IsControlGroup() { |
866 if (repeating_timer_.IsRunning()) | 578 return GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP; |
867 return; | |
868 repeating_timer_.Start(FROM_HERE, | |
869 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), | |
870 this, | |
871 &PrerenderManager::PeriodicCleanup); | |
872 } | 579 } |
873 | 580 |
874 void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { | 581 // static |
875 if (!prerender_list_.empty()) | 582 bool PrerenderManager::IsNoUseGroup() { |
876 return; | 583 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; |
877 | |
878 DCHECK(CalledOnValidThread()); | |
879 repeating_timer_.Stop(); | |
880 } | |
881 | |
882 void PrerenderManager::DeleteOldTabContents() { | |
883 while (!old_tab_contents_list_.empty()) { | |
884 TabContentsWrapper* tab_contents = old_tab_contents_list_.front(); | |
885 old_tab_contents_list_.pop_front(); | |
886 // TODO(dominich): should we use Instant Unload Handler here? | |
887 delete tab_contents; | |
888 } | |
889 } | |
890 | |
891 bool PrerenderManager::IsOldRenderViewHost( | |
892 const RenderViewHost* render_view_host) const { | |
893 for (std::list<TabContentsWrapper*>::const_iterator it = | |
894 old_tab_contents_list_.begin(); | |
895 it != old_tab_contents_list_.end(); | |
896 ++it) { | |
897 if ((*it)->web_contents()->GetRenderViewHost() == render_view_host) | |
898 return true; | |
899 } | |
900 return false; | |
901 } | |
902 | |
903 void PrerenderManager::PeriodicCleanup() { | |
904 DCHECK(CalledOnValidThread()); | |
905 DeleteOldTabContents(); | |
906 DeleteOldEntries(); | |
907 | |
908 // Grab a copy of the current PrerenderContents pointers, so that we | |
909 // will not interfere with potential deletions of the list. | |
910 std::vector<PrerenderContents*> prerender_contents; | |
911 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
912 it != prerender_list_.end(); | |
913 ++it) { | |
914 DCHECK(it->contents_); | |
915 prerender_contents.push_back(it->contents_); | |
916 } | |
917 for (std::vector<PrerenderContents*>::iterator it = | |
918 prerender_contents.begin(); | |
919 it != prerender_contents.end(); | |
920 ++it) { | |
921 (*it)->DestroyWhenUsingTooManyResources(); | |
922 } | |
923 | |
924 DeletePendingDeleteEntries(); | |
925 } | |
926 | |
927 void PrerenderManager::PostCleanupTask() { | |
928 DCHECK(CalledOnValidThread()); | |
929 MessageLoop::current()->PostTask( | |
930 FROM_HERE, | |
931 base::Bind(&PrerenderManager::PeriodicCleanup, | |
932 weak_factory_.GetWeakPtr())); | |
933 } | 584 } |
934 | 585 |
935 bool PrerenderManager::IsWebContentsPrerendering( | 586 bool PrerenderManager::IsWebContentsPrerendering( |
936 WebContents* web_contents) const { | 587 WebContents* web_contents) const { |
937 DCHECK(CalledOnValidThread()); | 588 DCHECK(CalledOnValidThread()); |
938 for (std::list<PrerenderContentsData>::const_iterator it = | 589 for (std::list<PrerenderContentsData>::const_iterator it = |
939 prerender_list_.begin(); | 590 prerender_list_.begin(); |
940 it != prerender_list_.end(); | 591 it != prerender_list_.end(); |
941 ++it) { | 592 ++it) { |
942 TabContentsWrapper* prerender_tab_contents_wrapper = | 593 TabContentsWrapper* prerender_tab_contents_wrapper = |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
985 DCHECK(CalledOnValidThread()); | 636 DCHECK(CalledOnValidThread()); |
986 return prerendered_tab_contents_set_.count(web_contents) > 0; | 637 return prerendered_tab_contents_set_.count(web_contents) > 0; |
987 } | 638 } |
988 | 639 |
989 bool PrerenderManager::WouldWebContentsBePrerendered( | 640 bool PrerenderManager::WouldWebContentsBePrerendered( |
990 WebContents* web_contents) const { | 641 WebContents* web_contents) const { |
991 DCHECK(CalledOnValidThread()); | 642 DCHECK(CalledOnValidThread()); |
992 return would_be_prerendered_tab_contents_set_.count(web_contents) > 0; | 643 return would_be_prerendered_tab_contents_set_.count(web_contents) > 0; |
993 } | 644 } |
994 | 645 |
646 bool PrerenderManager::IsOldRenderViewHost( | |
647 const RenderViewHost* render_view_host) const { | |
648 for (std::list<TabContentsWrapper*>::const_iterator it = | |
649 old_tab_contents_list_.begin(); | |
650 it != old_tab_contents_list_.end(); | |
651 ++it) { | |
652 if ((*it)->web_contents()->GetRenderViewHost() == render_view_host) | |
653 return true; | |
654 } | |
655 return false; | |
656 } | |
657 | |
995 bool PrerenderManager::HasRecentlyBeenNavigatedTo(const GURL& url) { | 658 bool PrerenderManager::HasRecentlyBeenNavigatedTo(const GURL& url) { |
996 DCHECK(CalledOnValidThread()); | 659 DCHECK(CalledOnValidThread()); |
997 | 660 |
998 CleanUpOldNavigations(); | 661 CleanUpOldNavigations(); |
999 for (std::list<NavigationRecord>::const_iterator it = navigations_.begin(); | 662 for (std::list<NavigationRecord>::const_iterator it = navigations_.begin(); |
1000 it != navigations_.end(); | 663 it != navigations_.end(); |
1001 ++it) { | 664 ++it) { |
1002 if (it->url_ == url) | 665 if (it->url_ == url) |
1003 return true; | 666 return true; |
1004 } | 667 } |
1005 | 668 |
1006 return false; | 669 return false; |
1007 } | 670 } |
1008 | 671 |
1009 void PrerenderManager::CleanUpOldNavigations() { | 672 // static |
1010 DCHECK(CalledOnValidThread()); | 673 bool PrerenderManager::IsValidHttpMethod(const std::string& method) { |
674 // method has been canonicalized to upper case at this point so we can just | |
675 // compare them. | |
676 DCHECK_EQ(method, StringToUpperASCII(method)); | |
677 for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) { | |
678 if (method.compare(kValidHttpMethods[i]) == 0) | |
679 return true; | |
680 } | |
1011 | 681 |
1012 // Cutoff. Navigations before this cutoff can be discarded. | 682 return false; |
1013 base::TimeTicks cutoff = GetCurrentTimeTicks() - | |
1014 base::TimeDelta::FromMilliseconds(kNavigationRecordWindowMs); | |
1015 while (!navigations_.empty()) { | |
1016 if (navigations_.front().time_ > cutoff) | |
1017 break; | |
1018 navigations_.pop_front(); | |
1019 } | |
1020 } | |
1021 | |
1022 void PrerenderManager::ScheduleDeleteOldTabContents( | |
1023 TabContentsWrapper* tab, | |
1024 OnCloseTabContentsDeleter* deleter) { | |
1025 old_tab_contents_list_.push_back(tab); | |
1026 PostCleanupTask(); | |
1027 | |
1028 if (deleter) { | |
1029 ScopedVector<OnCloseTabContentsDeleter>::iterator i = std::find( | |
1030 on_close_tab_contents_deleters_.begin(), | |
1031 on_close_tab_contents_deleters_.end(), | |
1032 deleter); | |
1033 DCHECK(i != on_close_tab_contents_deleters_.end()); | |
1034 on_close_tab_contents_deleters_.erase(i); | |
1035 } | |
1036 } | 683 } |
1037 | 684 |
1038 DictionaryValue* PrerenderManager::GetAsValue() const { | 685 DictionaryValue* PrerenderManager::GetAsValue() const { |
1039 DCHECK(CalledOnValidThread()); | 686 DCHECK(CalledOnValidThread()); |
1040 DictionaryValue* dict_value = new DictionaryValue(); | 687 DictionaryValue* dict_value = new DictionaryValue(); |
1041 dict_value->Set("history", prerender_history_->GetEntriesAsValue()); | 688 dict_value->Set("history", prerender_history_->GetEntriesAsValue()); |
1042 dict_value->Set("active", GetActivePrerendersAsValue()); | 689 dict_value->Set("active", GetActivePrerendersAsValue()); |
1043 dict_value->SetBoolean("enabled", enabled_); | 690 dict_value->SetBoolean("enabled", enabled_); |
1044 dict_value->SetBoolean("omnibox_enabled", IsOmniboxEnabled(profile_)); | 691 dict_value->SetBoolean("omnibox_enabled", IsOmniboxEnabled(profile_)); |
1045 // If prerender is disabled via a flag this method is not even called. | 692 // If prerender is disabled via a flag this method is not even called. |
1046 if (IsControlGroup()) | 693 if (IsControlGroup()) |
1047 dict_value->SetString("disabled_reason", "(Disabled for testing)"); | 694 dict_value->SetString("disabled_reason", "(Disabled for testing)"); |
1048 if (IsNoUseGroup()) | 695 if (IsNoUseGroup()) |
1049 dict_value->SetString("disabled_reason", "(Not using prerendered pages)"); | 696 dict_value->SetString("disabled_reason", "(Not using prerendered pages)"); |
1050 return dict_value; | 697 return dict_value; |
1051 } | 698 } |
1052 | 699 |
1053 void PrerenderManager::ClearData(int clear_flags) { | 700 void PrerenderManager::ClearData(int clear_flags) { |
1054 DCHECK_GE(clear_flags, 0); | 701 DCHECK_GE(clear_flags, 0); |
1055 DCHECK_LT(clear_flags, CLEAR_MAX); | 702 DCHECK_LT(clear_flags, CLEAR_MAX); |
1056 if (clear_flags & CLEAR_PRERENDER_CONTENTS) | 703 if (clear_flags & CLEAR_PRERENDER_CONTENTS) |
1057 DestroyAllContents(FINAL_STATUS_CACHE_OR_HISTORY_CLEARED); | 704 DestroyAllContents(FINAL_STATUS_CACHE_OR_HISTORY_CLEARED); |
1058 // This has to be second, since destroying prerenders can add to the history. | 705 // This has to be second, since destroying prerenders can add to the history. |
1059 if (clear_flags & CLEAR_PRERENDER_HISTORY) | 706 if (clear_flags & CLEAR_PRERENDER_HISTORY) |
1060 prerender_history_->Clear(); | 707 prerender_history_->Clear(); |
1061 } | 708 } |
1062 | 709 |
710 void PrerenderManager::RecordFinalStatus(Origin origin, | |
711 uint8 experiment_id, | |
712 FinalStatus final_status) const { | |
713 histograms_->RecordFinalStatus(origin, experiment_id, final_status); | |
714 } | |
715 | |
716 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { | |
717 prerender_conditions_.push_back(condition); | |
718 } | |
719 | |
720 bool PrerenderManager::IsTopSite(const GURL& url) { | |
721 if (!most_visited_.get()) | |
722 most_visited_.reset(new MostVisitedSites(profile_)); | |
723 return most_visited_->IsTopSite(url); | |
724 } | |
725 | |
726 bool PrerenderManager::IsPendingEntry(const GURL& url) const { | |
727 DCHECK(CalledOnValidThread()); | |
728 for (std::list<PrerenderContentsData>::const_iterator it = | |
729 prerender_list_.begin(); | |
730 it != prerender_list_.end(); | |
731 ++it) { | |
732 if (it->contents_->IsPendingEntry(url)) | |
733 return true; | |
734 } | |
735 return false; | |
736 } | |
737 | |
738 bool PrerenderManager::IsPrerendering(const GURL& url) { | |
739 DCHECK(CalledOnValidThread()); | |
740 return (FindEntry(url) != NULL); | |
741 } | |
742 | |
743 // protected | |
744 void PrerenderManager::SetPrerenderContentsFactory( | |
745 PrerenderContents::Factory* prerender_contents_factory) { | |
746 DCHECK(CalledOnValidThread()); | |
747 prerender_contents_factory_.reset(prerender_contents_factory); | |
748 } | |
749 | |
750 void PrerenderManager::DoShutdown() { | |
751 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); | |
752 STLDeleteElements(&prerender_conditions_); | |
753 profile_ = NULL; | |
754 } | |
755 | |
756 // private | |
cbentzel
2012/01/25 12:14:01
Nit: I haven't really seen the // private comment
| |
757 bool PrerenderManager::AddPrerender( | |
758 Origin origin, | |
759 const std::pair<int, int>& child_route_id_pair, | |
760 const GURL& url_arg, | |
761 const content::Referrer& referrer, | |
762 SessionStorageNamespace* session_storage_namespace) { | |
763 DCHECK(CalledOnValidThread()); | |
764 | |
765 if (origin == ORIGIN_LINK_REL_PRERENDER && | |
766 IsGoogleSearchResultURL(referrer.url)) { | |
767 origin = ORIGIN_GWS_PRERENDER; | |
768 } | |
769 | |
770 // If the referring page is prerendering, defer the prerender. | |
771 std::list<PrerenderContentsData>::iterator source_prerender = | |
772 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); | |
773 if (source_prerender != prerender_list_.end()) { | |
774 source_prerender->contents_->AddPendingPrerender( | |
775 origin, url_arg, referrer); | |
776 return true; | |
777 } | |
778 | |
779 DeleteOldEntries(); | |
780 DeletePendingDeleteEntries(); | |
781 | |
782 GURL url = url_arg; | |
783 GURL alias_url; | |
784 if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) | |
785 url = alias_url; | |
786 | |
787 // From here on, we will record a FinalStatus so we need to register with the | |
788 // histogram tracking. | |
789 histograms_->RecordPrerender(origin, url_arg); | |
790 | |
791 uint8 experiment = GetQueryStringBasedExperiment(url_arg); | |
792 | |
793 if (FindEntry(url)) { | |
794 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); | |
795 return false; | |
796 } | |
797 | |
798 // Do not prerender if there are too many render processes, and we would | |
799 // have to use an existing one. We do not want prerendering to happen in | |
800 // a shared process, so that we can always reliably lower the CPU | |
801 // priority for prerendering. | |
802 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns | |
803 // true, so that case needs to be explicitly checked for. | |
804 // TODO(tburkard): Figure out how to cancel prerendering in the opposite | |
805 // case, when a new tab is added to a process used for prerendering. | |
806 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost() && | |
807 !content::RenderProcessHost::run_renderer_in_process()) { | |
808 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); | |
809 return false; | |
810 } | |
811 | |
812 // Check if enough time has passed since the last prerender. | |
813 if (!DoesRateLimitAllowPrerender()) { | |
814 // Cancel the prerender. We could add it to the pending prerender list but | |
815 // this doesn't make sense as the next prerender request will be triggered | |
816 // by a navigation and is unlikely to be the same site. | |
817 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); | |
818 return false; | |
819 } | |
820 | |
821 RenderViewHost* source_render_view_host = NULL; | |
822 if (child_route_id_pair.first != -1) { | |
823 source_render_view_host = | |
824 RenderViewHost::FromID(child_route_id_pair.first, | |
825 child_route_id_pair.second); | |
826 // Don't prerender page if parent RenderViewHost no longer exists, or it has | |
827 // no view. The latter should only happen when the RenderView has closed. | |
828 if (!source_render_view_host || !source_render_view_host->view()) { | |
829 RecordFinalStatus(origin, experiment, | |
830 FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED); | |
831 return false; | |
832 } | |
833 } | |
834 | |
835 if (!session_storage_namespace && source_render_view_host) { | |
836 session_storage_namespace = | |
837 source_render_view_host->session_storage_namespace(); | |
838 } | |
839 | |
840 PrerenderContents* prerender_contents = CreatePrerenderContents( | |
841 url, referrer, origin, experiment); | |
842 if (!prerender_contents || !prerender_contents->Init()) | |
843 return false; | |
844 | |
845 histograms_->RecordPrerenderStarted(origin); | |
846 | |
847 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? | |
848 PrerenderContentsData data(prerender_contents, GetCurrentTime()); | |
849 | |
850 prerender_list_.push_back(data); | |
851 | |
852 if (IsControlGroup()) { | |
853 data.contents_->set_final_status(FINAL_STATUS_CONTROL_GROUP); | |
854 } else { | |
855 last_prerender_start_time_ = GetCurrentTimeTicks(); | |
856 data.contents_->StartPrerendering(source_render_view_host, | |
857 session_storage_namespace); | |
858 } | |
859 while (prerender_list_.size() > config_.max_elements) { | |
860 data = prerender_list_.front(); | |
861 prerender_list_.pop_front(); | |
862 data.contents_->Destroy(FINAL_STATUS_EVICTED); | |
863 } | |
864 StartSchedulingPeriodicCleanups(); | |
865 return true; | |
866 } | |
867 | |
868 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { | |
cbentzel
2012/01/25 12:14:01
I didn't check if all of the methods in this block
| |
869 return GetEntryButNotSpecifiedWC(url, NULL); | |
870 } | |
871 | |
872 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC( | |
873 const GURL& url, | |
874 WebContents* wc) { | |
875 DCHECK(CalledOnValidThread()); | |
876 DeleteOldEntries(); | |
877 DeletePendingDeleteEntries(); | |
878 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
879 it != prerender_list_.end(); | |
880 ++it) { | |
881 PrerenderContents* prerender_contents = it->contents_; | |
882 if (prerender_contents->MatchesURL(url, NULL)) { | |
883 if (!prerender_contents->prerender_contents() || | |
884 !wc || | |
885 prerender_contents->prerender_contents()->web_contents() != wc) { | |
886 prerender_list_.erase(it); | |
887 return prerender_contents; | |
888 } | |
889 } | |
890 } | |
891 // Entry not found. | |
892 return NULL; | |
893 } | |
894 | |
895 void PrerenderManager::StartSchedulingPeriodicCleanups() { | |
896 DCHECK(CalledOnValidThread()); | |
897 if (repeating_timer_.IsRunning()) | |
898 return; | |
899 repeating_timer_.Start(FROM_HERE, | |
900 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), | |
901 this, | |
902 &PrerenderManager::PeriodicCleanup); | |
903 } | |
904 | |
905 void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { | |
906 if (!prerender_list_.empty()) | |
907 return; | |
908 | |
909 DCHECK(CalledOnValidThread()); | |
910 repeating_timer_.Stop(); | |
911 } | |
912 | |
913 void PrerenderManager::PeriodicCleanup() { | |
914 DCHECK(CalledOnValidThread()); | |
915 DeleteOldTabContents(); | |
916 DeleteOldEntries(); | |
917 | |
918 // Grab a copy of the current PrerenderContents pointers, so that we | |
919 // will not interfere with potential deletions of the list. | |
920 std::vector<PrerenderContents*> prerender_contents; | |
921 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
922 it != prerender_list_.end(); | |
923 ++it) { | |
924 DCHECK(it->contents_); | |
925 prerender_contents.push_back(it->contents_); | |
926 } | |
927 for (std::vector<PrerenderContents*>::iterator it = | |
928 prerender_contents.begin(); | |
929 it != prerender_contents.end(); | |
930 ++it) { | |
931 (*it)->DestroyWhenUsingTooManyResources(); | |
932 } | |
933 | |
934 DeletePendingDeleteEntries(); | |
935 } | |
936 | |
937 void PrerenderManager::PostCleanupTask() { | |
938 DCHECK(CalledOnValidThread()); | |
939 MessageLoop::current()->PostTask( | |
940 FROM_HERE, | |
941 base::Bind(&PrerenderManager::PeriodicCleanup, | |
942 weak_factory_.GetWeakPtr())); | |
943 } | |
944 | |
945 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { | |
946 DCHECK(CalledOnValidThread()); | |
947 base::Time now = GetCurrentTime(); | |
948 return (now - start < config_.max_age); | |
949 } | |
950 | |
951 void PrerenderManager::DeleteOldEntries() { | |
952 DCHECK(CalledOnValidThread()); | |
953 while (!prerender_list_.empty()) { | |
954 PrerenderContentsData data = prerender_list_.front(); | |
955 if (IsPrerenderElementFresh(data.start_time_)) | |
956 return; | |
957 data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); | |
958 } | |
959 MaybeStopSchedulingPeriodicCleanups(); | |
960 } | |
961 | |
962 base::Time PrerenderManager::GetCurrentTime() const { | |
963 return base::Time::Now(); | |
964 } | |
965 | |
966 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { | |
967 return base::TimeTicks::Now(); | |
968 } | |
969 | |
970 PrerenderContents* PrerenderManager::CreatePrerenderContents( | |
971 const GURL& url, | |
972 const content::Referrer& referrer, | |
973 Origin origin, | |
974 uint8 experiment_id) { | |
975 DCHECK(CalledOnValidThread()); | |
976 return prerender_contents_factory_->CreatePrerenderContents( | |
977 this, prerender_tracker_, profile_, url, | |
978 referrer, origin, experiment_id); | |
979 } | |
980 | |
981 bool PrerenderManager::IsPendingDelete(PrerenderContents* entry) const { | |
982 DCHECK(CalledOnValidThread()); | |
983 for (std::list<PrerenderContents*>::const_iterator it = | |
984 pending_delete_list_.begin(); | |
985 it != pending_delete_list_.end(); | |
986 ++it) { | |
987 if (*it == entry) | |
988 return true; | |
989 } | |
990 | |
991 return false; | |
992 } | |
993 | |
994 void PrerenderManager::DeletePendingDeleteEntries() { | |
995 while (!pending_delete_list_.empty()) { | |
996 PrerenderContents* contents = pending_delete_list_.front(); | |
997 pending_delete_list_.pop_front(); | |
998 delete contents; | |
999 } | |
1000 } | |
1001 | |
1002 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) { | |
1003 DCHECK(CalledOnValidThread()); | |
1004 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
1005 it != prerender_list_.end(); | |
1006 ++it) { | |
1007 if (it->contents_->MatchesURL(url, NULL)) | |
1008 return it->contents_; | |
1009 } | |
1010 // Entry not found. | |
1011 return NULL; | |
1012 } | |
1013 | |
1014 std::list<PrerenderManager::PrerenderContentsData>::iterator | |
1015 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( | |
1016 const std::pair<int, int>& child_route_id_pair) { | |
1017 std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
1018 for (; it != prerender_list_.end(); ++it) { | |
1019 PrerenderContents* prerender_contents = it->contents_; | |
1020 | |
1021 int child_id; | |
1022 int route_id; | |
1023 bool has_child_id = prerender_contents->GetChildId(&child_id); | |
1024 bool has_route_id = has_child_id && | |
1025 prerender_contents->GetRouteId(&route_id); | |
1026 | |
1027 if (has_child_id && has_route_id && | |
1028 child_id == child_route_id_pair.first && | |
1029 route_id == child_route_id_pair.second) { | |
1030 break; | |
1031 } | |
1032 } | |
1033 return it; | |
1034 } | |
1035 | |
1036 bool PrerenderManager::DoesRateLimitAllowPrerender() const { | |
1037 DCHECK(CalledOnValidThread()); | |
1038 base::TimeDelta elapsed_time = | |
1039 GetCurrentTimeTicks() - last_prerender_start_time_; | |
1040 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); | |
1041 if (!config_.rate_limit_enabled) | |
1042 return true; | |
1043 return elapsed_time > | |
1044 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); | |
1045 } | |
1046 | |
1047 void PrerenderManager::DeleteOldTabContents() { | |
1048 while (!old_tab_contents_list_.empty()) { | |
1049 TabContentsWrapper* tab_contents = old_tab_contents_list_.front(); | |
1050 old_tab_contents_list_.pop_front(); | |
1051 // TODO(dominich): should we use Instant Unload Handler here? | |
1052 delete tab_contents; | |
1053 } | |
1054 } | |
1055 | |
1056 void PrerenderManager::CleanUpOldNavigations() { | |
1057 DCHECK(CalledOnValidThread()); | |
1058 | |
1059 // Cutoff. Navigations before this cutoff can be discarded. | |
1060 base::TimeTicks cutoff = GetCurrentTimeTicks() - | |
1061 base::TimeDelta::FromMilliseconds(kNavigationRecordWindowMs); | |
1062 while (!navigations_.empty()) { | |
1063 if (navigations_.front().time_ > cutoff) | |
1064 break; | |
1065 navigations_.pop_front(); | |
1066 } | |
1067 } | |
1068 | |
1069 void PrerenderManager::ScheduleDeleteOldTabContents( | |
1070 TabContentsWrapper* tab, | |
1071 OnCloseTabContentsDeleter* deleter) { | |
1072 old_tab_contents_list_.push_back(tab); | |
1073 PostCleanupTask(); | |
1074 | |
1075 if (deleter) { | |
1076 ScopedVector<OnCloseTabContentsDeleter>::iterator i = std::find( | |
1077 on_close_tab_contents_deleters_.begin(), | |
1078 on_close_tab_contents_deleters_.end(), | |
1079 deleter); | |
1080 DCHECK(i != on_close_tab_contents_deleters_.end()); | |
1081 on_close_tab_contents_deleters_.erase(i); | |
1082 } | |
1083 } | |
1084 | |
1063 void PrerenderManager::AddToHistory(PrerenderContents* contents) { | 1085 void PrerenderManager::AddToHistory(PrerenderContents* contents) { |
1064 PrerenderHistory::Entry entry(contents->prerender_url(), | 1086 PrerenderHistory::Entry entry(contents->prerender_url(), |
1065 contents->final_status(), | 1087 contents->final_status(), |
1066 contents->origin(), | 1088 contents->origin(), |
1067 base::Time::Now()); | 1089 base::Time::Now()); |
1068 prerender_history_->AddEntry(entry); | 1090 prerender_history_->AddEntry(entry); |
1069 } | 1091 } |
1070 | 1092 |
1071 void PrerenderManager::RecordNavigation(const GURL& url) { | 1093 void PrerenderManager::RecordNavigation(const GURL& url) { |
1072 DCHECK(CalledOnValidThread()); | 1094 DCHECK(CalledOnValidThread()); |
(...skipping 19 matching lines...) Expand all Loading... | |
1092 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { | 1114 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { |
1093 DeleteOldTabContents(); | 1115 DeleteOldTabContents(); |
1094 while (!prerender_list_.empty()) { | 1116 while (!prerender_list_.empty()) { |
1095 PrerenderContentsData data = prerender_list_.front(); | 1117 PrerenderContentsData data = prerender_list_.front(); |
1096 prerender_list_.pop_front(); | 1118 prerender_list_.pop_front(); |
1097 data.contents_->Destroy(final_status); | 1119 data.contents_->Destroy(final_status); |
1098 } | 1120 } |
1099 DeletePendingDeleteEntries(); | 1121 DeletePendingDeleteEntries(); |
1100 } | 1122 } |
1101 | 1123 |
1102 void PrerenderManager::RecordFinalStatus(Origin origin, | |
1103 uint8 experiment_id, | |
1104 FinalStatus final_status) const { | |
1105 histograms_->RecordFinalStatus(origin, experiment_id, final_status); | |
1106 } | |
1107 | |
1108 PrerenderManager* FindPrerenderManagerUsingRenderProcessId( | 1124 PrerenderManager* FindPrerenderManagerUsingRenderProcessId( |
1109 int render_process_id) { | 1125 int render_process_id) { |
1110 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 1126 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
1111 content::RenderProcessHost* render_process_host = | 1127 content::RenderProcessHost* render_process_host = |
1112 content::RenderProcessHost::FromID(render_process_id); | 1128 content::RenderProcessHost::FromID(render_process_id); |
1113 // Each render process is guaranteed to only hold RenderViews owned by the | 1129 // Each render process is guaranteed to only hold RenderViews owned by the |
1114 // same BrowserContext. This is enforced by | 1130 // same BrowserContext. This is enforced by |
1115 // RenderProcessHost::GetExistingProcessHost. | 1131 // RenderProcessHost::GetExistingProcessHost. |
1116 if (!render_process_host || !render_process_host->GetBrowserContext()) | 1132 if (!render_process_host || !render_process_host->GetBrowserContext()) |
1117 return NULL; | 1133 return NULL; |
1118 Profile* profile = Profile::FromBrowserContext( | 1134 Profile* profile = Profile::FromBrowserContext( |
1119 render_process_host->GetBrowserContext()); | 1135 render_process_host->GetBrowserContext()); |
1120 if (!profile) | 1136 if (!profile) |
1121 return NULL; | 1137 return NULL; |
1122 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); | 1138 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); |
1123 } | 1139 } |
1124 | 1140 |
1125 } // namespace prerender | 1141 } // namespace prerender |
OLD | NEW |