Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Side by Side Diff: chrome/browser/prerender/prerender_manager.cc

Issue 10553029: Handle interface to prerenders. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: unconfusify ownership of pending prerenders Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/prerender/prerender_manager.h" 5 #include "chrome/browser/prerender/prerender_manager.h"
6 6
7 #include <set> 7 #include <algorithm>
8 #include <functional>
8 #include <string> 9 #include <string>
9 #include <vector> 10 #include <vector>
10 11
11 #include "base/bind.h" 12 #include "base/bind.h"
12 #include "base/bind_helpers.h" 13 #include "base/bind_helpers.h"
13 #include "base/logging.h" 14 #include "base/logging.h"
14 #include "base/memory/weak_ptr.h" 15 #include "base/memory/weak_ptr.h"
15 #include "base/metrics/histogram.h" 16 #include "base/metrics/histogram.h"
16 #include "base/stl_util.h" 17 #include "base/stl_util.h"
17 #include "base/time.h" 18 #include "base/time.h"
18 #include "base/utf_string_conversions.h" 19 #include "base/utf_string_conversions.h"
19 #include "base/values.h" 20 #include "base/values.h"
20 #include "chrome/browser/browser_process.h" 21 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/cancelable_request.h" 22 #include "chrome/browser/cancelable_request.h"
22 #include "chrome/browser/favicon/favicon_tab_helper.h" 23 #include "chrome/browser/favicon/favicon_tab_helper.h"
23 #include "chrome/browser/prerender/prerender_condition.h" 24 #include "chrome/browser/prerender/prerender_condition.h"
24 #include "chrome/browser/prerender/prerender_contents.h" 25 #include "chrome/browser/prerender/prerender_contents.h"
25 #include "chrome/browser/prerender/prerender_field_trial.h" 26 #include "chrome/browser/prerender/prerender_field_trial.h"
26 #include "chrome/browser/prerender/prerender_final_status.h" 27 #include "chrome/browser/prerender/prerender_final_status.h"
28 #include "chrome/browser/prerender/prerender_handle.h"
27 #include "chrome/browser/prerender/prerender_histograms.h" 29 #include "chrome/browser/prerender/prerender_histograms.h"
28 #include "chrome/browser/prerender/prerender_history.h" 30 #include "chrome/browser/prerender/prerender_history.h"
29 #include "chrome/browser/prerender/prerender_local_predictor.h" 31 #include "chrome/browser/prerender/prerender_local_predictor.h"
30 #include "chrome/browser/prerender/prerender_manager_factory.h" 32 #include "chrome/browser/prerender/prerender_manager_factory.h"
31 #include "chrome/browser/prerender/prerender_tab_helper.h" 33 #include "chrome/browser/prerender/prerender_tab_helper.h"
32 #include "chrome/browser/prerender/prerender_tracker.h" 34 #include "chrome/browser/prerender/prerender_tracker.h"
33 #include "chrome/browser/prerender/prerender_util.h" 35 #include "chrome/browser/prerender/prerender_util.h"
34 #include "chrome/browser/profiles/profile.h" 36 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" 37 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
36 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" 38 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
99 // This ensures that there is no bias in terms of the page load times 101 // This ensures that there is no bias in terms of the page load times
100 // of the pages forming the difference between the two sets. 102 // of the pages forming the difference between the two sets.
101 103
102 bool NeedMatchCompleteDummyForFinalStatus(FinalStatus final_status) { 104 bool NeedMatchCompleteDummyForFinalStatus(FinalStatus final_status) {
103 return final_status != FINAL_STATUS_USED && 105 return final_status != FINAL_STATUS_USED &&
104 final_status != FINAL_STATUS_TIMED_OUT && 106 final_status != FINAL_STATUS_TIMED_OUT &&
105 final_status != FINAL_STATUS_EVICTED && 107 final_status != FINAL_STATUS_EVICTED &&
106 final_status != FINAL_STATUS_MANAGER_SHUTDOWN && 108 final_status != FINAL_STATUS_MANAGER_SHUTDOWN &&
107 final_status != FINAL_STATUS_APP_TERMINATING && 109 final_status != FINAL_STATUS_APP_TERMINATING &&
108 final_status != FINAL_STATUS_WINDOW_OPENER && 110 final_status != FINAL_STATUS_WINDOW_OPENER &&
109 final_status != FINAL_STATUS_FRAGMENT_MISMATCH &&
110 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED && 111 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED &&
111 final_status != FINAL_STATUS_CANCELLED && 112 final_status != FINAL_STATUS_CANCELLED &&
112 final_status != FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH &&
113 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED && 113 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED &&
114 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING; 114 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING;
115 } 115 }
116 116
117 } // namespace 117 } // namespace
118 118
119 class PrerenderManager::OnCloseTabContentsDeleter 119 class PrerenderManager::OnCloseTabContentsDeleter
120 : public content::WebContentsDelegate, 120 : public content::WebContentsDelegate,
121 public base::SupportsWeakPtr< 121 public base::SupportsWeakPtr<
122 PrerenderManager::OnCloseTabContentsDeleter> { 122 PrerenderManager::OnCloseTabContentsDeleter> {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
164 // static 164 // static
165 bool PrerenderManager::is_prefetch_enabled_ = false; 165 bool PrerenderManager::is_prefetch_enabled_ = false;
166 166
167 // static 167 // static
168 int PrerenderManager::prerenders_per_session_count_ = 0; 168 int PrerenderManager::prerenders_per_session_count_ = 0;
169 169
170 // static 170 // static
171 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = 171 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ =
172 PRERENDER_MODE_ENABLED; 172 PRERENDER_MODE_ENABLED;
173 173
174 struct PrerenderManager::PrerenderContentsData {
175 PrerenderContents* contents_;
176 base::Time start_time_;
177 int active_count_;
178 PrerenderContentsData(PrerenderContents* contents, base::Time start_time)
179 : contents_(contents),
180 start_time_(start_time),
181 active_count_(1) {
182 CHECK(contents);
183 }
184 };
185
186 struct PrerenderManager::NavigationRecord { 174 struct PrerenderManager::NavigationRecord {
187 GURL url_; 175 GURL url_;
188 base::TimeTicks time_; 176 base::TimeTicks time_;
189 NavigationRecord(const GURL& url, base::TimeTicks time) 177 NavigationRecord(const GURL& url, base::TimeTicks time)
190 : url_(url), 178 : url_(url),
191 time_(time) { 179 time_(time) {
192 } 180 }
193 }; 181 };
194 182
195 PrerenderManager::PrerenderManager(Profile* profile, 183 PrerenderManager::PrerenderManager(Profile* profile,
196 PrerenderTracker* prerender_tracker) 184 PrerenderTracker* prerender_tracker)
197 : enabled_(true), 185 : enabled_(true),
198 profile_(profile), 186 profile_(profile),
199 prerender_tracker_(prerender_tracker), 187 prerender_tracker_(prerender_tracker),
200 prerender_contents_factory_(PrerenderContents::CreateFactory()), 188 prerender_contents_factory_(PrerenderContents::CreateFactory()),
201 last_prerender_start_time_(GetCurrentTimeTicks() - 189 last_prerender_start_time_(GetCurrentTimeTicks() -
202 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)), 190 base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)),
203 weak_factory_(this), 191 weak_factory_(this),
204 prerender_history_(new PrerenderHistory(kHistoryLength)), 192 prerender_history_(new PrerenderHistory(kHistoryLength)),
205 histograms_(new PrerenderHistograms()), 193 histograms_(new PrerenderHistograms()),
206 local_predictor_(new PrerenderLocalPredictor(this)) { 194 local_predictor_(new PrerenderLocalPredictor(this)) {
207 // There are some assumptions that the PrerenderManager is on the UI thread. 195 // There are some assumptions that the PrerenderManager is on the UI thread.
208 // Any other checks simply make sure that the PrerenderManager is accessed on 196 // Any other checks simply make sure that the PrerenderManager is accessed on
209 // the same thread that it was created on. 197 // the same thread that it was created on.
210 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
211 } 199 }
212 200
213 PrerenderManager::~PrerenderManager() { 201 PrerenderManager::~PrerenderManager() {
mmenke 2012/07/12 17:23:21 If we can ensure PrerenderLinkManager is destroyed
214 } 202 }
215 203
216 void PrerenderManager::Shutdown() { 204 void PrerenderManager::Shutdown() {
217 DoShutdown(); 205 DoShutdown();
218 } 206 }
219 207
220 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( 208 PrerenderHandle* PrerenderManager::AddPrerenderFromLinkRelPrerender(
221 int process_id, 209 int process_id,
222 int route_id, 210 int route_id,
223 const GURL& url, 211 const GURL& url,
224 const content::Referrer& referrer, 212 const content::Referrer& referrer,
225 gfx::Size size) { 213 const gfx::Size& size) {
226 #if defined(OS_ANDROID) 214 #if defined(OS_ANDROID)
227 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable 215 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable
228 // link-prerender and enable omnibox-prerender only. 216 // link-prerender and enable omnibox-prerender only.
229 return false; 217 return false;
230 #else 218 #else
231 std::pair<int, int> child_route_id_pair(process_id, route_id); 219 DCHECK(!size.IsEmpty());
232 PrerenderContentsDataList::iterator it = 220 if (PrerenderData* parent_prerender_data =
233 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair); 221 FindPrerenderDataForChildAndRoute(process_id, route_id)) {
234 if (it != prerender_list_.end()) {
235 // Instead of prerendering from inside of a running prerender, we will defer 222 // Instead of prerendering from inside of a running prerender, we will defer
236 // this request until its launcher is made visible. 223 // this request until its launcher is made visible.
237 it->contents_->AddPendingPrerender(url, referrer, size); 224 if (PrerenderContents* contents = parent_prerender_data->contents_) {
238 return true; 225 pending_prerender_list_.push_back(
226 linked_ptr<PrerenderData>(new PrerenderData(this)));
227 PrerenderHandle* prerender_handle =
228 new PrerenderHandle(pending_prerender_list_.back().get());
229 contents->AddPendingPrerender(
230 prerender_handle->weak_ptr_factory_.GetWeakPtr(),
231 url, referrer, size);
232 return prerender_handle;
233 }
239 } 234 }
240 235
241 // Unit tests pass in a process_id == -1. 236 // Unit tests pass in a process_id == -1.
242 SessionStorageNamespace* session_storage_namespace = NULL; 237 SessionStorageNamespace* session_storage_namespace = NULL;
243 if (process_id != -1) { 238 if (process_id != -1) {
244 RenderViewHost* source_render_view_host = 239 RenderViewHost* source_render_view_host =
245 RenderViewHost::FromID(process_id, route_id); 240 RenderViewHost::FromID(process_id, route_id);
246 if (!source_render_view_host || !source_render_view_host->GetView()) 241 if (!source_render_view_host)
247 return false; 242 return NULL;
248 session_storage_namespace = 243 session_storage_namespace =
249 source_render_view_host->GetSessionStorageNamespace(); 244 source_render_view_host->GetSessionStorageNamespace();
250
251 if (size.IsEmpty()) {
252 // Use the size of the tab requesting the prerendering.
253 WebContents* web_contents =
254 WebContents::FromRenderViewHost(source_render_view_host);
255 if (web_contents && web_contents->GetView()) {
256 gfx::Rect container_bounds;
257 web_contents->GetView()->GetContainerBounds(&container_bounds);
258 size = container_bounds.size();
259 }
260 }
261 } 245 }
262 246
263 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, 247 return AddPrerender(ORIGIN_LINK_REL_PRERENDER,
264 process_id, url, referrer, size, 248 process_id, url, referrer, size,
265 session_storage_namespace); 249 session_storage_namespace);
266 #endif 250 #endif
267 } 251 }
268 252
269 bool PrerenderManager::AddPrerenderFromOmnibox( 253 PrerenderHandle* PrerenderManager::AddPrerenderFromOmnibox(
270 const GURL& url, 254 const GURL& url,
271 SessionStorageNamespace* session_storage_namespace, 255 SessionStorageNamespace* session_storage_namespace,
272 gfx::Size size) { 256 const gfx::Size& size) {
273 if (!IsOmniboxEnabled(profile_)) 257 if (!IsOmniboxEnabled(profile_))
274 return false; 258 return NULL;
275 return AddPrerender(ORIGIN_OMNIBOX, -1, url, 259 return AddPrerender(ORIGIN_OMNIBOX, -1, url, content::Referrer(), size,
276 content::Referrer(), size,
277 session_storage_namespace); 260 session_storage_namespace);
278 } 261 }
279 262
280 void PrerenderManager::MaybeCancelPrerender(const GURL& url) {
281 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url);
282 if (it == prerender_list_.end())
283 return;
284 PrerenderContentsData& prerender_contents_data = *it;
285 if (--prerender_contents_data.active_count_ == 0)
286 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED);
287 }
288
289 void PrerenderManager::DestroyPrerenderForRenderView( 263 void PrerenderManager::DestroyPrerenderForRenderView(
290 int process_id, int view_id, FinalStatus final_status) { 264 int process_id, int view_id, FinalStatus final_status) {
291 DCHECK(CalledOnValidThread()); 265 DCHECK(CalledOnValidThread());
292 PrerenderContentsDataList::iterator it = 266 if (PrerenderData* prerender_data =
293 FindPrerenderContentsForChildRouteIdPair( 267 FindPrerenderDataForChildAndRoute(process_id, view_id)) {
294 std::make_pair(process_id, view_id)); 268 prerender_data->contents_->Destroy(final_status);
295 if (it != prerender_list_.end()) {
296 PrerenderContents* prerender_contents = it->contents_;
297 prerender_contents->Destroy(final_status);
298 } 269 }
299 } 270 }
300 271
301 void PrerenderManager::CancelAllPrerenders() { 272 void PrerenderManager::CancelAllPrerenders() {
302 DCHECK(CalledOnValidThread()); 273 DCHECK(CalledOnValidThread());
303 while (!prerender_list_.empty()) { 274 while (!active_prerender_list_.empty()) {
304 PrerenderContentsData data = prerender_list_.front(); 275 PrerenderContents* prerender_contents =
305 DCHECK(data.contents_); 276 active_prerender_list_.front()->contents();
306 data.contents_->Destroy(FINAL_STATUS_CANCELLED); 277 prerender_contents->Destroy(FINAL_STATUS_CANCELLED);
307 } 278 }
308 } 279 }
309 280
310 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, 281 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
311 const GURL& url) { 282 const GURL& url) {
312 DCHECK(CalledOnValidThread()); 283 DCHECK(CalledOnValidThread());
313 DCHECK(!IsWebContentsPrerendering(web_contents)); 284 DCHECK(!IsWebContentsPrerendering(web_contents));
314 285
315 scoped_ptr<PrerenderContents> prerender_contents( 286 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost();
316 GetEntryButNotSpecifiedWC(url, web_contents)); 287
317 if (prerender_contents.get() == NULL) 288 DeleteOldEntries();
289 DeletePendingDeleteEntries();
290 PrerenderData* prerender_data = FindPrerenderData(
291 url, old_render_view_host->GetSessionStorageNamespace());
292 if (!prerender_data)
318 return false; 293 return false;
294 DCHECK(prerender_data->contents_);
295 if (IsNoSwapInExperiment(prerender_data->contents_->experiment_id()))
296 return false;
297
298 if (TabContents* new_tab_contents =
299 prerender_data->contents_->prerender_contents()) {
300 if (web_contents == new_tab_contents->web_contents())
301 return false; // Do not swap in to ourself.
302 }
303
304 scoped_ptr<PrerenderContents> prerender_contents(prerender_data->contents_);
305 std::list<linked_ptr<PrerenderData> >::iterator to_erase =
306 FindIteratorForPrerenderContents(prerender_contents.get());
307 DCHECK(active_prerender_list_.end() != to_erase);
308 DCHECK_EQ(prerender_data, to_erase->get());
309 active_prerender_list_.erase(to_erase);
319 310
320 // Do not use the prerendered version if there is an opener object. 311 // Do not use the prerendered version if there is an opener object.
321 if (web_contents->HasOpener()) { 312 if (web_contents->HasOpener()) {
322 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER); 313 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER);
323 return false; 314 return false;
324 } 315 }
325 316
326 // Even if we match, the location.hash might be different. Record this as a
327 // separate final status.
328 GURL matching_url;
329 bool url_matches = prerender_contents->MatchesURL(url, &matching_url);
330 DCHECK(url_matches);
331 if (url_matches && url.ref() != matching_url.ref()) {
332 prerender_contents.release()->Destroy(FINAL_STATUS_FRAGMENT_MISMATCH);
333 return false;
334 }
335
336 // If we are just in the control group (which can be detected by noticing 317 // If we are just in the control group (which can be detected by noticing
337 // that prerendering hasn't even started yet), record that |web_contents| now 318 // that prerendering hasn't even started yet), record that |web_contents| now
338 // would be showing a prerendered contents, but otherwise, don't do anything. 319 // would be showing a prerendered contents, but otherwise, don't do anything.
339 if (!prerender_contents->prerendering_has_started()) { 320 if (!prerender_contents->prerendering_has_started()) {
340 MarkWebContentsAsWouldBePrerendered(web_contents); 321 MarkWebContentsAsWouldBePrerendered(web_contents);
341 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); 322 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED);
342 return false; 323 return false;
343 } 324 }
344 325
345 // Don't use prerendered pages if debugger is attached to the tab. 326 // Don't use prerendered pages if debugger is attached to the tab.
346 // See http://crbug.com/98541 327 // See http://crbug.com/98541
347 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { 328 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) {
348 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(), 329 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(),
349 FINAL_STATUS_DEVTOOLS_ATTACHED); 330 FINAL_STATUS_DEVTOOLS_ATTACHED);
350 return false; 331 return false;
351 } 332 }
352 333
353 // If the prerendered page is in the middle of a cross-site navigation, 334 // If the prerendered page is in the middle of a cross-site navigation,
354 // don't swap it in because there isn't a good way to merge histories. 335 // don't swap it in because there isn't a good way to merge histories.
355 if (prerender_contents->IsCrossSiteNavigationPending()) { 336 if (prerender_contents->IsCrossSiteNavigationPending()) {
356 DestroyAndMarkMatchCompleteAsUsed( 337 DestroyAndMarkMatchCompleteAsUsed(
357 prerender_contents.release(), 338 prerender_contents.release(),
358 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); 339 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING);
359 return false; 340 return false;
360 } 341 }
361 342
362 // If the session storage namespaces don't match, cancel the prerender.
363 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost();
364 RenderViewHost* new_render_view_host =
365 prerender_contents->prerender_contents()->web_contents()->
366 GetRenderViewHost();
367 DCHECK(old_render_view_host);
368 DCHECK(new_render_view_host);
369 if (old_render_view_host->GetSessionStorageNamespace() !=
370 new_render_view_host->GetSessionStorageNamespace()) {
371 DestroyAndMarkMatchCompleteAsUsed(
372 prerender_contents.release(),
373 FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH);
374 return false;
375 }
376
377 // If we don't want to use prerenders at all, we are done.
378 // For bookkeeping purposes, we need to mark this WebContents to 343 // For bookkeeping purposes, we need to mark this WebContents to
379 // reflect that it would have been prerendered. 344 // reflect that it would have been prerendered.
380 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { 345 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) {
381 MarkWebContentsAsWouldBePrerendered(web_contents); 346 MarkWebContentsAsWouldBePrerendered(web_contents);
382 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); 347 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED);
383 return false; 348 return false;
384 } 349 }
385 350
386 int child_id, route_id; 351 int child_id, route_id;
387 CHECK(prerender_contents->GetChildId(&child_id)); 352 CHECK(prerender_contents->GetChildId(&child_id));
388 CHECK(prerender_contents->GetRouteId(&route_id)); 353 CHECK(prerender_contents->GetRouteId(&route_id));
389 354
390 // Try to set the prerendered page as used, so any subsequent attempts to 355 // Try to set the prerendered page as used, so any subsequent attempts to
391 // cancel on other threads will fail. If this fails because the prerender 356 // cancel on other threads will fail. If this fails because the prerender
392 // was already cancelled, possibly on another thread, fail. 357 // was already cancelled, possibly on another thread, fail.
393 if (!prerender_tracker_->TryUse(child_id, route_id)) 358 if (!prerender_tracker_->TryUse(child_id, route_id))
394 return false; 359 return false;
395 360
361 // At this point, we've determined that we will use the prerender.
362
396 if (!prerender_contents->load_start_time().is_null()) { 363 if (!prerender_contents->load_start_time().is_null()) {
397 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() - 364 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() -
398 prerender_contents->load_start_time(), 365 prerender_contents->load_start_time(),
399 GetMaxAge()); 366 GetMaxAge());
400 } 367 }
401 368
402 histograms_->RecordPerSessionCount(++prerenders_per_session_count_); 369 histograms_->RecordPerSessionCount(++prerenders_per_session_count_);
403 histograms_->RecordUsedPrerender(prerender_contents->origin()); 370 histograms_->RecordUsedPrerender(prerender_contents->origin());
404 prerender_contents->set_final_status(FINAL_STATUS_USED); 371 prerender_contents->set_final_status(FINAL_STATUS_USED);
405 372
373 RenderViewHost* new_render_view_host =
374 prerender_contents->prerender_contents()->web_contents()->
375 GetRenderViewHost();
406 new_render_view_host->Send( 376 new_render_view_host->Send(
407 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), 377 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(),
408 false)); 378 false));
409 379
380 // Start pending prerender requests from the PrerenderContents, if there are
381 // any.
382 prerender_contents->StartPendingPrerenders();
383
410 TabContents* new_tab_contents = 384 TabContents* new_tab_contents =
411 prerender_contents->ReleasePrerenderContents(); 385 prerender_contents->ReleasePrerenderContents();
412 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); 386 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents);
413 DCHECK(new_tab_contents); 387 DCHECK(new_tab_contents);
414 DCHECK(old_tab_contents); 388 DCHECK(old_tab_contents);
415 389
416 MarkWebContentsAsPrerendered(new_tab_contents->web_contents()); 390 MarkWebContentsAsPrerendered(new_tab_contents->web_contents());
417 391
418 // Merge the browsing history. 392 // Merge the browsing history.
419 new_tab_contents->web_contents()->GetController().CopyStateFromAndPrune( 393 new_tab_contents->web_contents()->GetController().CopyStateFromAndPrune(
(...skipping 12 matching lines...) Expand all
432 } 406 }
433 407
434 // Update PPLT metrics: 408 // Update PPLT metrics:
435 // If the tab has finished loading, record a PPLT of 0. 409 // If the tab has finished loading, record a PPLT of 0.
436 // If the tab is still loading, reset its start time to the current time. 410 // If the tab is still loading, reset its start time to the current time.
437 PrerenderTabHelper* prerender_tab_helper = 411 PrerenderTabHelper* prerender_tab_helper =
438 new_tab_contents->prerender_tab_helper(); 412 new_tab_contents->prerender_tab_helper();
439 DCHECK(prerender_tab_helper != NULL); 413 DCHECK(prerender_tab_helper != NULL);
440 prerender_tab_helper->PrerenderSwappedIn(); 414 prerender_tab_helper->PrerenderSwappedIn();
441 415
442 // Start pending prerender requests from the PrerenderContents, if there are
443 // any.
444 prerender_contents->StartPendingPrerenders();
445
446 if (old_tab_contents->web_contents()->NeedToFireBeforeUnload()) { 416 if (old_tab_contents->web_contents()->NeedToFireBeforeUnload()) {
447 // Schedule the delete to occur after the tab has run its unload handlers. 417 // Schedule the delete to occur after the tab has run its unload handlers.
448 on_close_tab_contents_deleters_.push_back( 418 on_close_tab_contents_deleters_.push_back(
449 new OnCloseTabContentsDeleter(this, old_tab_contents)); 419 new OnCloseTabContentsDeleter(this, old_tab_contents));
450 old_tab_contents->web_contents()->GetRenderViewHost()-> 420 old_tab_contents->web_contents()->GetRenderViewHost()->
451 FirePageBeforeUnload(false); 421 FirePageBeforeUnload(false);
452 } else { 422 } else {
453 // No unload handler to run, so delete asap. 423 // No unload handler to run, so delete asap.
454 ScheduleDeleteOldTabContents(old_tab_contents, NULL); 424 ScheduleDeleteOldTabContents(old_tab_contents, NULL);
455 } 425 }
456 426
457 // TODO(cbentzel): Should prerender_contents move to the pending delete 427 // TODO(cbentzel): Should prerender_contents move to the pending delete
458 // list, instead of deleting directly here? 428 // list, instead of deleting directly here?
459 AddToHistory(prerender_contents.get()); 429 AddToHistory(prerender_contents.get());
460 RecordNavigation(url); 430 RecordNavigation(url);
461 return true; 431 return true;
462 } 432 }
463 433
464 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry, 434 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
465 FinalStatus final_status) { 435 FinalStatus final_status) {
466 DCHECK(CalledOnValidThread()); 436 DCHECK(CalledOnValidThread());
467 DCHECK(entry); 437 DCHECK(entry);
468 // Confirm this entry has not already been moved to the pending delete list. 438 // Confirm this entry has not already been moved to the pending delete list.
469 DCHECK_EQ(0, std::count(pending_delete_list_.begin(), 439 DCHECK_EQ(0, std::count(pending_delete_list_.begin(),
470 pending_delete_list_.end(), entry)); 440 pending_delete_list_.end(), entry));
471 441
472 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 442 std::list<linked_ptr<PrerenderData> >::iterator it =
473 it != prerender_list_.end(); 443 FindIteratorForPrerenderContents(entry);
474 ++it) {
475 if (it->contents_ == entry) {
476 bool swapped_in_dummy_replacement = false;
477 444
478 // If this PrerenderContents is being deleted due to a cancellation, 445 // If this PrerenderContents is being deleted due to a cancellation,
479 // we need to create a dummy replacement for PPLT accounting purposes 446 // we need to create a dummy replacement for PPLT accounting purposes
480 // for the Match Complete group. 447 // for the Match Complete group.
481 // This is the case if the cancellation is for any reason that would not 448 // This is the case if the cancellation is for any reason that would not
482 // occur in the control group case. 449 // occur in the control group case.
483 if (entry->match_complete_status() == 450 if (it != active_prerender_list_.end()) {
484 PrerenderContents::MATCH_COMPLETE_DEFAULT && 451 if (entry->match_complete_status() ==
485 NeedMatchCompleteDummyForFinalStatus(final_status) && 452 PrerenderContents::MATCH_COMPLETE_DEFAULT &&
486 ActuallyPrerendering()) { 453 NeedMatchCompleteDummyForFinalStatus(final_status) &&
487 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. 454 ActuallyPrerendering()) {
488 // However, what if new conditions are added and 455 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering.
489 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure 456 // However, what if new conditions are added and
490 // what's the best thing to do here. For now, I will just check whether 457 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure
491 // we are actually prerendering. 458 // what's the best thing to do here. For now, I will just check whether
492 entry->set_match_complete_status( 459 // we are actually prerendering.
493 PrerenderContents::MATCH_COMPLETE_REPLACED); 460 entry->set_match_complete_status(
494 if (PrerenderContents* dummy_replacement_prerender_contents = 461 PrerenderContents::MATCH_COMPLETE_REPLACED);
495 CreatePrerenderContents(entry->prerender_url(), 462 PrerenderContents* dummy_replacement_prerender_contents =
496 entry->referrer(), 463 CreatePrerenderContents(entry->prerender_url(), entry->referrer(),
497 entry->origin(), 464 entry->origin(), entry->experiment_id());
498 entry->experiment_id())) { 465 dummy_replacement_prerender_contents->MakeIntoDummyReplacementOf(entry);
499 dummy_replacement_prerender_contents->set_match_complete_status( 466 DCHECK(dummy_replacement_prerender_contents);
500 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING); 467
501 if (!dummy_replacement_prerender_contents->Init()) 468 dummy_replacement_prerender_contents->set_match_complete_status(
502 break; 469 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING);
503 dummy_replacement_prerender_contents-> 470 DCHECK(dummy_replacement_prerender_contents->Init());
504 AddAliasURLsFromOtherPrerenderContents(entry); 471 dummy_replacement_prerender_contents->
505 dummy_replacement_prerender_contents->set_match_complete_status( 472 AddAliasURLsFromOtherPrerenderContents(entry);
506 PrerenderContents::MATCH_COMPLETE_REPLACEMENT); 473 dummy_replacement_prerender_contents->set_match_complete_status(
507 it->contents_ = dummy_replacement_prerender_contents; 474 PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
508 swapped_in_dummy_replacement = true; 475
509 } 476 it->get()->contents_ = dummy_replacement_prerender_contents;
510 } 477 } else {
511 if (!swapped_in_dummy_replacement) 478 active_prerender_list_.erase(it);
512 prerender_list_.erase(it);
513 break;
514 } 479 }
515 } 480 }
481
516 AddToHistory(entry); 482 AddToHistory(entry);
517 pending_delete_list_.push_back(entry); 483 pending_delete_list_.push_back(entry);
518 484
519 // Destroy the old WebContents relatively promptly to reduce resource usage, 485 // Destroy the old WebContents relatively promptly to reduce resource usage,
520 // and in the case of HTML5 media, reduce the change of playing any sound. 486 // and in the case of HTML5 media, reduce the change of playing any sound.
521 PostCleanupTask(); 487 PostCleanupTask();
522 } 488 }
523 489
524 // static 490 // static
525 void PrerenderManager::RecordPerceivedPageLoadTime( 491 void PrerenderManager::RecordPerceivedPageLoadTime(
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
616 } 582 }
617 583
618 // static 584 // static
619 bool PrerenderManager::IsNoUseGroup() { 585 bool PrerenderManager::IsNoUseGroup() {
620 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; 586 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP;
621 } 587 }
622 588
623 bool PrerenderManager::IsWebContentsPrerendering( 589 bool PrerenderManager::IsWebContentsPrerendering(
624 WebContents* web_contents) const { 590 WebContents* web_contents) const {
625 DCHECK(CalledOnValidThread()); 591 DCHECK(CalledOnValidThread());
626 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 592 for (std::list<linked_ptr<PrerenderData> >::const_iterator it =
627 it != prerender_list_.end(); 593 active_prerender_list_.begin();
594 it != active_prerender_list_.end();
628 ++it) { 595 ++it) {
629 TabContents* prerender_tab_contents = it->contents_->prerender_contents(); 596 TabContents* prerender_tab_contents =
597 it->get()->contents_->prerender_contents();
630 if (prerender_tab_contents && 598 if (prerender_tab_contents &&
631 prerender_tab_contents->web_contents() == web_contents) { 599 prerender_tab_contents->web_contents() == web_contents) {
632 return true; 600 return true;
633 } 601 }
634 } 602 }
635 603
636 // Also look through the pending-deletion list. 604 // Also look through the pending-deletion list.
637 for (std::list<PrerenderContents*>::const_iterator it = 605 for (std::list<PrerenderContents*>::const_iterator it =
638 pending_delete_list_.begin(); 606 pending_delete_list_.begin();
639 it != pending_delete_list_.end(); 607 it != pending_delete_list_.end();
640 ++it) { 608 ++it) {
641 TabContents* prerender_tab_contents = (*it)->prerender_contents(); 609 TabContents* prerender_tab_contents = (*it)->prerender_contents();
642 if (prerender_tab_contents && 610 if (prerender_tab_contents &&
643 prerender_tab_contents->web_contents() == web_contents) 611 prerender_tab_contents->web_contents() == web_contents)
644 return true; 612 return true;
645 } 613 }
646 614
647 return false; 615 return false;
648 } 616 }
649 617
650 bool PrerenderManager::DidPrerenderFinishLoading(const GURL& url) const {
651 DCHECK(CalledOnValidThread());
652 PrerenderContents* contents = FindEntry(url);
653 return contents ? contents->has_finished_loading() : false;
654 }
655
656 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) { 618 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) {
657 DCHECK(CalledOnValidThread()); 619 DCHECK(CalledOnValidThread());
658 prerendered_tab_contents_set_.insert(web_contents); 620 prerendered_tab_contents_set_.insert(web_contents);
659 } 621 }
660 622
661 void PrerenderManager::MarkWebContentsAsWouldBePrerendered( 623 void PrerenderManager::MarkWebContentsAsWouldBePrerendered(
662 WebContents* web_contents) { 624 WebContents* web_contents) {
663 DCHECK(CalledOnValidThread()); 625 DCHECK(CalledOnValidThread());
664 would_be_prerendered_map_[web_contents] = true; 626 would_be_prerendered_map_[web_contents] = true;
665 } 627 }
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
761 histograms_->RecordFinalStatus(origin, 723 histograms_->RecordFinalStatus(origin,
762 experiment_id, 724 experiment_id,
763 mc_status, 725 mc_status,
764 final_status); 726 final_status);
765 } 727 }
766 728
767 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { 729 void PrerenderManager::AddCondition(const PrerenderCondition* condition) {
768 prerender_conditions_.push_back(condition); 730 prerender_conditions_.push_back(condition);
769 } 731 }
770 732
771 bool PrerenderManager::IsPendingEntry(const GURL& url) const {
772 DCHECK(CalledOnValidThread());
773 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
774 it != prerender_list_.end();
775 ++it) {
776 if (it->contents_->IsPendingEntry(url))
777 return true;
778 }
779 return false;
780 }
781
782 bool PrerenderManager::IsPrerendering(const GURL& url) const {
783 DCHECK(CalledOnValidThread());
784 return (FindEntry(url) != NULL);
785 }
786
787 void PrerenderManager::RecordNavigation(const GURL& url) { 733 void PrerenderManager::RecordNavigation(const GURL& url) {
788 DCHECK(CalledOnValidThread()); 734 DCHECK(CalledOnValidThread());
789 735
790 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); 736 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks()));
791 CleanUpOldNavigations(); 737 CleanUpOldNavigations();
792 } 738 }
793 739
794 // protected 740 // protected
741 PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager)
742 : manager_(manager), contents_(NULL), handle_count_(0) {
743 }
744
745 PrerenderManager::PrerenderData::PrerenderData(PrerenderManager* manager,
746 PrerenderContents* contents)
747 : manager_(manager), contents_(contents), handle_count_(0) {
748 }
749
750 void PrerenderManager::PrerenderData::OnNewHandle() {
751 DCHECK(contents_ || handle_count_ == 0) <<
752 "Cannot create multiple handles to a pending prerender.";
753 ++handle_count_;
754 }
755
756 void PrerenderManager::PrerenderData::OnNavigateAway() {
757 // TODO(gavinp): Implement reasonable behaviour for navigation away from
758 // launcher. We can't just call OnCancel, because many cases have redirect
759 // chains that will eventually lead to the correct prerendered page, and we
760 // don't want to delete our prerender just as it is going to be used.
761
762 if (!contents_) {
763 DCHECK_EQ(1, handle_count_);
dominich 2012/07/12 16:16:48 I don't understand why the handle can only be 1 in
gavinp 2012/07/13 12:02:22 Ah, it can't. This was an assertion about the hand
764 // Pending prerenders are not maintained in the active_prerender_list_,
765 // and this prerender hasn't even been launched yet, so we just toss it.
766 // it.
767 manager_->DestroyPendingPrerenderData(this);
768 }
769 }
770
771 void PrerenderManager::PrerenderData::OnCancel() {
dominich 2012/07/12 16:16:48 DCHECK(handle_count_ >= 0); ?
gavinp 2012/07/13 12:02:22 Done.
772 if (--handle_count_ == 0) {
773 if (contents_) {
774 // This will eventually remove this object from active_prerender_list_,
775 // triggering the linked_ptr auto deletion.
776 contents_->Destroy(FINAL_STATUS_CANCELLED);
777 } else {
778 manager_->DestroyPendingPrerenderData(this);
779 }
780 }
781 }
782
783 PrerenderManager::PrerenderData::~PrerenderData() {
784 }
785
795 void PrerenderManager::SetPrerenderContentsFactory( 786 void PrerenderManager::SetPrerenderContentsFactory(
796 PrerenderContents::Factory* prerender_contents_factory) { 787 PrerenderContents::Factory* prerender_contents_factory) {
797 DCHECK(CalledOnValidThread()); 788 DCHECK(CalledOnValidThread());
798 prerender_contents_factory_.reset(prerender_contents_factory); 789 prerender_contents_factory_.reset(prerender_contents_factory);
799 } 790 }
800 791
792 void PrerenderManager::StartPendingPrerender(
793 PrerenderHandle* existing_prerender_handle,
794 Origin origin,
795 int process_id,
796 const GURL& url,
797 const content::Referrer& referrer,
798 const gfx::Size& size,
799 content::SessionStorageNamespace* session_storage_namespace) {
800 DCHECK(existing_prerender_handle);
801 DCHECK(existing_prerender_handle->IsValid());
802 DCHECK(existing_prerender_handle->IsPending());
803
804 DCHECK(process_id == -1 || session_storage_namespace);
805
806 scoped_ptr<PrerenderHandle> new_prerender_handle(AddPrerender(
807 origin, process_id, url, referrer, size, session_storage_namespace));
808 if (new_prerender_handle.get()) {
809 // AddPrerender has returned a new prerender handle to us. We want to make
810 // |existing_prerender_handle| active, so swap the underlying PrerenderData
811 // between the two handles, and delete our old handle (which will release
812 // our entry in the pending_prerender_list_).
813 existing_prerender_handle->SwapPrerenderDataWith(
814 new_prerender_handle.get());
mmenke 2012/07/12 17:23:21 nit: may fit on one line.
gavinp 2012/07/13 12:02:22 Not unless I rename the variable to |existing_prer
mmenke 2012/07/13 14:49:10 Was that before or after you renamed the handle, a
815 return;
816 }
817
818 // We could not start our Prerender. Canceling the existing handle will make
819 // it return false for PrerenderHandle::IsPending(), and will release the
820 // PrerenderData from pending_prerender_list_.
821 existing_prerender_handle->OnCancel();
822 }
823
824 void PrerenderManager::DestroyPendingPrerenderData(
825 PrerenderData* pending_prerender_data) {
826 for (std::list<linked_ptr<PrerenderData> >::iterator
827 it = pending_prerender_list_.begin();
828 it != pending_prerender_list_.end();
829 ++it) {
830 if (it->get() == pending_prerender_data) {
831 DCHECK_EQ(0, pending_prerender_data->handle_count_);
832 pending_prerender_list_.erase(it);
833 return;
834 }
835 }
836 NOTREACHED();
837 }
838
801 void PrerenderManager::DoShutdown() { 839 void PrerenderManager::DoShutdown() {
802 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); 840 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN);
803 STLDeleteElements(&prerender_conditions_); 841 STLDeleteElements(&prerender_conditions_);
804 on_close_tab_contents_deleters_.reset(); 842 on_close_tab_contents_deleters_.reset();
805 profile_ = NULL; 843 profile_ = NULL;
844
845 DCHECK(active_prerender_list_.empty());
806 } 846 }
807 847
808 // private 848 // private
809 bool PrerenderManager::AddPrerender( 849 PrerenderHandle* PrerenderManager::AddPrerender(
810 Origin origin, 850 Origin origin,
811 int process_id, 851 int process_id,
812 const GURL& url_arg, 852 const GURL& url_arg,
813 const content::Referrer& referrer, 853 const content::Referrer& referrer,
814 gfx::Size size, 854 const gfx::Size& size,
815 SessionStorageNamespace* session_storage_namespace) { 855 SessionStorageNamespace* session_storage_namespace) {
816 DCHECK(CalledOnValidThread()); 856 DCHECK(CalledOnValidThread());
817 857
818 if (!IsEnabled()) 858 if (!IsEnabled())
819 return false; 859 return NULL;
820 860
821 if (origin == ORIGIN_LINK_REL_PRERENDER && 861 if (origin == ORIGIN_LINK_REL_PRERENDER &&
822 IsGoogleSearchResultURL(referrer.url)) { 862 IsGoogleSearchResultURL(referrer.url)) {
823 origin = ORIGIN_GWS_PRERENDER; 863 origin = ORIGIN_GWS_PRERENDER;
824 } 864 }
825 865
826 DeleteOldEntries(); 866 DeleteOldEntries();
827 DeletePendingDeleteEntries(); 867 DeletePendingDeleteEntries();
828 868
829 GURL url = url_arg; 869 GURL url = url_arg;
830 GURL alias_url; 870 GURL alias_url;
831 uint8 experiment = GetQueryStringBasedExperiment(url_arg); 871 uint8 experiment = GetQueryStringBasedExperiment(url_arg);
832 bool control_group_behavior = 872 bool control_group_behavior =
833 IsControlGroup() || IsControlGroupExperiment(experiment); 873 IsControlGroup() || IsControlGroupExperiment(experiment);
834 if (control_group_behavior && 874 if (control_group_behavior &&
835 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { 875 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) {
836 url = alias_url; 876 url = alias_url;
837 } 877 }
838 878
839 // From here on, we will record a FinalStatus so we need to register with the 879 // From here on, we will record a FinalStatus so we need to register with the
840 // histogram tracking. 880 // histogram tracking.
841 histograms_->RecordPrerender(origin, url_arg); 881 histograms_->RecordPrerender(origin, url_arg);
842 882
843 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) { 883 if (PrerenderData* preexisting_prerender_data =
844 ++prerender_contents_data->active_count_; 884 FindPrerenderData(url, session_storage_namespace)) {
845 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); 885 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE);
846 return true; 886 return new PrerenderHandle(preexisting_prerender_data);
847 } 887 }
848 888
849 // Do not prerender if there are too many render processes, and we would 889 // Do not prerender if there are too many render processes, and we would
850 // have to use an existing one. We do not want prerendering to happen in 890 // have to use an existing one. We do not want prerendering to happen in
851 // a shared process, so that we can always reliably lower the CPU 891 // a shared process, so that we can always reliably lower the CPU
852 // priority for prerendering. 892 // priority for prerendering.
853 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns 893 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns
854 // true, so that case needs to be explicitly checked for. 894 // true, so that case needs to be explicitly checked for.
855 // TODO(tburkard): Figure out how to cancel prerendering in the opposite 895 // TODO(tburkard): Figure out how to cancel prerendering in the opposite
856 // case, when a new tab is added to a process used for prerendering. 896 // case, when a new tab is added to a process used for prerendering.
857 // On Android we do reuse processes as we have a limited number of them and we 897 // On Android we do reuse processes as we have a limited number of them and we
858 // still want the benefits of prerendering even when several tabs are open. 898 // still want the benefits of prerendering even when several tabs are open.
859 #if !defined(OS_ANDROID) 899 #if !defined(OS_ANDROID)
860 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost( 900 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost(
861 profile_, url) && 901 profile_, url) &&
862 !content::RenderProcessHost::run_renderer_in_process()) { 902 !content::RenderProcessHost::run_renderer_in_process()) {
863 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); 903 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES);
864 return false; 904 return NULL;
865 } 905 }
866 #endif 906 #endif
867 907
868 // Check if enough time has passed since the last prerender. 908 // Check if enough time has passed since the last prerender.
869 if (!DoesRateLimitAllowPrerender()) { 909 if (!DoesRateLimitAllowPrerender()) {
870 // Cancel the prerender. We could add it to the pending prerender list but 910 // Cancel the prerender. We could add it to the pending prerender list but
871 // this doesn't make sense as the next prerender request will be triggered 911 // this doesn't make sense as the next prerender request will be triggered
872 // by a navigation and is unlikely to be the same site. 912 // by a navigation and is unlikely to be the same site.
873 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); 913 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED);
874 return false; 914 return NULL;
875 } 915 }
876 916
877 PrerenderContents* prerender_contents = CreatePrerenderContents( 917 PrerenderContents* prerender_contents = CreatePrerenderContents(
878 url, referrer, origin, experiment); 918 url, referrer, origin, experiment);
879 if (!prerender_contents || !prerender_contents->Init()) 919 if (!prerender_contents || !prerender_contents->Init())
880 return false; 920 return NULL;
881 921
882 histograms_->RecordPrerenderStarted(origin); 922 histograms_->RecordPrerenderStarted(origin);
883 923
884 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? 924 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
885 PrerenderContentsData data(prerender_contents, GetCurrentTime()); 925 active_prerender_list_.push_back(
886 926 linked_ptr<PrerenderData>(new PrerenderData(this, prerender_contents)));
887 prerender_list_.push_back(data); 927 PrerenderHandle* prerender_handle =
928 new PrerenderHandle(active_prerender_list_.back().get());
888 929
889 last_prerender_start_time_ = GetCurrentTimeTicks(); 930 last_prerender_start_time_ = GetCurrentTimeTicks();
890 931
891 if (size.IsEmpty()) 932 gfx::Size contents_size =
892 size = config_.default_tab_bounds.size(); 933 size.IsEmpty() ? config_.default_tab_bounds.size() : size;
893 934
894 data.contents_->StartPrerendering(process_id, size, session_storage_namespace, 935 prerender_contents->StartPrerendering(process_id, contents_size,
895 control_group_behavior); 936 session_storage_namespace,
937 control_group_behavior);
896 938
897 while (prerender_list_.size() > config_.max_elements) { 939 while (active_prerender_list_.size() > config_.max_elements) {
898 data = prerender_list_.front(); 940 prerender_contents = active_prerender_list_.front()->contents_;
899 prerender_list_.pop_front(); 941 DCHECK(prerender_contents);
900 data.contents_->Destroy(FINAL_STATUS_EVICTED); 942 prerender_contents->Destroy(FINAL_STATUS_EVICTED);
901 } 943 }
944
902 StartSchedulingPeriodicCleanups(); 945 StartSchedulingPeriodicCleanups();
903 return true; 946 return prerender_handle;
904 }
905
906 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) {
907 return GetEntryButNotSpecifiedWC(url, NULL);
908 }
909
910 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC(
911 const GURL& url,
912 WebContents* wc) {
913 DCHECK(CalledOnValidThread());
914 DeleteOldEntries();
915 DeletePendingDeleteEntries();
916 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
917 it != prerender_list_.end();
918 ++it) {
919 PrerenderContents* prerender_contents = it->contents_;
920 if (prerender_contents->MatchesURL(url, NULL) &&
921 !IsNoSwapInExperiment(prerender_contents->experiment_id())) {
922 if (!prerender_contents->prerender_contents() ||
923 !wc ||
924 prerender_contents->prerender_contents()->web_contents() != wc) {
925 prerender_list_.erase(it);
926 return prerender_contents;
927 }
928 }
929 }
930 // Entry not found.
931 return NULL;
932 } 947 }
933 948
934 void PrerenderManager::StartSchedulingPeriodicCleanups() { 949 void PrerenderManager::StartSchedulingPeriodicCleanups() {
935 DCHECK(CalledOnValidThread()); 950 DCHECK(CalledOnValidThread());
936 if (repeating_timer_.IsRunning()) 951 if (repeating_timer_.IsRunning())
937 return; 952 return;
938 repeating_timer_.Start(FROM_HERE, 953 repeating_timer_.Start(FROM_HERE,
939 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), 954 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs),
940 this, 955 this,
941 &PrerenderManager::PeriodicCleanup); 956 &PrerenderManager::PeriodicCleanup);
942 } 957 }
943 958
944 void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { 959 void PrerenderManager::StopSchedulingPeriodicCleanups() {
945 if (!prerender_list_.empty())
946 return;
947
948 DCHECK(CalledOnValidThread()); 960 DCHECK(CalledOnValidThread());
949 repeating_timer_.Stop(); 961 repeating_timer_.Stop();
950 } 962 }
951 963
952 void PrerenderManager::PeriodicCleanup() { 964 void PrerenderManager::PeriodicCleanup() {
953 DCHECK(CalledOnValidThread()); 965 DCHECK(CalledOnValidThread());
954 DeleteOldTabContents(); 966 DeleteOldTabContents();
955 DeleteOldEntries(); 967 DeleteOldEntries();
968 if (active_prerender_list_.empty())
969 StopSchedulingPeriodicCleanups();
956 970
957 // Grab a copy of the current PrerenderContents pointers, so that we 971 // Grab a copy of the current PrerenderContents pointers, so that we
958 // will not interfere with potential deletions of the list. 972 // will not interfere with potential deletions of the list.
959 std::vector<PrerenderContents*> prerender_contents; 973 std::vector<PrerenderContents*> prerender_contents;
960 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 974 prerender_contents.reserve(active_prerender_list_.size());
961 it != prerender_list_.end(); 975 for (std::list<linked_ptr<PrerenderData> >::iterator
962 ++it) { 976 it = active_prerender_list_.begin();
963 DCHECK(it->contents_); 977 it != active_prerender_list_.end();
964 prerender_contents.push_back(it->contents_); 978 ++it) {
979 prerender_contents.push_back(it->get()->contents_);
965 } 980 }
966 for (std::vector<PrerenderContents*>::iterator it = 981 std::for_each(prerender_contents.begin(), prerender_contents.end(),
967 prerender_contents.begin(); 982 std::mem_fun(
968 it != prerender_contents.end(); 983 &PrerenderContents::DestroyWhenUsingTooManyResources));
969 ++it) {
970 (*it)->DestroyWhenUsingTooManyResources();
971 }
972 984
973 DeletePendingDeleteEntries(); 985 DeletePendingDeleteEntries();
974 } 986 }
975 987
976 void PrerenderManager::PostCleanupTask() { 988 void PrerenderManager::PostCleanupTask() {
977 DCHECK(CalledOnValidThread()); 989 DCHECK(CalledOnValidThread());
978 MessageLoop::current()->PostTask( 990 MessageLoop::current()->PostTask(
979 FROM_HERE, 991 FROM_HERE,
980 base::Bind(&PrerenderManager::PeriodicCleanup, 992 base::Bind(&PrerenderManager::PeriodicCleanup,
981 weak_factory_.GetWeakPtr())); 993 weak_factory_.GetWeakPtr()));
982 } 994 }
983 995
984 base::TimeDelta PrerenderManager::GetMaxAge() const { 996 base::TimeDelta PrerenderManager::GetMaxAge() const {
985 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ? 997 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ?
986 base::TimeDelta::FromSeconds(300) : config_.max_age); 998 base::TimeDelta::FromSeconds(300) : config_.max_age);
987 } 999 }
988 1000
989 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { 1001 bool PrerenderManager::IsPrerenderFresh(const base::TimeTicks start) const {
990 DCHECK(CalledOnValidThread()); 1002 DCHECK(CalledOnValidThread());
991 base::Time now = GetCurrentTime(); 1003 return GetCurrentTimeTicks() - start < GetMaxAge();
992 return (now - start < GetMaxAge());
993 } 1004 }
994 1005
995 void PrerenderManager::DeleteOldEntries() { 1006 void PrerenderManager::DeleteOldEntries() {
996 DCHECK(CalledOnValidThread()); 1007 DCHECK(CalledOnValidThread());
997 while (!prerender_list_.empty()) { 1008 while (!active_prerender_list_.empty()) {
998 PrerenderContentsData data = prerender_list_.front(); 1009 PrerenderContents* contents = active_prerender_list_.front()->contents_;
999 if (IsPrerenderElementFresh(data.start_time_)) 1010 DCHECK(contents);
1011 if (IsPrerenderFresh(contents->load_start_time()))
1000 return; 1012 return;
1001 data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); 1013 contents->Destroy(FINAL_STATUS_TIMED_OUT);
1002 } 1014 }
1003 MaybeStopSchedulingPeriodicCleanups();
1004 } 1015 }
1005 1016
1006 base::Time PrerenderManager::GetCurrentTime() const { 1017 base::Time PrerenderManager::GetCurrentTime() const {
1007 return base::Time::Now(); 1018 return base::Time::Now();
1008 } 1019 }
1009 1020
1010 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { 1021 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const {
1011 return base::TimeTicks::Now(); 1022 return base::TimeTicks::Now();
1012 } 1023 }
1013 1024
1014 PrerenderContents* PrerenderManager::CreatePrerenderContents( 1025 PrerenderContents* PrerenderManager::CreatePrerenderContents(
1015 const GURL& url, 1026 const GURL& url,
1016 const content::Referrer& referrer, 1027 const content::Referrer& referrer,
1017 Origin origin, 1028 Origin origin,
1018 uint8 experiment_id) { 1029 uint8 experiment_id) {
1019 DCHECK(CalledOnValidThread()); 1030 DCHECK(CalledOnValidThread());
1020 return prerender_contents_factory_->CreatePrerenderContents( 1031 return prerender_contents_factory_->CreatePrerenderContents(
1021 this, prerender_tracker_, profile_, url, 1032 this, prerender_tracker_, profile_, url,
1022 referrer, origin, experiment_id); 1033 referrer, origin, experiment_id);
1023 } 1034 }
1024 1035
1025 void PrerenderManager::DeletePendingDeleteEntries() { 1036 void PrerenderManager::DeletePendingDeleteEntries() {
1026 while (!pending_delete_list_.empty()) { 1037 while (!pending_delete_list_.empty()) {
1027 PrerenderContents* contents = pending_delete_list_.front(); 1038 PrerenderContents* contents = pending_delete_list_.front();
1028 pending_delete_list_.pop_front(); 1039 pending_delete_list_.pop_front();
1029 delete contents; 1040 delete contents;
1030 } 1041 }
1031 } 1042 }
1032 1043
1033 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData( 1044 PrerenderManager::PrerenderData* PrerenderManager::FindPrerenderData(
1034 const GURL& url) { 1045 const GURL& url,
1035 DCHECK(CalledOnValidThread()); 1046 const SessionStorageNamespace* session_storage_namespace) {
1036 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url); 1047 for (std::list<linked_ptr<PrerenderData> >::iterator
1037 if (it == prerender_list_.end()) 1048 it = active_prerender_list_.begin();
1038 return NULL; 1049 it != active_prerender_list_.end();
1039 PrerenderContentsData& prerender_contents_data = *it;
1040 return &prerender_contents_data;
1041 }
1042
1043 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const {
1044 DCHECK(CalledOnValidThread());
1045 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
1046 it != prerender_list_.end();
1047 ++it) { 1050 ++it) {
1048 if (it->contents_->MatchesURL(url, NULL)) 1051 PrerenderContents* prerender_contents = it->get()->contents_;
1049 return it->contents_; 1052 if (prerender_contents->Matches(url, session_storage_namespace))
1053 return it->get();
1050 } 1054 }
1051 // Entry not found.
1052 return NULL; 1055 return NULL;
1053 } 1056 }
1054 1057
1055 PrerenderManager::PrerenderContentsDataList::iterator 1058 PrerenderManager::PrerenderData*
1056 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( 1059 PrerenderManager::FindPrerenderDataForChildAndRoute(
1057 const std::pair<int, int>& child_route_id_pair) { 1060 const int child_id, const int route_id) {
1058 PrerenderContentsDataList::iterator it = prerender_list_.begin(); 1061 for (std::list<linked_ptr<PrerenderData> >::iterator
1059 for (; it != prerender_list_.end(); ++it) { 1062 it = active_prerender_list_.begin();
1060 PrerenderContents* prerender_contents = it->contents_; 1063 it != active_prerender_list_.end();
1064 ++it) {
1065 PrerenderContents* prerender_contents = it->get()->contents_;
1061 1066
1062 int child_id; 1067 int contents_child_id;
1063 int route_id; 1068 if (!prerender_contents->GetChildId(&contents_child_id))
1064 bool has_child_id = prerender_contents->GetChildId(&child_id); 1069 continue;
1065 bool has_route_id = has_child_id && 1070 int contents_route_id;
1066 prerender_contents->GetRouteId(&route_id); 1071 if (!prerender_contents->GetRouteId(&contents_route_id))
1072 continue;
1067 1073
1068 if (has_child_id && has_route_id && 1074 if (contents_child_id == child_id && contents_route_id == route_id)
1069 child_id == child_route_id_pair.first && 1075 return it->get();
1070 route_id == child_route_id_pair.second) {
1071 break;
1072 }
1073 } 1076 }
1074 return it; 1077 return NULL;
1075 } 1078 }
1076 1079
1077 PrerenderManager::PrerenderContentsDataList::iterator 1080 std::list<linked_ptr<PrerenderManager::PrerenderData> >::iterator
1078 PrerenderManager::FindPrerenderContentsForURL(const GURL& url) { 1081 PrerenderManager::FindIteratorForPrerenderContents(
1079 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 1082 PrerenderContents* prerender_contents) {
1080 it != prerender_list_.end(); ++it) { 1083 for (std::list<linked_ptr<PrerenderData> >::iterator
1081 if (it->contents_->MatchesURL(url, NULL)) 1084 it = active_prerender_list_.begin();
1085 it != active_prerender_list_.end();
1086 ++it) {
1087 if (prerender_contents == it->get()->contents_)
1082 return it; 1088 return it;
1083 } 1089 }
1084 return prerender_list_.end(); 1090 return active_prerender_list_.end();
1085 } 1091 }
1086 1092
1087 bool PrerenderManager::DoesRateLimitAllowPrerender() const { 1093 bool PrerenderManager::DoesRateLimitAllowPrerender() const {
1088 DCHECK(CalledOnValidThread()); 1094 DCHECK(CalledOnValidThread());
1089 base::TimeDelta elapsed_time = 1095 base::TimeDelta elapsed_time =
1090 GetCurrentTimeTicks() - last_prerender_start_time_; 1096 GetCurrentTimeTicks() - last_prerender_start_time_;
1091 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); 1097 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time);
1092 if (!config_.rate_limit_enabled) 1098 if (!config_.rate_limit_enabled)
1093 return true; 1099 return true;
1094 return elapsed_time > 1100 return elapsed_time >
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1136 void PrerenderManager::AddToHistory(PrerenderContents* contents) { 1142 void PrerenderManager::AddToHistory(PrerenderContents* contents) {
1137 PrerenderHistory::Entry entry(contents->prerender_url(), 1143 PrerenderHistory::Entry entry(contents->prerender_url(),
1138 contents->final_status(), 1144 contents->final_status(),
1139 contents->origin(), 1145 contents->origin(),
1140 base::Time::Now()); 1146 base::Time::Now());
1141 prerender_history_->AddEntry(entry); 1147 prerender_history_->AddEntry(entry);
1142 } 1148 }
1143 1149
1144 Value* PrerenderManager::GetActivePrerendersAsValue() const { 1150 Value* PrerenderManager::GetActivePrerendersAsValue() const {
1145 ListValue* list_value = new ListValue(); 1151 ListValue* list_value = new ListValue();
1146 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 1152 for (std::list<linked_ptr<PrerenderData> >::const_iterator it =
1147 it != prerender_list_.end(); 1153 active_prerender_list_.begin();
1154 it != active_prerender_list_.end();
1148 ++it) { 1155 ++it) {
1149 Value* prerender_value = it->contents_->GetAsValue(); 1156 if (Value* prerender_value = it->get()->contents_->GetAsValue())
1150 if (!prerender_value) 1157 list_value->Append(prerender_value);
1151 continue;
1152 list_value->Append(prerender_value);
1153 } 1158 }
1154 return list_value; 1159 return list_value;
1155 } 1160 }
1156 1161
1157 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { 1162 void PrerenderManager::DestroyAllContents(FinalStatus final_status) {
1158 DeleteOldTabContents(); 1163 DeleteOldTabContents();
1159 while (!prerender_list_.empty()) { 1164 while (!active_prerender_list_.empty()) {
1160 PrerenderContentsData data = prerender_list_.front(); 1165 PrerenderContents* contents = active_prerender_list_.front()->contents_;
1161 prerender_list_.pop_front(); 1166 contents->Destroy(final_status);
1162 data.contents_->Destroy(final_status);
1163 } 1167 }
1164 DeletePendingDeleteEntries(); 1168 DeletePendingDeleteEntries();
1165 } 1169 }
1166 1170
1167 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed( 1171 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed(
1168 PrerenderContents* prerender_contents, 1172 PrerenderContents* prerender_contents,
1169 FinalStatus final_status) { 1173 FinalStatus final_status) {
1170 prerender_contents->set_match_complete_status( 1174 prerender_contents->set_match_complete_status(
1171 PrerenderContents::MATCH_COMPLETE_REPLACED); 1175 PrerenderContents::MATCH_COMPLETE_REPLACED);
1172 histograms_->RecordFinalStatus(prerender_contents->origin(), 1176 histograms_->RecordFinalStatus(prerender_contents->origin(),
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1211 if (!render_process_host || !render_process_host->GetBrowserContext()) 1215 if (!render_process_host || !render_process_host->GetBrowserContext())
1212 return NULL; 1216 return NULL;
1213 Profile* profile = Profile::FromBrowserContext( 1217 Profile* profile = Profile::FromBrowserContext(
1214 render_process_host->GetBrowserContext()); 1218 render_process_host->GetBrowserContext());
1215 if (!profile) 1219 if (!profile)
1216 return NULL; 1220 return NULL;
1217 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); 1221 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile);
1218 } 1222 }
1219 1223
1220 } // namespace prerender 1224 } // namespace prerender
1225
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698