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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 53 | 53 |
| 54 struct PrerenderManager::PrerenderContentsData { | 54 struct PrerenderManager::PrerenderContentsData { |
| 55 PrerenderContents* contents_; | 55 PrerenderContents* contents_; |
| 56 base::Time start_time_; | 56 base::Time start_time_; |
| 57 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) | 57 PrerenderContentsData(PrerenderContents* contents, base::Time start_time) |
| 58 : contents_(contents), | 58 : contents_(contents), |
| 59 start_time_(start_time) { | 59 start_time_(start_time) { |
| 60 } | 60 } |
| 61 }; | 61 }; |
| 62 | 62 |
| 63 struct PrerenderManager::PendingContentsData { | |
| 64 PendingContentsData(const GURL& url, const std::vector<GURL>& alias_urls, | |
| 65 const GURL& referrer) | |
| 66 : url_(url), alias_urls_(alias_urls), referrer_(referrer) { } | |
| 67 ~PendingContentsData() {} | |
| 68 GURL url_; | |
| 69 std::vector<GURL> alias_urls_; | |
| 70 GURL referrer_; | |
| 71 }; | |
| 72 | |
| 73 | |
| 63 PrerenderManager::PrerenderManager(Profile* profile) | 74 PrerenderManager::PrerenderManager(Profile* profile) |
| 64 : profile_(profile), | 75 : profile_(profile), |
| 65 max_prerender_age_(base::TimeDelta::FromSeconds( | 76 max_prerender_age_(base::TimeDelta::FromSeconds( |
| 66 kDefaultMaxPrerenderAgeSeconds)), | 77 kDefaultMaxPrerenderAgeSeconds)), |
| 67 max_elements_(kDefaultMaxPrerenderElements), | 78 max_elements_(kDefaultMaxPrerenderElements), |
| 68 prerender_contents_factory_(PrerenderContents::CreateFactory()) { | 79 prerender_contents_factory_(PrerenderContents::CreateFactory()) { |
| 69 } | 80 } |
| 70 | 81 |
| 71 PrerenderManager::~PrerenderManager() { | 82 PrerenderManager::~PrerenderManager() { |
| 72 while (!prerender_list_.empty()) { | 83 while (!prerender_list_.empty()) { |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 while (prerender_list_.size() > max_elements_) { | 121 while (prerender_list_.size() > max_elements_) { |
| 111 data = prerender_list_.front(); | 122 data = prerender_list_.front(); |
| 112 prerender_list_.pop_front(); | 123 prerender_list_.pop_front(); |
| 113 data.contents_->set_final_status(FINAL_STATUS_EVICTED); | 124 data.contents_->set_final_status(FINAL_STATUS_EVICTED); |
| 114 delete data.contents_; | 125 delete data.contents_; |
| 115 } | 126 } |
| 116 StartSchedulingPeriodicCleanups(); | 127 StartSchedulingPeriodicCleanups(); |
| 117 return true; | 128 return true; |
| 118 } | 129 } |
| 119 | 130 |
| 131 void PrerenderManager::AddPendingPreload( | |
| 132 const std::pair<int,int>& child_route_id_pair, | |
| 133 const GURL& url, | |
| 134 const std::vector<GURL>& alias_urls, | |
| 135 const GURL& referrer) { | |
| 136 // Check if this is coming from a valid prerender rvh. | |
| 137 | |
| 138 bool is_valid_prerender = false; | |
| 139 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | |
| 140 it != prerender_list_.end(); ++it) { | |
| 141 PrerenderContents* pc = it->contents_; | |
| 142 | |
| 143 int child_id; | |
| 144 int route_id; | |
| 145 bool has_child_id = pc->child_id(&child_id); | |
|
cbentzel
2011/03/21 19:46:04
Probably not important, but you could do
if (pc->
dominich
2011/03/21 20:25:51
Short-circuited, but slightly differently to retai
| |
| 146 bool has_route_id = pc->route_id(&route_id); | |
| 147 | |
| 148 if (has_child_id && has_route_id && | |
| 149 child_id == child_route_id_pair.first && | |
| 150 route_id == child_route_id_pair.second) { | |
| 151 is_valid_prerender = true; | |
| 152 break; | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 // If not, we could check to see if the RenderViewHost specified by the | |
| 157 // child_route_id_pair exists and if so just start prerendering, as this | |
| 158 // suggests that the link was clicked, though this might prerender something | |
| 159 // that the user has already navigated away from. For now, we'll be | |
| 160 // conservative and skip the prerender which will mean some prerender requests | |
| 161 // from prerendered pages will be missed if the user navigates quickly. | |
| 162 if (!is_valid_prerender) { | |
| 163 RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED); | |
| 164 return; | |
| 165 } | |
| 166 | |
| 167 PendingPrerenderList::iterator it = | |
| 168 pending_prerender_list_.find(child_route_id_pair); | |
| 169 if (it == pending_prerender_list_.end()) { | |
| 170 PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair, | |
| 171 std::vector<PendingContentsData>()); | |
| 172 it = pending_prerender_list_.insert(el).first; | |
| 173 } | |
| 174 | |
| 175 it->second.push_back(PendingContentsData(url, alias_urls, referrer)); | |
| 176 } | |
| 177 | |
| 120 void PrerenderManager::DeleteOldEntries() { | 178 void PrerenderManager::DeleteOldEntries() { |
| 121 while (!prerender_list_.empty()) { | 179 while (!prerender_list_.empty()) { |
| 122 PrerenderContentsData data = prerender_list_.front(); | 180 PrerenderContentsData data = prerender_list_.front(); |
| 123 if (IsPrerenderElementFresh(data.start_time_)) | 181 if (IsPrerenderElementFresh(data.start_time_)) |
| 124 return; | 182 return; |
| 125 prerender_list_.pop_front(); | 183 prerender_list_.pop_front(); |
| 126 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); | 184 data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT); |
| 127 delete data.contents_; | 185 delete data.contents_; |
| 128 } | 186 } |
| 129 if (prerender_list_.empty()) | 187 if (prerender_list_.empty()) |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 157 // be showing a prerendered contents, but otherwise, don't do anything. | 215 // be showing a prerendered contents, but otherwise, don't do anything. |
| 158 if (!pc->prerendering_has_started()) { | 216 if (!pc->prerendering_has_started()) { |
| 159 MarkTabContentsAsWouldBePrerendered(tc); | 217 MarkTabContentsAsWouldBePrerendered(tc); |
| 160 return false; | 218 return false; |
| 161 } | 219 } |
| 162 | 220 |
| 163 if (!pc->load_start_time().is_null()) | 221 if (!pc->load_start_time().is_null()) |
| 164 RecordTimeUntilUsed(base::TimeTicks::Now() - pc->load_start_time()); | 222 RecordTimeUntilUsed(base::TimeTicks::Now() - pc->load_start_time()); |
| 165 pc->set_final_status(FINAL_STATUS_USED); | 223 pc->set_final_status(FINAL_STATUS_USED); |
| 166 | 224 |
| 225 int child_id; | |
| 226 int route_id; | |
| 227 CHECK(pc->child_id(&child_id)); | |
|
cbentzel
2011/03/21 19:46:04
CHECK is probably OK here, although I'd hate to cr
dominich
2011/03/21 20:25:51
I considered that, but I wasn't sure what an inval
mmenke
2011/03/21 21:18:57
I've seen -1 used to check for invalid elsewhere,
| |
| 228 CHECK(pc->route_id(&route_id)); | |
| 229 | |
| 167 RenderViewHost* rvh = pc->render_view_host(); | 230 RenderViewHost* rvh = pc->render_view_host(); |
| 168 // RenderViewHosts in PrerenderContents start out hidden. | 231 // RenderViewHosts in PrerenderContents start out hidden. |
| 169 // Since we are actually using it now, restore it. | 232 // Since we are actually using it now, restore it. |
| 170 rvh->WasRestored(); | 233 rvh->WasRestored(); |
| 171 pc->set_render_view_host(NULL); | 234 pc->set_render_view_host(NULL); |
| 172 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); | 235 rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id())); |
| 173 tc->SwapInRenderViewHost(rvh); | 236 tc->SwapInRenderViewHost(rvh); |
| 174 MarkTabContentsAsPrerendered(tc); | 237 MarkTabContentsAsPrerendered(tc); |
| 175 | 238 |
| 239 // See if we have any pending prerender requests for this routing id and start | |
| 240 // the preload if we do. | |
| 241 std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id); | |
| 242 PendingPrerenderList::iterator pending_it = | |
| 243 pending_prerender_list_.find(child_route_pair); | |
| 244 if (pending_it != pending_prerender_list_.end()) { | |
| 245 for (std::vector<PendingContentsData>::iterator content_it = | |
| 246 pending_it->second.begin(); | |
| 247 content_it != pending_it->second.end(); ++content_it) { | |
| 248 AddPreload(content_it->url_, content_it->alias_urls_, | |
| 249 content_it->referrer_); | |
| 250 } | |
| 251 pending_prerender_list_.erase(pending_it); | |
| 252 } | |
| 253 | |
| 176 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params(); | 254 ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params(); |
| 177 if (p != NULL) | 255 if (p != NULL) |
| 178 tc->DidNavigate(rvh, *p); | 256 tc->DidNavigate(rvh, *p); |
| 179 | 257 |
| 180 string16 title = pc->title(); | 258 string16 title = pc->title(); |
| 181 if (!title.empty()) | 259 if (!title.empty()) |
| 182 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title)); | 260 tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title)); |
| 183 | 261 |
| 184 GURL icon_url = pc->icon_url(); | 262 GURL icon_url = pc->icon_url(); |
| 185 if (!icon_url.is_empty()) | 263 if (!icon_url.is_empty()) |
| 186 tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), icon_url); | 264 tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), icon_url); |
| 187 | 265 |
| 188 if (pc->has_stopped_loading()) | 266 if (pc->has_stopped_loading()) |
| 189 tc->DidStopLoading(); | 267 tc->DidStopLoading(); |
| 190 | 268 |
| 191 return true; | 269 return true; |
| 192 } | 270 } |
| 193 | 271 |
| 194 void PrerenderManager::RemoveEntry(PrerenderContents* entry) { | 272 void PrerenderManager::RemoveEntry(PrerenderContents* entry) { |
| 195 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 273 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 196 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | 274 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| 197 it != prerender_list_.end(); | 275 it != prerender_list_.end(); |
| 198 ++it) { | 276 ++it) { |
| 199 if (it->contents_ == entry) { | 277 if (it->contents_ == entry) { |
| 278 RemovePendingPreload(entry); | |
| 200 prerender_list_.erase(it); | 279 prerender_list_.erase(it); |
| 201 break; | 280 break; |
| 202 } | 281 } |
| 203 } | 282 } |
| 204 DeleteOldEntries(); | 283 DeleteOldEntries(); |
| 205 } | 284 } |
| 206 | 285 |
| 207 base::Time PrerenderManager::GetCurrentTime() const { | 286 base::Time PrerenderManager::GetCurrentTime() const { |
| 208 return base::Time::Now(); | 287 return base::Time::Now(); |
| 209 } | 288 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); | 352 for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin(); |
| 274 it != prerender_list_.end(); | 353 it != prerender_list_.end(); |
| 275 ++it) { | 354 ++it) { |
| 276 if (it->contents_->MatchesURL(url)) | 355 if (it->contents_->MatchesURL(url)) |
| 277 return it->contents_; | 356 return it->contents_; |
| 278 } | 357 } |
| 279 // Entry not found. | 358 // Entry not found. |
| 280 return NULL; | 359 return NULL; |
| 281 } | 360 } |
| 282 | 361 |
| 362 PrerenderManager::PendingContentsData* | |
| 363 PrerenderManager::FindPendingEntry(const GURL& url) { | |
| 364 for (PendingPrerenderList::iterator map_it = pending_prerender_list_.begin(); | |
| 365 map_it != pending_prerender_list_.end(); | |
| 366 ++map_it) { | |
| 367 for (std::vector<PendingContentsData>::iterator content_it = | |
| 368 map_it->second.begin(); | |
| 369 content_it != map_it->second.end(); | |
| 370 ++content_it) { | |
| 371 if (content_it->url_ == url) { | |
| 372 return &(*content_it); | |
| 373 } | |
| 374 } | |
| 375 } | |
| 376 | |
| 377 return NULL; | |
| 378 } | |
| 379 | |
| 283 // static | 380 // static |
| 284 void PrerenderManager::RecordPrefetchTagObserved() { | 381 void PrerenderManager::RecordPrefetchTagObserved() { |
| 285 // Ensure that we are in the UI thread, and post to the UI thread if | 382 // Ensure that we are in the UI thread, and post to the UI thread if |
| 286 // necessary. | 383 // necessary. |
| 287 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { | 384 if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { |
| 288 BrowserThread::PostTask( | 385 BrowserThread::PostTask( |
| 289 BrowserThread::UI, | 386 BrowserThread::UI, |
| 290 FROM_HERE, | 387 FROM_HERE, |
| 291 NewRunnableFunction( | 388 NewRunnableFunction( |
| 292 &PrerenderManager::RecordPrefetchTagObservedOnUIThread)); | 389 &PrerenderManager::RecordPrefetchTagObservedOnUIThread)); |
| 293 } else { | 390 } else { |
| 294 RecordPrefetchTagObservedOnUIThread(); | 391 RecordPrefetchTagObservedOnUIThread(); |
| 295 } | 392 } |
| 296 } | 393 } |
| 297 | 394 |
| 298 // static | 395 // static |
| 299 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() { | 396 void PrerenderManager::RecordPrefetchTagObservedOnUIThread() { |
| 300 // Once we get here, we have to be on the UI thread. | 397 // Once we get here, we have to be on the UI thread. |
| 301 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 398 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 302 | 399 |
| 303 // If we observe multiple tags within the 30 second window, we will still | 400 // If we observe multiple tags within the 30 second window, we will still |
| 304 // reset the window to begin at the most recent occurrence, so that we will | 401 // reset the window to begin at the most recent occurrence, so that we will |
| 305 // always be in a window in the 30 seconds from each occurrence. | 402 // always be in a window in the 30 seconds from each occurrence. |
| 306 last_prefetch_seen_time_ = base::TimeTicks::Now(); | 403 last_prefetch_seen_time_ = base::TimeTicks::Now(); |
| 307 } | 404 } |
| 308 | 405 |
| 406 void PrerenderManager::RemovePendingPreload(PrerenderContents* entry) { | |
| 407 RenderViewHost* rvh = entry->render_view_host(); | |
|
cbentzel
2011/03/21 19:46:04
You could remove the rvh here, remove the CHECK's
dominich
2011/03/21 20:25:51
Done.
| |
| 408 | |
| 409 // If the entry doesn't have a RenderViewHost then it didn't start | |
| 410 // prerendering and there shouldn't be any pending preloads to remove. | |
| 411 if (rvh == NULL) | |
| 412 return; | |
| 413 | |
| 414 int child_id; | |
| 415 int route_id; | |
| 416 CHECK(entry->child_id(&child_id)); | |
| 417 CHECK(entry->route_id(&route_id)); | |
| 418 | |
| 419 std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id); | |
| 420 pending_prerender_list_.erase(child_route_pair); | |
| 421 } | |
| 422 | |
| 309 // static | 423 // static |
| 310 bool PrerenderManager::ShouldRecordWindowedPPLT() { | 424 bool PrerenderManager::ShouldRecordWindowedPPLT() { |
| 311 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 312 if (last_prefetch_seen_time_.is_null()) | 426 if (last_prefetch_seen_time_.is_null()) |
| 313 return false; | 427 return false; |
| 314 base::TimeDelta elapsed_time = | 428 base::TimeDelta elapsed_time = |
| 315 base::TimeTicks::Now() - last_prefetch_seen_time_; | 429 base::TimeTicks::Now() - last_prefetch_seen_time_; |
| 316 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); | 430 return elapsed_time <= base::TimeDelta::FromSeconds(kWindowedPPLTSeconds); |
| 317 } | 431 } |
| 318 | 432 |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 362 | 476 |
| 363 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { | 477 bool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const { |
| 364 return prerendered_tc_set_.count(tc) > 0; | 478 return prerendered_tc_set_.count(tc) > 0; |
| 365 } | 479 } |
| 366 | 480 |
| 367 bool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const { | 481 bool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const { |
| 368 return would_be_prerendered_tc_set_.count(tc) > 0; | 482 return would_be_prerendered_tc_set_.count(tc) > 0; |
| 369 } | 483 } |
| 370 | 484 |
| 371 } // namespace prerender | 485 } // namespace prerender |
| OLD | NEW |