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( |