Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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 "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "base/time.h" | 9 #include "base/time.h" |
| 10 #include "base/utf_string_conversions.h" | 10 #include "base/utf_string_conversions.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 46 | 46 |
| 47 struct PrerenderManager::PrerenderContentsData { | 47 struct PrerenderManager::PrerenderContentsData { |
| 48 PrerenderContents* contents_; | 48 PrerenderContents* contents_; |
| 49 base::Time start_time_; | 49 base::Time start_time_; |
| 50 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) | 50 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) |
| 51 : contents_(contents), | 51 : contents_(contents), |
| 52 start_time_(start_time) { | 52 start_time_(start_time) { |
| 53 } | 53 } |
| 54 }; | 54 }; |
| 55 | 55 |
| 56 struct PrerenderManager::PendingContentsData { | |
| 57 PendingContentsData(const GURL& url, const std::vector<GURL>& alias_urls, | |
| 58 const GURL& referrer) | |
| 59 : url_(url), alias_urls_(alias_urls), referrer_(referrer) { } | |
| 60 ~PendingContentsData() {} | |
| 61 GURL url_; | |
| 62 std::vector<GURL> alias_urls_; | |
| 63 GURL referrer_; | |
| 64 }; | |
| 65 | |
| 66 | |
| 56 PrerenderManager::PrerenderManager(Profile* profile) | 67 PrerenderManager::PrerenderManager(Profile* profile) |
| 57 : profile_(profile), | 68 : profile_(profile), |
| 58 max_prerender_age_(base::TimeDelta::FromSeconds( | 69 max_prerender_age_(base::TimeDelta::FromSeconds( |
| 59 kDefaultMaxPrerenderAgeSeconds)), | 70 kDefaultMaxPrerenderAgeSeconds)), |
| 60 max_elements_(kDefaultMaxPrerenderElements), | 71 max_elements_(kDefaultMaxPrerenderElements), |
| 61 prerender_contents_factory_(PrerenderContents::CreateFactory()) { | 72 prerender_contents_factory_(PrerenderContents::CreateFactory()) { |
| 62 } | 73 } |
| 63 | 74 |
| 64 PrerenderManager::~PrerenderManager() { | 75 PrerenderManager::~PrerenderManager() { |
| 65 while (!prerender_list_.empty()) { | 76 while (!prerender_list_.empty()) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 100 while (prerender_list_.size() > max_elements_) { | 111 while (prerender_list_.size() > max_elements_) { |
| 101 data = prerender_list_.front(); | 112 data = prerender_list_.front(); |
| 102 prerender_list_.pop_front(); | 113 prerender_list_.pop_front(); |
| 103 data.contents_->set_final_status(FINAL_STATUS_EVICTED); | 114 data.contents_->set_final_status(FINAL_STATUS_EVICTED); |
| 104 delete data.contents_; | 115 delete data.contents_; |
| 105 } | 116 } |
| 106 StartSchedulingPeriodicCleanups(); | 117 StartSchedulingPeriodicCleanups(); |
| 107 return true; | 118 return true; |
| 108 } | 119 } |
| 109 | 120 |
| 121 void PrerenderManager::AddPendingPreload( | |
| 122 const std::pair<int,int>& child_route_id_pair, | |
| 123 const GURL& url, | |
| 124 const std::vector<GURL>& alias_urls, | |
| 125 const GURL& referrer) { | |
| 126 // Check if this is coming from a valid prerender rvh. | |
| 127 bool is_valid_prerender = false; | |
| 128 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
| 129 it != prerender_list_.end(); ++it) { | |
|
cbentzel
2011/03/18 18:35:43
This is a pretty subtle case. Could you add a test
dominich
2011/03/21 16:36:11
Done.
| |
| 130 PrerenderContents* pc = it->contents_; | |
| 131 const RenderViewHost* rvh = pc->render_view_host(); | |
| 132 if (rvh && | |
| 133 rvh->process() && | |
|
cbentzel
2011/03/18 18:35:43
You don't check for process() in RemovePendingPrel
dominich
2011/03/21 16:36:11
Actually no - I checked that when I wrote RemovePe
| |
| 134 rvh->process()->id() == child_route_id_pair.first && | |
| 135 rvh->routing_id() == child_route_id_pair.second) { | |
| 136 is_valid_prerender = true; | |
| 137 break; | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 // If not, we could check to see if the RenderViewHost specified by the | |
| 142 // child_route_id_pair exists and if so just start prerendering, as this | |
| 143 // suggests that the link was clicked, though this might prerender something | |
| 144 // that the user has already navigated away from. For now, we'll be | |
| 145 // conservative and skip the prerender which will mean some prerender requests | |
| 146 // from prerendered pages will be missed if the user navigates quickly. | |
|
cbentzel
2011/03/18 18:35:43
Should you add a FINAL_STATUS entry here? This is
dominich
2011/03/21 16:36:11
I thought about it, but we're not creating the pre
| |
| 147 if (!is_valid_prerender) | |
|
cbentzel
2011/03/18 18:35:43
Thanks for the comment here.
| |
| 148 return; | |
| 149 | |
| 150 PendingPrerenderList::iterator it = | |
| 151 pending_prerender_list_.find(child_route_id_pair); | |
| 152 if (it == pending_prerender_list_.end()) { | |
| 153 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair, | |
| 154 std::vector<PendingContentsData>()); | |
| 155 it = pending_prerender_list_.insert(el).first; | |
| 156 } | |
| 157 | |
| 158 it->second.push_back(PendingContentsData(url, alias_urls, referrer)); | |
| 159 } | |
| 160 | |
| 110 void PrerenderManager::DeleteOldEntries() { | 161 void PrerenderManager::DeleteOldEntries() { |
| 111 while (!prerender_list_.empty()) { | 162 while (!prerender_list_.empty()) { |
| 112 PrerenderContentsData data = prerender_list_.front(); | 163 PrerenderContentsData data = prerender_list_.front(); |
| 113 if (IsPrerenderElementFresh(data.start_time_)) | 164 if (IsPrerenderElementFresh(data.start_time_)) |
| 114 return; | 165 return; |
| 115 prerender_list_.pop_front(); | 166 prerender_list_.pop_front(); |
| 116 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); | 167 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); |
| 117 delete data.contents_; | 168 delete data.contents_; |
| 118 } | 169 } |
| 119 if (prerender_list_.empty()) | 170 if (prerender_list_.empty()) |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 148 | 199 |
| 149 RenderViewHost* rvh = pc->render_view_host(); | 200 RenderViewHost* rvh = pc->render_view_host(); |
| 150 // RenderViewHosts in PrerenderContents start out hidden. | 201 // RenderViewHosts in PrerenderContents start out hidden. |
| 151 // Since we are actually using it now, restore it. | 202 // Since we are actually using it now, restore it. |
| 152 rvh->WasRestored(); | 203 rvh->WasRestored(); |
| 153 pc->set_render_view_host(NULL); | 204 pc->set_render_view_host(NULL); |
| 154 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); | 205 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); |
| 155 tc->SwapInRenderViewHost(rvh); | 206 tc->SwapInRenderViewHost(rvh); |
| 156 MarkTabContentsAsPrerendered(tc); | 207 MarkTabContentsAsPrerendered(tc); |
| 157 | 208 |
| 209 // See if we have any pending prerender requests for this routing id and start | |
| 210 // the preload if we do. | |
| 211 std::pair<int, int> child_route_pair = std::make_pair(rvh->process()->id(), | |
| 212 rvh->routing_id()); | |
| 213 PendingPrerenderList::iterator pending_it = | |
| 214 pending_prerender_list_.find(child_route_pair); | |
| 215 if (pending_it != pending_prerender_list_.end()) { | |
| 216 for (std::vector<PendingContentsData>::iterator content_it = | |
| 217 pending_it->second.begin(); | |
| 218 content_it != pending_it->second.end(); ++content_it) { | |
| 219 AddPreload(content_it->url_, content_it->alias_urls_, | |
| 220 content_it->referrer_); | |
| 221 } | |
| 222 pending_prerender_list_.erase(pending_it); | |
| 223 } | |
| 224 | |
| 158 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params(); | 225 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params(); |
| 159 if (p != NULL) | 226 if (p != NULL) |
| 160 tc->DidNavigate(rvh, *p); | 227 tc->DidNavigate(rvh, *p); |
| 161 | 228 |
| 162 string16 title = pc->title(); | 229 string16 title = pc->title(); |
| 163 if (!title.empty()) | 230 if (!title.empty()) |
| 164 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title)); | 231 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title)); |
| 165 | 232 |
| 166 GURL icon_url = pc->icon_url(); | 233 GURL icon_url = pc->icon_url(); |
| 167 if (!icon_url.is_empty()) | 234 if (!icon_url.is_empty()) |
| 168 tc->fav_icon_helper().OnUpdateFavIconURL(pc->page_id(), icon_url); | 235 tc->fav_icon_helper().OnUpdateFavIconURL(pc->page_id(), icon_url); |
| 169 | 236 |
| 170 if (pc->has_stopped_loading()) | 237 if (pc->has_stopped_loading()) |
| 171 tc->DidStopLoading(); | 238 tc->DidStopLoading(); |
| 172 | 239 |
| 173 return true; | 240 return true; |
| 174 } | 241 } |
| 175 | 242 |
| 176 void PrerenderManager::RemoveEntry(PrerenderContents* entry) { | 243 void PrerenderManager::RemoveEntry(PrerenderContents* entry) { |
| 177 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 244 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 178 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | 245 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| 179 it != prerender_list_.end(); | 246 it != prerender_list_.end(); |
| 180 ++it) { | 247 ++it) { |
| 181 if (it->contents_ == entry) { | 248 if (it->contents_ == entry) { |
| 249 RemovePendingPreload(entry); | |
| 182 prerender_list_.erase(it); | 250 prerender_list_.erase(it); |
| 183 break; | 251 break; |
| 184 } | 252 } |
| 185 } | 253 } |
| 186 DeleteOldEntries(); | 254 DeleteOldEntries(); |
| 187 } | 255 } |
| 188 | 256 |
| 189 base::Time PrerenderManager::GetCurrentTime() const { | 257 base::Time PrerenderManager::GetCurrentTime() const { |
| 190 return base::Time::Now(); | 258 return base::Time::Now(); |
| 191 } | 259 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 234 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | 302 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| 235 it != prerender_list_.end(); | 303 it != prerender_list_.end(); |
| 236 ++it) { | 304 ++it) { |
| 237 if (it->contents_->MatchesURL(url)) | 305 if (it->contents_->MatchesURL(url)) |
| 238 return it->contents_; | 306 return it->contents_; |
| 239 } | 307 } |
| 240 // Entry not found. | 308 // Entry not found. |
| 241 return NULL; | 309 return NULL; |
| 242 } | 310 } |
| 243 | 311 |
| 312 PrerenderManager::PendingContentsData* | |
| 313 PrerenderManager::FindPendingEntry(const GURL& url) { | |
| 314 for (PendingPrerenderList::iterator map_it = pending_prerender_list_.begin(); | |
| 315 map_it != pending_prerender_list_.end(); | |
| 316 ++map_it) { | |
| 317 for (std::vector<PendingContentsData>::iterator content_it = | |
| 318 map_it->second.begin(); | |
| 319 content_it != map_it->second.end(); | |
| 320 ++content_it) { | |
| 321 if (content_it->url_ == url) | |
| 322 return &(*content_it); | |
| 323 } | |
| 324 } | |
| 325 | |
| 326 return NULL; | |
| 327 } | |
| 328 | |
| 244 // static | 329 // static |
| 245 void PrerenderManager::RecordPrefetchTagObserved() { | 330 void PrerenderManager::RecordPrefetchTagObserved() { |
| 246 // Ensure that we are in the UI thread, and post to the UI thread if | 331 // Ensure that we are in the UI thread, and post to the UI thread if |
| 247 // necessary. | 332 // necessary. |
| 248 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 333 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 249 BrowserThread::PostTask( | 334 BrowserThread::PostTask( |
| 250 BrowserThread::UI, | 335 BrowserThread::UI, |
| 251 FROM_HERE, | 336 FROM_HERE, |
| 252 NewRunnableFunction( | 337 NewRunnableFunction( |
| 253 &PrerenderManager::RecordPrefetchTagObservedOnUIThread)); | 338 &PrerenderManager::RecordPrefetchTagObservedOnUIThread)); |
| 254 } else { | 339 } else { |
| 255 RecordPrefetchTagObservedOnUIThread(); | 340 RecordPrefetchTagObservedOnUIThread(); |
| 256 } | 341 } |
| 257 } | 342 } |
| 258 | 343 |
| 259 // static | 344 // static |
| 260 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() { | 345 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() { |
| 261 // Once we get here, we have to be on the UI thread. | 346 // Once we get here, we have to be on the UI thread. |
| 262 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 347 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 263 | 348 |
| 264 // If we observe multiple tags within the 30 second window, we will still | 349 // If we observe multiple tags within the 30 second window, we will still |
| 265 // reset the window to begin at the most recent occurrence, so that we will | 350 // reset the window to begin at the most recent occurrence, so that we will |
| 266 // always be in a window in the 30 seconds from each occurrence. | 351 // always be in a window in the 30 seconds from each occurrence. |
| 267 last_prefetch_seen_time_ = base::TimeTicks::Now(); | 352 last_prefetch_seen_time_ = base::TimeTicks::Now(); |
| 268 } | 353 } |
| 269 | 354 |
| 355 void PrerenderManager::RemovePendingPreload(PrerenderContents* entry) { | |
|
cbentzel
2011/03/18 18:35:43
can |entry| be const?
dominich
2011/03/21 16:36:11
no - render_view_host() is not const.
Is there pr
| |
| 356 RenderViewHost* rvh = entry->render_view_host(); | |
| 357 | |
| 358 // If the entry doesn't have a RenderViewHost then it didn't start | |
| 359 // prerendering and there shouldn't be any pending preloads to remove. | |
| 360 if (rvh == NULL) | |
| 361 return; | |
| 362 | |
| 363 std::pair<int, int> child_route_pair = std::make_pair(rvh->process()->id(), | |
| 364 rvh->routing_id()); | |
| 365 pending_prerender_list_.erase(child_route_pair); | |
| 366 } | |
| 367 | |
| 270 // static | 368 // static |
| 271 bool PrerenderManager::ShouldRecordWindowedPPLT() { | 369 bool PrerenderManager::ShouldRecordWindowedPPLT() { |
| 272 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 273 if (last_prefetch_seen_time_.is_null()) | 371 if (last_prefetch_seen_time_.is_null()) |
| 274 return false; | 372 return false; |
| 275 base::TimeDelta elapsed_time = | 373 base::TimeDelta elapsed_time = |
| 276 base::TimeTicks::Now() - last_prefetch_seen_time_; | 374 base::TimeTicks::Now() - last_prefetch_seen_time_; |
| 277 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); | 375 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); |
| 278 } | 376 } |
| 279 | 377 |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 314 | 412 |
| 315 void PrerenderManager::MarkTabContentsAsNotPrerendered(TabContents* tc) { | 413 void PrerenderManager::MarkTabContentsAsNotPrerendered(TabContents* tc) { |
| 316 prerendered_tc_set_.erase(tc); | 414 prerendered_tc_set_.erase(tc); |
| 317 } | 415 } |
| 318 | 416 |
| 319 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { | 417 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { |
| 320 return prerendered_tc_set_.count(tc) > 0; | 418 return prerendered_tc_set_.count(tc) > 0; |
| 321 } | 419 } |
| 322 | 420 |
| 323 } // namespace prerender | 421 } // namespace prerender |
| OLD | NEW |