Chromium Code Reviews| Index: chrome/browser/prerender/prerender_manager.cc |
| diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc |
| index 59bb8609fd6a56cf8b05fb11f920b8a2b014b779..e52557c3721f09c43afdf9c3228e19f1a88cd2d2 100644 |
| --- a/chrome/browser/prerender/prerender_manager.cc |
| +++ b/chrome/browser/prerender/prerender_manager.cc |
| @@ -153,52 +153,6 @@ int PrerenderManager::prerenders_per_session_count_ = 0; |
| PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = |
| PRERENDER_MODE_ENABLED; |
| -// static |
| -PrerenderManager::PrerenderManagerMode PrerenderManager::GetMode() { |
| - return mode_; |
| -} |
| - |
| -// static |
| -void PrerenderManager::SetMode(PrerenderManagerMode mode) { |
| - mode_ = mode; |
| -} |
| - |
| -// static |
| -bool PrerenderManager::IsPrerenderingPossible() { |
| - return GetMode() == PRERENDER_MODE_ENABLED || |
| - GetMode() == PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP || |
| - GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP || |
| - GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; |
| -} |
| - |
| -// static |
| -bool PrerenderManager::ActuallyPrerendering() { |
| - return IsPrerenderingPossible() && !IsControlGroup(); |
| -} |
| - |
| -// static |
| -bool PrerenderManager::IsControlGroup() { |
| - return GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP; |
| -} |
| - |
| -// static |
| -bool PrerenderManager::IsNoUseGroup() { |
| - return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; |
| -} |
| - |
| -// static |
| -bool PrerenderManager::IsValidHttpMethod(const std::string& method) { |
| - // method has been canonicalized to upper case at this point so we can just |
| - // compare them. |
| - DCHECK_EQ(method, StringToUpperASCII(method)); |
| - for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) { |
| - if (method.compare(kValidHttpMethods[i]) == 0) |
| - return true; |
| - } |
| - |
| - return false; |
| -} |
| - |
| struct PrerenderManager::PrerenderContentsData { |
| PrerenderContents* contents_; |
| base::Time start_time_; |
| @@ -272,24 +226,6 @@ class PrerenderManager::MostVisitedSites |
| std::set<GURL> urls_; |
| }; |
| -bool PrerenderManager::IsTopSite(const GURL& url) { |
| - if (!most_visited_.get()) |
| - most_visited_.reset(new MostVisitedSites(profile_)); |
| - return most_visited_->IsTopSite(url); |
| -} |
| - |
| -bool PrerenderManager::IsPendingEntry(const GURL& url) const { |
| - DCHECK(CalledOnValidThread()); |
| - for (std::list<PrerenderContentsData>::const_iterator it = |
| - prerender_list_.begin(); |
| - it != prerender_list_.end(); |
| - ++it) { |
| - if (it->contents_->IsPendingEntry(url)) |
| - return true; |
| - } |
| - return false; |
| -} |
| - |
| PrerenderManager::PrerenderManager(Profile* profile, |
| PrerenderTracker* prerender_tracker) |
| : enabled_(true), |
| @@ -314,12 +250,6 @@ void PrerenderManager::Shutdown() { |
| DoShutdown(); |
| } |
| -void PrerenderManager::SetPrerenderContentsFactory( |
| - PrerenderContents::Factory* prerender_contents_factory) { |
| - DCHECK(CalledOnValidThread()); |
| - prerender_contents_factory_.reset(prerender_contents_factory); |
| -} |
| - |
| bool PrerenderManager::AddPrerenderFromLinkRelPrerender( |
| int process_id, |
| int route_id, |
| @@ -335,146 +265,12 @@ bool PrerenderManager::AddPrerenderFromLinkRelPrerender( |
| bool PrerenderManager::AddPrerenderFromOmnibox( |
| const GURL& url, |
| SessionStorageNamespace* session_storage_namespace) { |
| - DCHECK(session_storage_namespace); |
|
cbentzel
2012/01/25 12:14:01
Why was this removed?
|
| if (!IsOmniboxEnabled(profile_)) |
| return false; |
| return AddPrerender(ORIGIN_OMNIBOX, std::make_pair(-1, -1), url, |
| content::Referrer(), session_storage_namespace); |
| } |
| -bool PrerenderManager::AddPrerender( |
| - Origin origin, |
| - const std::pair<int, int>& child_route_id_pair, |
| - const GURL& url_arg, |
| - const content::Referrer& referrer, |
| - SessionStorageNamespace* session_storage_namespace) { |
| - DCHECK(CalledOnValidThread()); |
| - |
| - if (origin == ORIGIN_LINK_REL_PRERENDER && |
| - IsGoogleSearchResultURL(referrer.url)) { |
| - origin = ORIGIN_GWS_PRERENDER; |
| - } |
| - |
| - // If the referring page is prerendering, defer the prerender. |
| - std::list<PrerenderContentsData>::iterator source_prerender = |
| - FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); |
| - if (source_prerender != prerender_list_.end()) { |
| - source_prerender->contents_->AddPendingPrerender( |
| - origin, url_arg, referrer); |
| - return true; |
| - } |
| - |
| - DeleteOldEntries(); |
| - DeletePendingDeleteEntries(); |
| - |
| - GURL url = url_arg; |
| - GURL alias_url; |
| - if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) |
| - url = alias_url; |
| - |
| - // From here on, we will record a FinalStatus so we need to register with the |
| - // histogram tracking. |
| - histograms_->RecordPrerender(origin, url_arg); |
| - |
| - uint8 experiment = GetQueryStringBasedExperiment(url_arg); |
| - |
| - if (FindEntry(url)) { |
| - RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); |
| - return false; |
| - } |
| - |
| - // Do not prerender if there are too many render processes, and we would |
| - // have to use an existing one. We do not want prerendering to happen in |
| - // a shared process, so that we can always reliably lower the CPU |
| - // priority for prerendering. |
| - // In single-process mode, ShouldTryToUseExistingProcessHost() always returns |
| - // true, so that case needs to be explicitly checked for. |
| - // TODO(tburkard): Figure out how to cancel prerendering in the opposite |
| - // case, when a new tab is added to a process used for prerendering. |
| - if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost() && |
| - !content::RenderProcessHost::run_renderer_in_process()) { |
| - RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); |
| - return false; |
| - } |
| - |
| - // Check if enough time has passed since the last prerender. |
| - if (!DoesRateLimitAllowPrerender()) { |
| - // Cancel the prerender. We could add it to the pending prerender list but |
| - // this doesn't make sense as the next prerender request will be triggered |
| - // by a navigation and is unlikely to be the same site. |
| - RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
| - return false; |
| - } |
| - |
| - RenderViewHost* source_render_view_host = NULL; |
| - if (child_route_id_pair.first != -1) { |
| - source_render_view_host = |
| - RenderViewHost::FromID(child_route_id_pair.first, |
| - child_route_id_pair.second); |
| - // Don't prerender page if parent RenderViewHost no longer exists, or it has |
| - // no view. The latter should only happen when the RenderView has closed. |
| - if (!source_render_view_host || !source_render_view_host->view()) { |
| - RecordFinalStatus(origin, experiment, |
| - FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED); |
| - return false; |
| - } |
| - } |
| - |
| - if (!session_storage_namespace && source_render_view_host) { |
| - session_storage_namespace = |
| - source_render_view_host->session_storage_namespace(); |
| - } |
| - |
| - PrerenderContents* prerender_contents = CreatePrerenderContents( |
| - url, referrer, origin, experiment); |
| - if (!prerender_contents || !prerender_contents->Init()) |
| - return false; |
| - |
| - histograms_->RecordPrerenderStarted(origin); |
| - |
| - // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? |
| - PrerenderContentsData data(prerender_contents, GetCurrentTime()); |
| - |
| - prerender_list_.push_back(data); |
| - |
| - if (IsControlGroup()) { |
| - data.contents_->set_final_status(FINAL_STATUS_CONTROL_GROUP); |
| - } else { |
| - last_prerender_start_time_ = GetCurrentTimeTicks(); |
| - data.contents_->StartPrerendering(source_render_view_host, |
| - session_storage_namespace); |
| - } |
| - while (prerender_list_.size() > config_.max_elements) { |
| - data = prerender_list_.front(); |
| - prerender_list_.pop_front(); |
| - data.contents_->Destroy(FINAL_STATUS_EVICTED); |
| - } |
| - StartSchedulingPeriodicCleanups(); |
| - return true; |
| -} |
| - |
| -std::list<PrerenderManager::PrerenderContentsData>::iterator |
| - PrerenderManager::FindPrerenderContentsForChildRouteIdPair( |
| - const std::pair<int, int>& child_route_id_pair) { |
| - std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| - for (; it != prerender_list_.end(); ++it) { |
| - PrerenderContents* prerender_contents = it->contents_; |
| - |
| - int child_id; |
| - int route_id; |
| - bool has_child_id = prerender_contents->GetChildId(&child_id); |
| - bool has_route_id = has_child_id && |
| - prerender_contents->GetRouteId(&route_id); |
| - |
| - if (has_child_id && has_route_id && |
| - child_id == child_route_id_pair.first && |
| - route_id == child_route_id_pair.second) { |
| - break; |
| - } |
| - } |
| - return it; |
| -} |
| - |
| void PrerenderManager::DestroyPrerenderForRenderView( |
| int process_id, int view_id, FinalStatus final_status) { |
| DCHECK(CalledOnValidThread()); |
| @@ -496,42 +292,14 @@ void PrerenderManager::CancelAllPrerenders() { |
| } |
| } |
| -void PrerenderManager::DeleteOldEntries() { |
| - DCHECK(CalledOnValidThread()); |
| - while (!prerender_list_.empty()) { |
| - PrerenderContentsData data = prerender_list_.front(); |
| - if (IsPrerenderElementFresh(data.start_time_)) |
| - return; |
| - data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); |
| - } |
| - MaybeStopSchedulingPeriodicCleanups(); |
| -} |
| - |
| -PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC( |
| - const GURL& url, |
| - WebContents* wc) { |
| +void PrerenderManager::CancelOmniboxPrerenders() { |
| DCHECK(CalledOnValidThread()); |
| - DeleteOldEntries(); |
| - DeletePendingDeleteEntries(); |
| 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
|
| - it != prerender_list_.end(); |
| - ++it) { |
| - PrerenderContents* prerender_contents = it->contents_; |
| - if (prerender_contents->MatchesURL(url, NULL)) { |
| - if (!prerender_contents->prerender_contents() || |
| - !wc || |
| - prerender_contents->prerender_contents()->web_contents() != wc) { |
| - prerender_list_.erase(it); |
| - return prerender_contents; |
| - } |
| - } |
| + it != prerender_list_.end(); ) { |
| + std::list<PrerenderContentsData>::iterator cur = it++; |
| + if (cur->contents_->origin() == ORIGIN_OMNIBOX) |
| + cur->contents_->Destroy(FINAL_STATUS_CANCELLED); |
| } |
| - // Entry not found. |
| - return NULL; |
| -} |
| - |
| -PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { |
| - return GetEntryButNotSpecifiedWC(url, NULL); |
| } |
| bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, |
| @@ -741,52 +509,6 @@ void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry, |
| PostCleanupTask(); |
| } |
| -base::Time PrerenderManager::GetCurrentTime() const { |
| - return base::Time::Now(); |
| -} |
| - |
| -base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { |
| - return base::TimeTicks::Now(); |
| -} |
| - |
| -bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { |
| - DCHECK(CalledOnValidThread()); |
| - base::Time now = GetCurrentTime(); |
| - return (now - start < config_.max_age); |
| -} |
| - |
| -PrerenderContents* PrerenderManager::CreatePrerenderContents( |
| - const GURL& url, |
| - const content::Referrer& referrer, |
| - Origin origin, |
| - uint8 experiment_id) { |
| - DCHECK(CalledOnValidThread()); |
| - return prerender_contents_factory_->CreatePrerenderContents( |
| - this, prerender_tracker_, profile_, url, |
| - referrer, origin, experiment_id); |
| -} |
| - |
| -bool PrerenderManager::IsPendingDelete(PrerenderContents* entry) const { |
| - DCHECK(CalledOnValidThread()); |
| - for (std::list<PrerenderContents*>::const_iterator it = |
| - pending_delete_list_.begin(); |
| - it != pending_delete_list_.end(); |
| - ++it) { |
| - if (*it == entry) |
| - return true; |
| - } |
| - |
| - return false; |
| -} |
| - |
| -void PrerenderManager::DeletePendingDeleteEntries() { |
| - while (!pending_delete_list_.empty()) { |
| - PrerenderContents* contents = pending_delete_list_.front(); |
| - pending_delete_list_.pop_front(); |
| - delete contents; |
| - } |
| -} |
| - |
| // static |
| void PrerenderManager::RecordPerceivedPageLoadTime( |
| base::TimeDelta perceived_page_load_time, |
| @@ -828,108 +550,37 @@ void PrerenderManager::set_enabled(bool enabled) { |
| enabled_ = enabled; |
| } |
| -void PrerenderManager::AddCondition(const PrerenderCondition* condition) { |
| - prerender_conditions_.push_back(condition); |
| -} |
| - |
| -PrerenderContents* PrerenderManager::FindEntry(const GURL& url) { |
| - DCHECK(CalledOnValidThread()); |
| - for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| - it != prerender_list_.end(); |
| - ++it) { |
| - if (it->contents_->MatchesURL(url, NULL)) |
| - return it->contents_; |
| - } |
| - // Entry not found. |
| - return NULL; |
| -} |
| - |
| -void PrerenderManager::DoShutdown() { |
| - DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); |
| - STLDeleteElements(&prerender_conditions_); |
| - profile_ = NULL; |
| -} |
| - |
| -bool PrerenderManager::DoesRateLimitAllowPrerender() const { |
| - DCHECK(CalledOnValidThread()); |
| - base::TimeDelta elapsed_time = |
| - GetCurrentTimeTicks() - last_prerender_start_time_; |
| - histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); |
| - if (!config_.rate_limit_enabled) |
| - return true; |
| - return elapsed_time > |
| - base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); |
| -} |
| - |
| -void PrerenderManager::StartSchedulingPeriodicCleanups() { |
| - DCHECK(CalledOnValidThread()); |
| - if (repeating_timer_.IsRunning()) |
| - return; |
| - repeating_timer_.Start(FROM_HERE, |
| - base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), |
| - this, |
| - &PrerenderManager::PeriodicCleanup); |
| +// static |
| +PrerenderManager::PrerenderManagerMode PrerenderManager::GetMode() { |
| + return mode_; |
| } |
| -void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { |
| - if (!prerender_list_.empty()) |
| - return; |
| - |
| - DCHECK(CalledOnValidThread()); |
| - repeating_timer_.Stop(); |
| +// static |
| +void PrerenderManager::SetMode(PrerenderManagerMode mode) { |
| + mode_ = mode; |
| } |
| -void PrerenderManager::DeleteOldTabContents() { |
| - while (!old_tab_contents_list_.empty()) { |
| - TabContentsWrapper* tab_contents = old_tab_contents_list_.front(); |
| - old_tab_contents_list_.pop_front(); |
| - // TODO(dominich): should we use Instant Unload Handler here? |
| - delete tab_contents; |
| - } |
| +// static |
| +bool PrerenderManager::IsPrerenderingPossible() { |
| + return GetMode() == PRERENDER_MODE_ENABLED || |
| + GetMode() == PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP || |
| + GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP || |
| + GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; |
| } |
| -bool PrerenderManager::IsOldRenderViewHost( |
| - const RenderViewHost* render_view_host) const { |
| - for (std::list<TabContentsWrapper*>::const_iterator it = |
| - old_tab_contents_list_.begin(); |
| - it != old_tab_contents_list_.end(); |
| - ++it) { |
| - if ((*it)->web_contents()->GetRenderViewHost() == render_view_host) |
| - return true; |
| - } |
| - return false; |
| +// static |
| +bool PrerenderManager::ActuallyPrerendering() { |
| + return IsPrerenderingPossible() && !IsControlGroup(); |
| } |
| -void PrerenderManager::PeriodicCleanup() { |
| - DCHECK(CalledOnValidThread()); |
| - DeleteOldTabContents(); |
| - DeleteOldEntries(); |
| - |
| - // Grab a copy of the current PrerenderContents pointers, so that we |
| - // will not interfere with potential deletions of the list. |
| - std::vector<PrerenderContents*> prerender_contents; |
| - for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| - it != prerender_list_.end(); |
| - ++it) { |
| - DCHECK(it->contents_); |
| - prerender_contents.push_back(it->contents_); |
| - } |
| - for (std::vector<PrerenderContents*>::iterator it = |
| - prerender_contents.begin(); |
| - it != prerender_contents.end(); |
| - ++it) { |
| - (*it)->DestroyWhenUsingTooManyResources(); |
| - } |
| - |
| - DeletePendingDeleteEntries(); |
| +// static |
| +bool PrerenderManager::IsControlGroup() { |
| + return GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP; |
| } |
| -void PrerenderManager::PostCleanupTask() { |
| - DCHECK(CalledOnValidThread()); |
| - MessageLoop::current()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&PrerenderManager::PeriodicCleanup, |
| - weak_factory_.GetWeakPtr())); |
| +// static |
| +bool PrerenderManager::IsNoUseGroup() { |
| + return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; |
| } |
| bool PrerenderManager::IsWebContentsPrerendering( |
| @@ -992,6 +643,18 @@ bool PrerenderManager::WouldWebContentsBePrerendered( |
| return would_be_prerendered_tab_contents_set_.count(web_contents) > 0; |
| } |
| +bool PrerenderManager::IsOldRenderViewHost( |
| + const RenderViewHost* render_view_host) const { |
| + for (std::list<TabContentsWrapper*>::const_iterator it = |
| + old_tab_contents_list_.begin(); |
| + it != old_tab_contents_list_.end(); |
| + ++it) { |
| + if ((*it)->web_contents()->GetRenderViewHost() == render_view_host) |
| + return true; |
| + } |
| + return false; |
| +} |
| + |
| bool PrerenderManager::HasRecentlyBeenNavigatedTo(const GURL& url) { |
| DCHECK(CalledOnValidThread()); |
| @@ -1006,33 +669,17 @@ bool PrerenderManager::HasRecentlyBeenNavigatedTo(const GURL& url) { |
| return false; |
| } |
| -void PrerenderManager::CleanUpOldNavigations() { |
| - DCHECK(CalledOnValidThread()); |
| - |
| - // Cutoff. Navigations before this cutoff can be discarded. |
| - base::TimeTicks cutoff = GetCurrentTimeTicks() - |
| - base::TimeDelta::FromMilliseconds(kNavigationRecordWindowMs); |
| - while (!navigations_.empty()) { |
| - if (navigations_.front().time_ > cutoff) |
| - break; |
| - navigations_.pop_front(); |
| +// static |
| +bool PrerenderManager::IsValidHttpMethod(const std::string& method) { |
| + // method has been canonicalized to upper case at this point so we can just |
| + // compare them. |
| + DCHECK_EQ(method, StringToUpperASCII(method)); |
| + for (size_t i = 0; i < arraysize(kValidHttpMethods); ++i) { |
| + if (method.compare(kValidHttpMethods[i]) == 0) |
| + return true; |
| } |
| -} |
| - |
| -void PrerenderManager::ScheduleDeleteOldTabContents( |
| - TabContentsWrapper* tab, |
| - OnCloseTabContentsDeleter* deleter) { |
| - old_tab_contents_list_.push_back(tab); |
| - PostCleanupTask(); |
| - if (deleter) { |
| - ScopedVector<OnCloseTabContentsDeleter>::iterator i = std::find( |
| - on_close_tab_contents_deleters_.begin(), |
| - on_close_tab_contents_deleters_.end(), |
| - deleter); |
| - DCHECK(i != on_close_tab_contents_deleters_.end()); |
| - on_close_tab_contents_deleters_.erase(i); |
| - } |
| + return false; |
| } |
| DictionaryValue* PrerenderManager::GetAsValue() const { |
| @@ -1060,49 +707,418 @@ void PrerenderManager::ClearData(int clear_flags) { |
| prerender_history_->Clear(); |
| } |
| -void PrerenderManager::AddToHistory(PrerenderContents* contents) { |
| - PrerenderHistory::Entry entry(contents->prerender_url(), |
| - contents->final_status(), |
| - contents->origin(), |
| - base::Time::Now()); |
| - prerender_history_->AddEntry(entry); |
| +void PrerenderManager::RecordFinalStatus(Origin origin, |
| + uint8 experiment_id, |
| + FinalStatus final_status) const { |
| + histograms_->RecordFinalStatus(origin, experiment_id, final_status); |
| } |
| -void PrerenderManager::RecordNavigation(const GURL& url) { |
| - DCHECK(CalledOnValidThread()); |
| +void PrerenderManager::AddCondition(const PrerenderCondition* condition) { |
| + prerender_conditions_.push_back(condition); |
| +} |
| - navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); |
| - CleanUpOldNavigations(); |
| +bool PrerenderManager::IsTopSite(const GURL& url) { |
| + if (!most_visited_.get()) |
| + most_visited_.reset(new MostVisitedSites(profile_)); |
| + return most_visited_->IsTopSite(url); |
| } |
| -Value* PrerenderManager::GetActivePrerendersAsValue() const { |
| - ListValue* list_value = new ListValue(); |
| +bool PrerenderManager::IsPendingEntry(const GURL& url) const { |
| + DCHECK(CalledOnValidThread()); |
| for (std::list<PrerenderContentsData>::const_iterator it = |
| prerender_list_.begin(); |
| it != prerender_list_.end(); |
| ++it) { |
| - Value* prerender_value = it->contents_->GetAsValue(); |
| - if (!prerender_value) |
| - continue; |
| - list_value->Append(prerender_value); |
| + if (it->contents_->IsPendingEntry(url)) |
| + return true; |
| } |
| - return list_value; |
| + return false; |
| } |
| -void PrerenderManager::DestroyAllContents(FinalStatus final_status) { |
| - DeleteOldTabContents(); |
| - while (!prerender_list_.empty()) { |
| - PrerenderContentsData data = prerender_list_.front(); |
| - prerender_list_.pop_front(); |
| - data.contents_->Destroy(final_status); |
| - } |
| - DeletePendingDeleteEntries(); |
| +bool PrerenderManager::IsPrerendering(const GURL& url) { |
| + DCHECK(CalledOnValidThread()); |
| + return (FindEntry(url) != NULL); |
| } |
| -void PrerenderManager::RecordFinalStatus(Origin origin, |
| - uint8 experiment_id, |
| - FinalStatus final_status) const { |
| - histograms_->RecordFinalStatus(origin, experiment_id, final_status); |
| +// protected |
| +void PrerenderManager::SetPrerenderContentsFactory( |
| + PrerenderContents::Factory* prerender_contents_factory) { |
| + DCHECK(CalledOnValidThread()); |
| + prerender_contents_factory_.reset(prerender_contents_factory); |
| +} |
| + |
| +void PrerenderManager::DoShutdown() { |
| + DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); |
| + STLDeleteElements(&prerender_conditions_); |
| + profile_ = NULL; |
| +} |
| + |
| +// private |
|
cbentzel
2012/01/25 12:14:01
Nit: I haven't really seen the // private comment
|
| +bool PrerenderManager::AddPrerender( |
| + Origin origin, |
| + const std::pair<int, int>& child_route_id_pair, |
| + const GURL& url_arg, |
| + const content::Referrer& referrer, |
| + SessionStorageNamespace* session_storage_namespace) { |
| + DCHECK(CalledOnValidThread()); |
| + |
| + if (origin == ORIGIN_LINK_REL_PRERENDER && |
| + IsGoogleSearchResultURL(referrer.url)) { |
| + origin = ORIGIN_GWS_PRERENDER; |
| + } |
| + |
| + // If the referring page is prerendering, defer the prerender. |
| + std::list<PrerenderContentsData>::iterator source_prerender = |
| + FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); |
| + if (source_prerender != prerender_list_.end()) { |
| + source_prerender->contents_->AddPendingPrerender( |
| + origin, url_arg, referrer); |
| + return true; |
| + } |
| + |
| + DeleteOldEntries(); |
| + DeletePendingDeleteEntries(); |
| + |
| + GURL url = url_arg; |
| + GURL alias_url; |
| + if (IsControlGroup() && MaybeGetQueryStringBasedAliasURL(url, &alias_url)) |
| + url = alias_url; |
| + |
| + // From here on, we will record a FinalStatus so we need to register with the |
| + // histogram tracking. |
| + histograms_->RecordPrerender(origin, url_arg); |
| + |
| + uint8 experiment = GetQueryStringBasedExperiment(url_arg); |
| + |
| + if (FindEntry(url)) { |
| + RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); |
| + return false; |
| + } |
| + |
| + // Do not prerender if there are too many render processes, and we would |
| + // have to use an existing one. We do not want prerendering to happen in |
| + // a shared process, so that we can always reliably lower the CPU |
| + // priority for prerendering. |
| + // In single-process mode, ShouldTryToUseExistingProcessHost() always returns |
| + // true, so that case needs to be explicitly checked for. |
| + // TODO(tburkard): Figure out how to cancel prerendering in the opposite |
| + // case, when a new tab is added to a process used for prerendering. |
| + if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost() && |
| + !content::RenderProcessHost::run_renderer_in_process()) { |
| + RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); |
| + return false; |
| + } |
| + |
| + // Check if enough time has passed since the last prerender. |
| + if (!DoesRateLimitAllowPrerender()) { |
| + // Cancel the prerender. We could add it to the pending prerender list but |
| + // this doesn't make sense as the next prerender request will be triggered |
| + // by a navigation and is unlikely to be the same site. |
| + RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); |
| + return false; |
| + } |
| + |
| + RenderViewHost* source_render_view_host = NULL; |
| + if (child_route_id_pair.first != -1) { |
| + source_render_view_host = |
| + RenderViewHost::FromID(child_route_id_pair.first, |
| + child_route_id_pair.second); |
| + // Don't prerender page if parent RenderViewHost no longer exists, or it has |
| + // no view. The latter should only happen when the RenderView has closed. |
| + if (!source_render_view_host || !source_render_view_host->view()) { |
| + RecordFinalStatus(origin, experiment, |
| + FINAL_STATUS_SOURCE_RENDER_VIEW_CLOSED); |
| + return false; |
| + } |
| + } |
| + |
| + if (!session_storage_namespace && source_render_view_host) { |
| + session_storage_namespace = |
| + source_render_view_host->session_storage_namespace(); |
| + } |
| + |
| + PrerenderContents* prerender_contents = CreatePrerenderContents( |
| + url, referrer, origin, experiment); |
| + if (!prerender_contents || !prerender_contents->Init()) |
| + return false; |
| + |
| + histograms_->RecordPrerenderStarted(origin); |
| + |
| + // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? |
| + PrerenderContentsData data(prerender_contents, GetCurrentTime()); |
| + |
| + prerender_list_.push_back(data); |
| + |
| + if (IsControlGroup()) { |
| + data.contents_->set_final_status(FINAL_STATUS_CONTROL_GROUP); |
| + } else { |
| + last_prerender_start_time_ = GetCurrentTimeTicks(); |
| + data.contents_->StartPrerendering(source_render_view_host, |
| + session_storage_namespace); |
| + } |
| + while (prerender_list_.size() > config_.max_elements) { |
| + data = prerender_list_.front(); |
| + prerender_list_.pop_front(); |
| + data.contents_->Destroy(FINAL_STATUS_EVICTED); |
| + } |
| + StartSchedulingPeriodicCleanups(); |
| + return true; |
| +} |
| + |
| +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
|
| + return GetEntryButNotSpecifiedWC(url, NULL); |
| +} |
| + |
| +PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC( |
| + const GURL& url, |
| + WebContents* wc) { |
| + DCHECK(CalledOnValidThread()); |
| + DeleteOldEntries(); |
| + DeletePendingDeleteEntries(); |
| + for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| + it != prerender_list_.end(); |
| + ++it) { |
| + PrerenderContents* prerender_contents = it->contents_; |
| + if (prerender_contents->MatchesURL(url, NULL)) { |
| + if (!prerender_contents->prerender_contents() || |
| + !wc || |
| + prerender_contents->prerender_contents()->web_contents() != wc) { |
| + prerender_list_.erase(it); |
| + return prerender_contents; |
| + } |
| + } |
| + } |
| + // Entry not found. |
| + return NULL; |
| +} |
| + |
| +void PrerenderManager::StartSchedulingPeriodicCleanups() { |
| + DCHECK(CalledOnValidThread()); |
| + if (repeating_timer_.IsRunning()) |
| + return; |
| + repeating_timer_.Start(FROM_HERE, |
| + base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), |
| + this, |
| + &PrerenderManager::PeriodicCleanup); |
| +} |
| + |
| +void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { |
| + if (!prerender_list_.empty()) |
| + return; |
| + |
| + DCHECK(CalledOnValidThread()); |
| + repeating_timer_.Stop(); |
| +} |
| + |
| +void PrerenderManager::PeriodicCleanup() { |
| + DCHECK(CalledOnValidThread()); |
| + DeleteOldTabContents(); |
| + DeleteOldEntries(); |
| + |
| + // Grab a copy of the current PrerenderContents pointers, so that we |
| + // will not interfere with potential deletions of the list. |
| + std::vector<PrerenderContents*> prerender_contents; |
| + for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| + it != prerender_list_.end(); |
| + ++it) { |
| + DCHECK(it->contents_); |
| + prerender_contents.push_back(it->contents_); |
| + } |
| + for (std::vector<PrerenderContents*>::iterator it = |
| + prerender_contents.begin(); |
| + it != prerender_contents.end(); |
| + ++it) { |
| + (*it)->DestroyWhenUsingTooManyResources(); |
| + } |
| + |
| + DeletePendingDeleteEntries(); |
| +} |
| + |
| +void PrerenderManager::PostCleanupTask() { |
| + DCHECK(CalledOnValidThread()); |
| + MessageLoop::current()->PostTask( |
| + FROM_HERE, |
| + base::Bind(&PrerenderManager::PeriodicCleanup, |
| + weak_factory_.GetWeakPtr())); |
| +} |
| + |
| +bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { |
| + DCHECK(CalledOnValidThread()); |
| + base::Time now = GetCurrentTime(); |
| + return (now - start < config_.max_age); |
| +} |
| + |
| +void PrerenderManager::DeleteOldEntries() { |
| + DCHECK(CalledOnValidThread()); |
| + while (!prerender_list_.empty()) { |
| + PrerenderContentsData data = prerender_list_.front(); |
| + if (IsPrerenderElementFresh(data.start_time_)) |
| + return; |
| + data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); |
| + } |
| + MaybeStopSchedulingPeriodicCleanups(); |
| +} |
| + |
| +base::Time PrerenderManager::GetCurrentTime() const { |
| + return base::Time::Now(); |
| +} |
| + |
| +base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { |
| + return base::TimeTicks::Now(); |
| +} |
| + |
| +PrerenderContents* PrerenderManager::CreatePrerenderContents( |
| + const GURL& url, |
| + const content::Referrer& referrer, |
| + Origin origin, |
| + uint8 experiment_id) { |
| + DCHECK(CalledOnValidThread()); |
| + return prerender_contents_factory_->CreatePrerenderContents( |
| + this, prerender_tracker_, profile_, url, |
| + referrer, origin, experiment_id); |
| +} |
| + |
| +bool PrerenderManager::IsPendingDelete(PrerenderContents* entry) const { |
| + DCHECK(CalledOnValidThread()); |
| + for (std::list<PrerenderContents*>::const_iterator it = |
| + pending_delete_list_.begin(); |
| + it != pending_delete_list_.end(); |
| + ++it) { |
| + if (*it == entry) |
| + return true; |
| + } |
| + |
| + return false; |
| +} |
| + |
| +void PrerenderManager::DeletePendingDeleteEntries() { |
| + while (!pending_delete_list_.empty()) { |
| + PrerenderContents* contents = pending_delete_list_.front(); |
| + pending_delete_list_.pop_front(); |
| + delete contents; |
| + } |
| +} |
| + |
| +PrerenderContents* PrerenderManager::FindEntry(const GURL& url) { |
| + DCHECK(CalledOnValidThread()); |
| + for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| + it != prerender_list_.end(); |
| + ++it) { |
| + if (it->contents_->MatchesURL(url, NULL)) |
| + return it->contents_; |
| + } |
| + // Entry not found. |
| + return NULL; |
| +} |
| + |
| +std::list<PrerenderManager::PrerenderContentsData>::iterator |
| + PrerenderManager::FindPrerenderContentsForChildRouteIdPair( |
| + const std::pair<int, int>& child_route_id_pair) { |
| + std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| + for (; it != prerender_list_.end(); ++it) { |
| + PrerenderContents* prerender_contents = it->contents_; |
| + |
| + int child_id; |
| + int route_id; |
| + bool has_child_id = prerender_contents->GetChildId(&child_id); |
| + bool has_route_id = has_child_id && |
| + prerender_contents->GetRouteId(&route_id); |
| + |
| + if (has_child_id && has_route_id && |
| + child_id == child_route_id_pair.first && |
| + route_id == child_route_id_pair.second) { |
| + break; |
| + } |
| + } |
| + return it; |
| +} |
| + |
| +bool PrerenderManager::DoesRateLimitAllowPrerender() const { |
| + DCHECK(CalledOnValidThread()); |
| + base::TimeDelta elapsed_time = |
| + GetCurrentTimeTicks() - last_prerender_start_time_; |
| + histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); |
| + if (!config_.rate_limit_enabled) |
| + return true; |
| + return elapsed_time > |
| + base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs); |
| +} |
| + |
| +void PrerenderManager::DeleteOldTabContents() { |
| + while (!old_tab_contents_list_.empty()) { |
| + TabContentsWrapper* tab_contents = old_tab_contents_list_.front(); |
| + old_tab_contents_list_.pop_front(); |
| + // TODO(dominich): should we use Instant Unload Handler here? |
| + delete tab_contents; |
| + } |
| +} |
| + |
| +void PrerenderManager::CleanUpOldNavigations() { |
| + DCHECK(CalledOnValidThread()); |
| + |
| + // Cutoff. Navigations before this cutoff can be discarded. |
| + base::TimeTicks cutoff = GetCurrentTimeTicks() - |
| + base::TimeDelta::FromMilliseconds(kNavigationRecordWindowMs); |
| + while (!navigations_.empty()) { |
| + if (navigations_.front().time_ > cutoff) |
| + break; |
| + navigations_.pop_front(); |
| + } |
| +} |
| + |
| +void PrerenderManager::ScheduleDeleteOldTabContents( |
| + TabContentsWrapper* tab, |
| + OnCloseTabContentsDeleter* deleter) { |
| + old_tab_contents_list_.push_back(tab); |
| + PostCleanupTask(); |
| + |
| + if (deleter) { |
| + ScopedVector<OnCloseTabContentsDeleter>::iterator i = std::find( |
| + on_close_tab_contents_deleters_.begin(), |
| + on_close_tab_contents_deleters_.end(), |
| + deleter); |
| + DCHECK(i != on_close_tab_contents_deleters_.end()); |
| + on_close_tab_contents_deleters_.erase(i); |
| + } |
| +} |
| + |
| +void PrerenderManager::AddToHistory(PrerenderContents* contents) { |
| + PrerenderHistory::Entry entry(contents->prerender_url(), |
| + contents->final_status(), |
| + contents->origin(), |
| + base::Time::Now()); |
| + prerender_history_->AddEntry(entry); |
| +} |
| + |
| +void PrerenderManager::RecordNavigation(const GURL& url) { |
| + DCHECK(CalledOnValidThread()); |
| + |
| + navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); |
| + CleanUpOldNavigations(); |
| +} |
| + |
| +Value* PrerenderManager::GetActivePrerendersAsValue() const { |
| + ListValue* list_value = new ListValue(); |
| + for (std::list<PrerenderContentsData>::const_iterator it = |
| + prerender_list_.begin(); |
| + it != prerender_list_.end(); |
| + ++it) { |
| + Value* prerender_value = it->contents_->GetAsValue(); |
| + if (!prerender_value) |
| + continue; |
| + list_value->Append(prerender_value); |
| + } |
| + return list_value; |
| +} |
| + |
| +void PrerenderManager::DestroyAllContents(FinalStatus final_status) { |
| + DeleteOldTabContents(); |
| + while (!prerender_list_.empty()) { |
| + PrerenderContentsData data = prerender_list_.front(); |
| + prerender_list_.pop_front(); |
| + data.contents_->Destroy(final_status); |
| + } |
| + DeletePendingDeleteEntries(); |
| } |
| PrerenderManager* FindPrerenderManagerUsingRenderProcessId( |