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

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: more standard code, simpler handle, no class explosion Created 8 years, 6 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 <set>
8 #include <string> 8 #include <string>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/memory/weak_ptr.h" 14 #include "base/memory/weak_ptr.h"
15 #include "base/metrics/histogram.h" 15 #include "base/metrics/histogram.h"
16 #include "base/stl_util.h" 16 #include "base/stl_util.h"
17 #include "base/time.h" 17 #include "base/time.h"
18 #include "base/utf_string_conversions.h" 18 #include "base/utf_string_conversions.h"
19 #include "base/values.h" 19 #include "base/values.h"
20 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/cancelable_request.h" 21 #include "chrome/browser/cancelable_request.h"
22 #include "chrome/browser/favicon/favicon_tab_helper.h" 22 #include "chrome/browser/favicon/favicon_tab_helper.h"
23 #include "chrome/browser/prerender/prerender_condition.h" 23 #include "chrome/browser/prerender/prerender_condition.h"
24 #include "chrome/browser/prerender/prerender_contents.h" 24 #include "chrome/browser/prerender/prerender_contents.h"
25 #include "chrome/browser/prerender/prerender_field_trial.h" 25 #include "chrome/browser/prerender/prerender_field_trial.h"
26 #include "chrome/browser/prerender/prerender_final_status.h" 26 #include "chrome/browser/prerender/prerender_final_status.h"
27 #include "chrome/browser/prerender/prerender_handle.h"
27 #include "chrome/browser/prerender/prerender_histograms.h" 28 #include "chrome/browser/prerender/prerender_histograms.h"
28 #include "chrome/browser/prerender/prerender_history.h" 29 #include "chrome/browser/prerender/prerender_history.h"
29 #include "chrome/browser/prerender/prerender_local_predictor.h" 30 #include "chrome/browser/prerender/prerender_local_predictor.h"
30 #include "chrome/browser/prerender/prerender_manager_factory.h" 31 #include "chrome/browser/prerender/prerender_manager_factory.h"
31 #include "chrome/browser/prerender/prerender_tab_helper.h" 32 #include "chrome/browser/prerender/prerender_tab_helper.h"
32 #include "chrome/browser/prerender/prerender_tracker.h" 33 #include "chrome/browser/prerender/prerender_tracker.h"
33 #include "chrome/browser/prerender/prerender_util.h" 34 #include "chrome/browser/prerender/prerender_util.h"
34 #include "chrome/browser/profiles/profile.h" 35 #include "chrome/browser/profiles/profile.h"
35 #include "chrome/browser/ui/tab_contents/core_tab_helper.h" 36 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
36 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h" 37 #include "chrome/browser/ui/tab_contents/core_tab_helper_delegate.h"
(...skipping 15 matching lines...) Expand all
52 53
53 using content::BrowserThread; 54 using content::BrowserThread;
54 using content::RenderViewHost; 55 using content::RenderViewHost;
55 using content::SessionStorageNamespace; 56 using content::SessionStorageNamespace;
56 using content::WebContents; 57 using content::WebContents;
57 58
58 namespace prerender { 59 namespace prerender {
59 60
60 namespace { 61 namespace {
61 62
62 // Time window for which we will record windowed PLT's from the last
63 // observed link rel=prefetch tag.
64 const int kWindowDurationSeconds = 30;
65
66 // Time interval at which periodic cleanups are performed.
67 const int kPeriodicCleanupIntervalMs = 1000;
68
69 // Time interval before a new prerender is allowed.
70 const int kMinTimeBetweenPrerendersMs = 500;
71
72 // Valid HTTP methods for prerendering.
73 const char* const kValidHttpMethods[] = {
74 "GET",
75 "HEAD",
76 "OPTIONS",
77 "POST",
78 "TRACE",
79 };
80
81 // Length of prerender history, for display in chrome://net-internals
82 const int kHistoryLength = 100;
83
84 // Indicates whether a Prerender has been cancelled such that we need 63 // Indicates whether a Prerender has been cancelled such that we need
85 // a dummy replacement for the purpose of recording the correct PPLT for 64 // a dummy replacement for the purpose of recording the correct PPLT for
86 // the Match Complete case. 65 // the Match Complete case.
87 // Traditionally, "Match" means that a prerendered page was actually visited & 66 // Traditionally, "Match" means that a prerendered page was actually visited &
88 // the prerender was used. Our goal is to have "Match" cases line up in the 67 // the prerender was used. Our goal is to have "Match" cases line up in the
89 // control group & the experiment group, so that we can make meaningful 68 // control group & the experiment group, so that we can make meaningful
90 // comparisons of improvements. However, in the control group, since we don't 69 // comparisons of improvements. However, in the control group, since we don't
91 // actually perform prerenders, many of the cancellation reasons cannot be 70 // actually perform prerenders, many of the cancellation reasons cannot be
92 // detected. Therefore, in the Prerender group, when we cancel for one of these 71 // detected. Therefore, in the Prerender group, when we cancel for one of these
93 // reasons, we keep track of a dummy Prerender representing what we would 72 // reasons, we keep track of a dummy Prerender representing what we would
(...skipping 12 matching lines...) Expand all
106 final_status != FINAL_STATUS_APP_TERMINATING && 85 final_status != FINAL_STATUS_APP_TERMINATING &&
107 final_status != FINAL_STATUS_WINDOW_OPENER && 86 final_status != FINAL_STATUS_WINDOW_OPENER &&
108 final_status != FINAL_STATUS_FRAGMENT_MISMATCH && 87 final_status != FINAL_STATUS_FRAGMENT_MISMATCH &&
109 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED && 88 final_status != FINAL_STATUS_CACHE_OR_HISTORY_CLEARED &&
110 final_status != FINAL_STATUS_CANCELLED && 89 final_status != FINAL_STATUS_CANCELLED &&
111 final_status != FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH && 90 final_status != FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH &&
112 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED && 91 final_status != FINAL_STATUS_DEVTOOLS_ATTACHED &&
113 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING; 92 final_status != FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING;
114 } 93 }
115 94
95 // Time window for which we will record windowed PLT's from the last
96 // observed link rel=prefetch tag.
97 const int kWindowDurationSeconds = 30;
98
99 // Time interval at which periodic cleanups are performed.
100 const int kPeriodicCleanupIntervalMs = 1000;
101
102 // Time interval before a new prerender is allowed.
103 const int kMinTimeBetweenPrerendersMs = 500;
104
105 // Valid HTTP methods for prerendering.
106 const char* const kValidHttpMethods[] = {
107 "GET",
108 "HEAD",
109 "OPTIONS",
110 "POST",
111 "TRACE",
112 };
113
114 // Length of prerender history, for display in chrome://net-internals
115 const int kHistoryLength = 100;
mmenke 2012/06/22 16:12:45 nit: In cc files, the general style is to put con
116
116 } // namespace 117 } // namespace
117 118
118 class PrerenderManager::OnCloseTabContentsDeleter 119 class PrerenderManager::OnCloseTabContentsDeleter
119 : public content::WebContentsDelegate, 120 : public content::WebContentsDelegate,
120 public base::SupportsWeakPtr< 121 public base::SupportsWeakPtr<
121 PrerenderManager::OnCloseTabContentsDeleter> { 122 PrerenderManager::OnCloseTabContentsDeleter> {
122 public: 123 public:
123 OnCloseTabContentsDeleter(PrerenderManager* manager, 124 OnCloseTabContentsDeleter(PrerenderManager* manager,
124 TabContents* tab) 125 TabContents* tab)
125 : manager_(manager), 126 : manager_(manager),
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 // static 164 // static
164 bool PrerenderManager::is_prefetch_enabled_ = false; 165 bool PrerenderManager::is_prefetch_enabled_ = false;
165 166
166 // static 167 // static
167 int PrerenderManager::prerenders_per_session_count_ = 0; 168 int PrerenderManager::prerenders_per_session_count_ = 0;
168 169
169 // static 170 // static
170 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ = 171 PrerenderManager::PrerenderManagerMode PrerenderManager::mode_ =
171 PRERENDER_MODE_ENABLED; 172 PRERENDER_MODE_ENABLED;
172 173
173 struct PrerenderManager::PrerenderContentsData {
174 PrerenderContents* contents_;
175 base::Time start_time_;
176 int active_count_;
177 PrerenderContentsData(PrerenderContents* contents, base::Time start_time)
178 : contents_(contents),
179 start_time_(start_time),
180 active_count_(1) {
181 CHECK(contents);
182 }
183 };
184
185 struct PrerenderManager::NavigationRecord { 174 struct PrerenderManager::NavigationRecord {
186 GURL url_; 175 GURL url_;
187 base::TimeTicks time_; 176 base::TimeTicks time_;
188 NavigationRecord(const GURL& url, base::TimeTicks time) 177 NavigationRecord(const GURL& url, base::TimeTicks time)
189 : url_(url), 178 : url_(url),
190 time_(time) { 179 time_(time) {
191 } 180 }
192 }; 181 };
193 182
194 PrerenderManager::PrerenderManager(Profile* profile, 183 PrerenderManager::PrerenderManager(Profile* profile,
(...skipping 13 matching lines...) Expand all
208 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 197 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
209 } 198 }
210 199
211 PrerenderManager::~PrerenderManager() { 200 PrerenderManager::~PrerenderManager() {
212 } 201 }
213 202
214 void PrerenderManager::Shutdown() { 203 void PrerenderManager::Shutdown() {
215 DoShutdown(); 204 DoShutdown();
216 } 205 }
217 206
218 bool PrerenderManager::AddPrerenderFromLinkRelPrerender( 207 base::WeakPtr<PrerenderHandle> PrerenderManager::AddPrerenderFromLinkRelPrerende r(
219 int process_id, 208 int process_id,
220 int route_id, 209 int route_id,
221 const GURL& url, 210 const GURL& url,
222 const content::Referrer& referrer, 211 const content::Referrer& referrer,
223 const gfx::Size& size) { 212 const gfx::Size& size) {
224 #if defined(OS_ANDROID) 213 #if defined(OS_ANDROID)
225 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable 214 // TODO(jcivelli): http://crbug.com/113322 We should have an option to disable
226 // link-prerender and enable omnibox-prerender only. 215 // link-prerender and enable omnibox-prerender only.
227 return false; 216 return false;
228 #else 217 #else
229 std::pair<int, int> child_route_id_pair(process_id, route_id); 218 if (PrerenderContents* parent_prerender_contents =
230 PrerenderContentsDataList::iterator it = 219 FindContentsForChildAndRoute(process_id, route_id)) {
231 FindPrerenderContentsForChildRouteIdPair(child_route_id_pair);
232 if (it != prerender_list_.end()) {
233 // Instead of prerendering from inside of a running prerender, we will defer 220 // Instead of prerendering from inside of a running prerender, we will defer
234 // this request until its launcher is made visible. 221 // this request until its launcher is made visible.
235 it->contents_->AddPendingPrerender(url, referrer, size); 222 scoped_ptr<PrerenderHandle> scoped_prerender_handle(new PrerenderHandle);
dominich 2012/06/22 15:36:16 Expected implementation: return parent_prerender_
236 return true; 223 base::WeakPtr<PrerenderHandle> prerender_handle =
224 scoped_prerender_handle.get()->AsWeakPtr();
225 parent_prerender_contents->AddPendingPrerender(
226 scoped_prerender_handle.Pass(), url, referrer, size);
227 return prerender_handle;
237 } 228 }
238 229
239 // Unit tests pass in a process_id == -1. 230 // Unit tests pass in a process_id == -1.
240 RenderViewHost* source_render_view_host = NULL; 231 RenderViewHost* source_render_view_host = NULL;
241 SessionStorageNamespace* session_storage_namespace = NULL; 232 SessionStorageNamespace* session_storage_namespace = NULL;
242 if (process_id != -1) { 233 if (process_id != -1) {
243 source_render_view_host = 234 source_render_view_host =
244 RenderViewHost::FromID(process_id, route_id); 235 RenderViewHost::FromID(process_id, route_id);
245 if (!source_render_view_host || !source_render_view_host->GetView()) 236 if (!source_render_view_host || !source_render_view_host->GetView())
246 return false; 237 return base::WeakPtr<PrerenderHandle>();
dominich 2012/06/22 15:36:16 return PrerenderHandle::kInvalidHandle; where kIn
247 session_storage_namespace = 238 session_storage_namespace =
248 source_render_view_host->GetSessionStorageNamespace(); 239 source_render_view_host->GetSessionStorageNamespace();
249 } 240 }
250 241
251 return AddPrerender(ORIGIN_LINK_REL_PRERENDER, 242 return AddPrerender(ORIGIN_LINK_REL_PRERENDER,
252 process_id, url, referrer, size, 243 process_id, url, referrer, size,
253 session_storage_namespace); 244 session_storage_namespace,
245 scoped_ptr<PrerenderHandle>());
254 #endif 246 #endif
255 } 247 }
256 248
257 bool PrerenderManager::AddPrerenderFromOmnibox( 249 base::WeakPtr<PrerenderHandle> PrerenderManager::AddPrerenderFromOmnibox(
258 const GURL& url, 250 const GURL& url,
259 SessionStorageNamespace* session_storage_namespace) { 251 SessionStorageNamespace* session_storage_namespace) {
260 if (!IsOmniboxEnabled(profile_)) 252 if (!IsOmniboxEnabled(profile_))
261 return false; 253 return base::WeakPtr<PrerenderHandle>();
262 return AddPrerender(ORIGIN_OMNIBOX, -1, url, 254 return AddPrerender(ORIGIN_OMNIBOX, -1, url,
263 content::Referrer(), gfx::Size(), 255 content::Referrer(), gfx::Size(),
264 session_storage_namespace); 256 session_storage_namespace,
257 scoped_ptr<PrerenderHandle>());
265 } 258 }
266 259
267 void PrerenderManager::MaybeCancelPrerender(const GURL& url) { 260 void PrerenderManager::StartPendingPrerender(
268 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url); 261 scoped_ptr<PrerenderHandle> existing_prerender_handle,
269 if (it == prerender_list_.end()) 262 int process_id,
270 return; 263 const GURL& url,
271 PrerenderContentsData& prerender_contents_data = *it; 264 const content::Referrer& referrer,
272 if (--prerender_contents_data.active_count_ == 0) 265 const gfx::Size& size,
273 prerender_contents_data.contents_->Destroy(FINAL_STATUS_CANCELLED); 266 content::SessionStorageNamespace* session_storage_namespace) {
267 DCHECK(existing_prerender_handle.get());
268 DCHECK(existing_prerender_handle->IsPending());
269 DCHECK(session_storage_namespace);
270 AddPrerender(ORIGIN_LINK_REL_PRERENDER,
dominich 2012/06/22 15:36:16 origin should have been tracked. We might start pe
271 process_id, url, referrer, size, session_storage_namespace,
272 existing_prerender_handle.Pass());
dominich 2012/06/22 15:36:16 ahah! Now I see the need for the existing prerende
274 } 273 }
275 274
276 void PrerenderManager::DestroyPrerenderForRenderView( 275 void PrerenderManager::DestroyPrerenderForRenderView(
277 int process_id, int view_id, FinalStatus final_status) { 276 int process_id, int view_id, FinalStatus final_status) {
278 DCHECK(CalledOnValidThread()); 277 DCHECK(CalledOnValidThread());
279 PrerenderContentsDataList::iterator it = 278 if (PrerenderContents* prerender_contents =
280 FindPrerenderContentsForChildRouteIdPair( 279 FindContentsForChildAndRoute(process_id, view_id)) {
281 std::make_pair(process_id, view_id));
282 if (it != prerender_list_.end()) {
283 PrerenderContents* prerender_contents = it->contents_;
284 prerender_contents->Destroy(final_status); 280 prerender_contents->Destroy(final_status);
285 } 281 }
286 } 282 }
287 283
288 void PrerenderManager::CancelAllPrerenders() { 284 void PrerenderManager::CancelAllPrerenders() {
289 DCHECK(CalledOnValidThread()); 285 DCHECK(CalledOnValidThread());
290 while (!prerender_list_.empty()) { 286 while (!prerender_map_.empty()) {
291 PrerenderContentsData data = prerender_list_.front(); 287 PrerenderContents* prerender_contents = prerender_map_.begin()->first;
292 DCHECK(data.contents_); 288 DCHECK_EQ(prerender_contents, prerender_map_.begin()->second->contents());
293 data.contents_->Destroy(FINAL_STATUS_CANCELLED); 289 prerender_contents->Destroy(FINAL_STATUS_CANCELLED);
294 } 290 }
295 } 291 }
296 292
297 void PrerenderManager::CancelOmniboxPrerenders() {
298 DCHECK(CalledOnValidThread());
299 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
300 it != prerender_list_.end(); ) {
301 PrerenderContentsDataList::iterator cur = it++;
302 if (cur->contents_->origin() == ORIGIN_OMNIBOX)
303 cur->contents_->Destroy(FINAL_STATUS_CANCELLED);
304 }
305 }
306
307 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents, 293 bool PrerenderManager::MaybeUsePrerenderedPage(WebContents* web_contents,
308 const GURL& url) { 294 const GURL& url) {
309 DCHECK(CalledOnValidThread()); 295 DCHECK(CalledOnValidThread());
310 DCHECK(!IsWebContentsPrerendering(web_contents)); 296 DCHECK(!IsWebContentsPrerendering(web_contents));
311 297
312 scoped_ptr<PrerenderContents> prerender_contents( 298 scoped_ptr<PrerenderContents> prerender_contents(
313 GetEntryButNotSpecifiedWC(url, web_contents)); 299 GetEntryButNotSpecifiedWC(url, web_contents));
314 if (prerender_contents.get() == NULL) 300 if (prerender_contents.get() == NULL)
315 return false; 301 return false;
316 302
317 // Do not use the prerendered version if there is an opener object. 303 // Do not use the prerendered version if there is an opener object.
318 if (web_contents->HasOpener()) { 304 if (web_contents->HasOpener()) {
319 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER); 305 prerender_contents.release()->Destroy(FINAL_STATUS_WINDOW_OPENER);
320 return false; 306 return false;
321 } 307 }
322 308
323 // Even if we match, the location.hash might be different. Record this as a
dominich 2012/06/22 15:36:16 The problem with fragment mismatch is that we don'
324 // separate final status.
325 GURL matching_url;
326 bool url_matches = prerender_contents->MatchesURL(url, &matching_url);
327 DCHECK(url_matches);
328 if (url_matches && url.ref() != matching_url.ref()) {
329 prerender_contents.release()->Destroy(FINAL_STATUS_FRAGMENT_MISMATCH);
330 return false;
331 }
332
333 // If we are just in the control group (which can be detected by noticing 309 // If we are just in the control group (which can be detected by noticing
334 // that prerendering hasn't even started yet), record that |web_contents| now 310 // that prerendering hasn't even started yet), record that |web_contents| now
335 // would be showing a prerendered contents, but otherwise, don't do anything. 311 // would be showing a prerendered contents, but otherwise, don't do anything.
336 if (!prerender_contents->prerendering_has_started()) { 312 if (!prerender_contents->prerendering_has_started()) {
337 MarkWebContentsAsWouldBePrerendered(web_contents); 313 MarkWebContentsAsWouldBePrerendered(web_contents);
338 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); 314 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED);
339 return false; 315 return false;
340 } 316 }
341 317
342 // Don't use prerendered pages if debugger is attached to the tab. 318 // Don't use prerendered pages if debugger is attached to the tab.
343 // See http://crbug.com/98541 319 // See http://crbug.com/98541
344 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) { 320 if (content::DevToolsAgentHostRegistry::IsDebuggerAttached(web_contents)) {
345 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(), 321 DestroyAndMarkMatchCompleteAsUsed(prerender_contents.release(),
346 FINAL_STATUS_DEVTOOLS_ATTACHED); 322 FINAL_STATUS_DEVTOOLS_ATTACHED);
347 return false; 323 return false;
348 } 324 }
349 325
350 // If the prerendered page is in the middle of a cross-site navigation, 326 // If the prerendered page is in the middle of a cross-site navigation,
351 // don't swap it in because there isn't a good way to merge histories. 327 // don't swap it in because there isn't a good way to merge histories.
352 if (prerender_contents->IsCrossSiteNavigationPending()) { 328 if (prerender_contents->IsCrossSiteNavigationPending()) {
353 DestroyAndMarkMatchCompleteAsUsed( 329 DestroyAndMarkMatchCompleteAsUsed(
354 prerender_contents.release(), 330 prerender_contents.release(),
355 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING); 331 FINAL_STATUS_CROSS_SITE_NAVIGATION_PENDING);
356 return false; 332 return false;
357 } 333 }
358 334
359 // If the session storage namespaces don't match, cancel the prerender.
360 RenderViewHost* old_render_view_host = web_contents->GetRenderViewHost();
361 RenderViewHost* new_render_view_host =
362 prerender_contents->prerender_contents()->web_contents()->
363 GetRenderViewHost();
364 DCHECK(old_render_view_host);
365 DCHECK(new_render_view_host);
366 if (old_render_view_host->GetSessionStorageNamespace() !=
367 new_render_view_host->GetSessionStorageNamespace()) {
368 DestroyAndMarkMatchCompleteAsUsed(
369 prerender_contents.release(),
370 FINAL_STATUS_SESSION_STORAGE_NAMESPACE_MISMATCH);
371 return false;
372 }
373
374 // If we don't want to use prerenders at all, we are done.
375 // For bookkeeping purposes, we need to mark this WebContents to 335 // For bookkeeping purposes, we need to mark this WebContents to
376 // reflect that it would have been prerendered. 336 // reflect that it would have been prerendered.
377 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) { 337 if (GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP) {
378 MarkWebContentsAsWouldBePrerendered(web_contents); 338 MarkWebContentsAsWouldBePrerendered(web_contents);
379 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED); 339 prerender_contents.release()->Destroy(FINAL_STATUS_WOULD_HAVE_BEEN_USED);
380 return false; 340 return false;
381 } 341 }
382 342
383 int child_id, route_id; 343 int child_id, route_id;
384 CHECK(prerender_contents->GetChildId(&child_id)); 344 CHECK(prerender_contents->GetChildId(&child_id));
385 CHECK(prerender_contents->GetRouteId(&route_id)); 345 CHECK(prerender_contents->GetRouteId(&route_id));
386 346
387 // Try to set the prerendered page as used, so any subsequent attempts to 347 // Try to set the prerendered page as used, so any subsequent attempts to
388 // cancel on other threads will fail. If this fails because the prerender 348 // cancel on other threads will fail. If this fails because the prerender
389 // was already cancelled, possibly on another thread, fail. 349 // was already cancelled, possibly on another thread, fail.
390 if (!prerender_tracker_->TryUse(child_id, route_id)) 350 if (!prerender_tracker_->TryUse(child_id, route_id))
391 return false; 351 return false;
392 352
393 if (!prerender_contents->load_start_time().is_null()) { 353 if (!prerender_contents->load_start_time().is_null()) {
394 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() - 354 histograms_->RecordTimeUntilUsed(GetCurrentTimeTicks() -
395 prerender_contents->load_start_time(), 355 prerender_contents->load_start_time(),
396 GetMaxAge()); 356 GetMaxAge());
397 } 357 }
398 358
399 histograms_->RecordPerSessionCount(++prerenders_per_session_count_); 359 histograms_->RecordPerSessionCount(++prerenders_per_session_count_);
400 histograms_->RecordUsedPrerender(prerender_contents->origin()); 360 histograms_->RecordUsedPrerender(prerender_contents->origin());
401 prerender_contents->set_final_status(FINAL_STATUS_USED); 361 prerender_contents->set_final_status(FINAL_STATUS_USED);
402 362
363 RenderViewHost* new_render_view_host =
364 prerender_contents->prerender_contents()->web_contents()->GetRenderViewHos t();
403 new_render_view_host->Send( 365 new_render_view_host->Send(
404 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(), 366 new PrerenderMsg_SetIsPrerendering(new_render_view_host->GetRoutingID(),
405 false)); 367 false));
406 368
407 TabContents* new_tab_contents = 369 TabContents* new_tab_contents =
408 prerender_contents->ReleasePrerenderContents(); 370 prerender_contents->ReleasePrerenderContents();
409 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents); 371 TabContents* old_tab_contents = TabContents::FromWebContents(web_contents);
410 DCHECK(new_tab_contents); 372 DCHECK(new_tab_contents);
411 DCHECK(old_tab_contents); 373 DCHECK(old_tab_contents);
412 374
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 } 421 }
460 422
461 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry, 423 void PrerenderManager::MoveEntryToPendingDelete(PrerenderContents* entry,
462 FinalStatus final_status) { 424 FinalStatus final_status) {
463 DCHECK(CalledOnValidThread()); 425 DCHECK(CalledOnValidThread());
464 DCHECK(entry); 426 DCHECK(entry);
465 // Confirm this entry has not already been moved to the pending delete list. 427 // Confirm this entry has not already been moved to the pending delete list.
466 DCHECK_EQ(0, std::count(pending_delete_list_.begin(), 428 DCHECK_EQ(0, std::count(pending_delete_list_.begin(),
467 pending_delete_list_.end(), entry)); 429 pending_delete_list_.end(), entry));
468 430
469 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 431 PrerenderHandleMap::iterator it = prerender_map_.find(entry);
470 it != prerender_list_.end(); 432 if (it == prerender_map_.end())
471 ++it) { 433 return;
472 if (it->contents_ == entry) {
473 bool swapped_in_dummy_replacement = false;
474 434
475 // If this PrerenderContents is being deleted due to a cancellation, 435 // If this PrerenderContents is being deleted due to a cancellation,
476 // we need to create a dummy replacement for PPLT accounting purposes 436 // we need to create a dummy replacement for PPLT accounting purposes
477 // for the Match Complete group. 437 // for the Match Complete group.
478 // This is the case if the cancellation is for any reason that would not 438 // This is the case if the cancellation is for any reason that would not
479 // occur in the control group case. 439 // occur in the control group case.
480 if (entry->match_complete_status() == 440 if (entry->match_complete_status() ==
481 PrerenderContents::MATCH_COMPLETE_DEFAULT && 441 PrerenderContents::MATCH_COMPLETE_DEFAULT &&
482 NeedMatchCompleteDummyForFinalStatus(final_status) && 442 NeedMatchCompleteDummyForFinalStatus(final_status) &&
483 ActuallyPrerendering()) { 443 ActuallyPrerendering()) {
484 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering. 444 // TODO(tburkard): I'd like to DCHECK that we are actually prerendering.
485 // However, what if new conditions are added and 445 // However, what if new conditions are added and
486 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure 446 // NeedMatchCompleteDummyForFinalStatus, is not being updated. Not sure
487 // what's the best thing to do here. For now, I will just check whether 447 // what's the best thing to do here. For now, I will just check whether
488 // we are actually prerendering. 448 // we are actually prerendering.
489 entry->set_match_complete_status( 449 entry->set_match_complete_status(
490 PrerenderContents::MATCH_COMPLETE_REPLACED); 450 PrerenderContents::MATCH_COMPLETE_REPLACED);
491 if (PrerenderContents* dummy_replacement_prerender_contents = 451 PrerenderContents*
492 CreatePrerenderContents(entry->prerender_url(), 452 dummy_replacement_prerender_contents = entry->CreateDummyReplacement();
493 entry->referrer(), 453 DCHECK(dummy_replacement_prerender_contents);
494 entry->origin(), 454
495 entry->experiment_id())) { 455 dummy_replacement_prerender_contents->set_match_complete_status(
496 dummy_replacement_prerender_contents->set_match_complete_status( 456 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING);
497 PrerenderContents::MATCH_COMPLETE_REPLACEMENT_PENDING); 457 DCHECK(dummy_replacement_prerender_contents->Init());
498 if (!dummy_replacement_prerender_contents->Init()) 458 dummy_replacement_prerender_contents->
499 break; 459 AddAliasURLsFromOtherPrerenderContents(entry);
500 dummy_replacement_prerender_contents-> 460 dummy_replacement_prerender_contents->set_match_complete_status(
501 AddAliasURLsFromOtherPrerenderContents(entry); 461 PrerenderContents::MATCH_COMPLETE_REPLACEMENT);
502 dummy_replacement_prerender_contents->set_match_complete_status( 462 prerender_map_.insert(std::make_pair(dummy_replacement_prerender_contents,
503 PrerenderContents::MATCH_COMPLETE_REPLACEMENT); 463 it->second));
504 it->contents_ = dummy_replacement_prerender_contents;
505 swapped_in_dummy_replacement = true;
506 }
507 }
508 if (!swapped_in_dummy_replacement)
509 prerender_list_.erase(it);
510 break;
511 }
512 } 464 }
465 prerender_map_.erase(it);
466
513 AddToHistory(entry); 467 AddToHistory(entry);
514 pending_delete_list_.push_back(entry); 468 pending_delete_list_.push_back(entry);
515 469
516 // Destroy the old WebContents relatively promptly to reduce resource usage, 470 // Destroy the old WebContents relatively promptly to reduce resource usage,
517 // and in the case of HTML5 media, reduce the change of playing any sound. 471 // and in the case of HTML5 media, reduce the change of playing any sound.
518 PostCleanupTask(); 472 PostCleanupTask();
519 } 473 }
520 474
521 // static 475 // static
522 void PrerenderManager::RecordPerceivedPageLoadTime( 476 void PrerenderManager::RecordPerceivedPageLoadTime(
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
613 } 567 }
614 568
615 // static 569 // static
616 bool PrerenderManager::IsNoUseGroup() { 570 bool PrerenderManager::IsNoUseGroup() {
617 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP; 571 return GetMode() == PRERENDER_MODE_EXPERIMENT_NO_USE_GROUP;
618 } 572 }
619 573
620 bool PrerenderManager::IsWebContentsPrerendering( 574 bool PrerenderManager::IsWebContentsPrerendering(
621 WebContents* web_contents) const { 575 WebContents* web_contents) const {
622 DCHECK(CalledOnValidThread()); 576 DCHECK(CalledOnValidThread());
623 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 577 for (PrerenderHandleMap::const_iterator it = prerender_map_.begin();
624 it != prerender_list_.end(); 578 it != prerender_map_.end();
625 ++it) { 579 ++it) {
626 TabContents* prerender_tab_contents = it->contents_->prerender_contents(); 580 TabContents* prerender_tab_contents = it->first->prerender_contents();
627 if (prerender_tab_contents && 581 if (prerender_tab_contents &&
628 prerender_tab_contents->web_contents() == web_contents) { 582 prerender_tab_contents->web_contents() == web_contents) {
629 return true; 583 return true;
630 } 584 }
631 } 585 }
632 586
633 // Also look through the pending-deletion list. 587 // Also look through the pending-deletion list.
634 for (std::list<PrerenderContents*>::const_iterator it = 588 for (std::list<PrerenderContents*>::const_iterator it =
635 pending_delete_list_.begin(); 589 pending_delete_list_.begin();
636 it != pending_delete_list_.end(); 590 it != pending_delete_list_.end();
637 ++it) { 591 ++it) {
638 TabContents* prerender_tab_contents = (*it)->prerender_contents(); 592 TabContents* prerender_tab_contents = (*it)->prerender_contents();
639 if (prerender_tab_contents && 593 if (prerender_tab_contents &&
640 prerender_tab_contents->web_contents() == web_contents) 594 prerender_tab_contents->web_contents() == web_contents)
641 return true; 595 return true;
642 } 596 }
643 597
644 return false; 598 return false;
645 } 599 }
646 600
647 bool PrerenderManager::DidPrerenderFinishLoading(const GURL& url) const {
648 DCHECK(CalledOnValidThread());
649 PrerenderContents* contents = FindEntry(url);
650 return contents ? contents->has_finished_loading() : false;
651 }
652
653 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) { 601 void PrerenderManager::MarkWebContentsAsPrerendered(WebContents* web_contents) {
654 DCHECK(CalledOnValidThread()); 602 DCHECK(CalledOnValidThread());
655 prerendered_tab_contents_set_.insert(web_contents); 603 prerendered_tab_contents_set_.insert(web_contents);
656 } 604 }
657 605
658 void PrerenderManager::MarkWebContentsAsWouldBePrerendered( 606 void PrerenderManager::MarkWebContentsAsWouldBePrerendered(
659 WebContents* web_contents) { 607 WebContents* web_contents) {
660 DCHECK(CalledOnValidThread()); 608 DCHECK(CalledOnValidThread());
661 would_be_prerendered_map_[web_contents] = true; 609 would_be_prerendered_map_[web_contents] = true;
662 } 610 }
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
758 histograms_->RecordFinalStatus(origin, 706 histograms_->RecordFinalStatus(origin,
759 experiment_id, 707 experiment_id,
760 mc_status, 708 mc_status,
761 final_status); 709 final_status);
762 } 710 }
763 711
764 void PrerenderManager::AddCondition(const PrerenderCondition* condition) { 712 void PrerenderManager::AddCondition(const PrerenderCondition* condition) {
765 prerender_conditions_.push_back(condition); 713 prerender_conditions_.push_back(condition);
766 } 714 }
767 715
768 bool PrerenderManager::IsPendingEntry(const GURL& url) const {
769 DCHECK(CalledOnValidThread());
770 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
771 it != prerender_list_.end();
772 ++it) {
773 if (it->contents_->IsPendingEntry(url))
774 return true;
775 }
776 return false;
777 }
778
779 bool PrerenderManager::IsPrerendering(const GURL& url) const {
780 DCHECK(CalledOnValidThread());
781 return (FindEntry(url) != NULL);
782 }
783
784 void PrerenderManager::RecordNavigation(const GURL& url) { 716 void PrerenderManager::RecordNavigation(const GURL& url) {
785 DCHECK(CalledOnValidThread()); 717 DCHECK(CalledOnValidThread());
786 718
787 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks())); 719 navigations_.push_back(NavigationRecord(url, GetCurrentTimeTicks()));
788 CleanUpOldNavigations(); 720 CleanUpOldNavigations();
789 } 721 }
790 722
791 // protected 723 // protected
792 void PrerenderManager::SetPrerenderContentsFactory( 724 void PrerenderManager::SetPrerenderContentsFactory(
793 PrerenderContents::Factory* prerender_contents_factory) { 725 PrerenderContents::Factory* prerender_contents_factory) {
794 DCHECK(CalledOnValidThread()); 726 DCHECK(CalledOnValidThread());
795 prerender_contents_factory_.reset(prerender_contents_factory); 727 prerender_contents_factory_.reset(prerender_contents_factory);
796 } 728 }
797 729
798 void PrerenderManager::DoShutdown() { 730 void PrerenderManager::DoShutdown() {
799 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN); 731 DestroyAllContents(FINAL_STATUS_MANAGER_SHUTDOWN);
800 STLDeleteElements(&prerender_conditions_); 732 STLDeleteElements(&prerender_conditions_);
801 on_close_tab_contents_deleters_.reset(); 733 on_close_tab_contents_deleters_.reset();
802 profile_ = NULL; 734 profile_ = NULL;
803 } 735 }
804 736
737 PrerenderContents* PrerenderManager::FindEntry(
738 const GURL& url) {
739 if (PrerenderHandle* handle = FindHandle(url, NULL))
740 return handle->contents();
741 return NULL;
742 }
743
805 // private 744 // private
806 bool PrerenderManager::AddPrerender( 745 base::WeakPtr<PrerenderHandle> PrerenderManager::AddPrerender(
807 Origin origin, 746 Origin origin,
808 int process_id, 747 int process_id,
809 const GURL& url_arg, 748 const GURL& url_arg,
810 const content::Referrer& referrer, 749 const content::Referrer& referrer,
811 const gfx::Size& size, 750 const gfx::Size& size,
812 SessionStorageNamespace* session_storage_namespace) { 751 SessionStorageNamespace* session_storage_namespace,
752 scoped_ptr<PrerenderHandle> preexisting_prerender_handle) {
813 DCHECK(CalledOnValidThread()); 753 DCHECK(CalledOnValidThread());
814 754
755 // Take ownership of preeexisting_prerender_handle immediately if it was
756 // provided, otherwise create a new PrerenderHandle to own so we don't have
757 // special cases for early exits depending on if preexisting_prerender_handle
758 // was provided.
759 scoped_ptr<PrerenderHandle>
760 scoped_prerender_handle = preexisting_prerender_handle.Pass();
761 if (!scoped_prerender_handle.get())
762 scoped_prerender_handle.reset(new PrerenderHandle);
763 DCHECK(!scoped_prerender_handle->contents());
764 base::WeakPtr<PrerenderHandle> prerender_handle =
765 scoped_prerender_handle->AsWeakPtr();
766
815 if (!IsEnabled()) 767 if (!IsEnabled())
816 return false; 768 return base::WeakPtr<PrerenderHandle>();
817 769
818 if (origin == ORIGIN_LINK_REL_PRERENDER && 770 if (origin == ORIGIN_LINK_REL_PRERENDER &&
819 IsGoogleSearchResultURL(referrer.url)) { 771 IsGoogleSearchResultURL(referrer.url)) {
820 origin = ORIGIN_GWS_PRERENDER; 772 origin = ORIGIN_GWS_PRERENDER;
821 } 773 }
822 774
823 DeleteOldEntries(); 775 DeleteOldEntries();
824 DeletePendingDeleteEntries(); 776 DeletePendingDeleteEntries();
825 777
826 GURL url = url_arg; 778 GURL url = url_arg;
827 GURL alias_url; 779 GURL alias_url;
828 uint8 experiment = GetQueryStringBasedExperiment(url_arg); 780 uint8 experiment = GetQueryStringBasedExperiment(url_arg);
829 bool control_group_behavior = 781 bool control_group_behavior =
830 IsControlGroup() || IsControlGroupExperiment(experiment); 782 IsControlGroup() || IsControlGroupExperiment(experiment);
831 if (control_group_behavior && 783 if (control_group_behavior &&
832 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) { 784 MaybeGetQueryStringBasedAliasURL(url, &alias_url)) {
833 url = alias_url; 785 url = alias_url;
834 } 786 }
835 787
836 // From here on, we will record a FinalStatus so we need to register with the 788 // From here on, we will record a FinalStatus so we need to register with the
837 // histogram tracking. 789 // histogram tracking.
838 histograms_->RecordPrerender(origin, url_arg); 790 histograms_->RecordPrerender(origin, url_arg);
839 791
840 if (PrerenderContentsData* prerender_contents_data = FindEntryData(url)) { 792 if (PrerenderHandle* preexisting_prerender_handle =
841 ++prerender_contents_data->active_count_; 793 FindHandle(url, session_storage_namespace)) {
842 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE); 794 RecordFinalStatus(origin, experiment, FINAL_STATUS_DUPLICATE);
843 return true; 795 preexisting_prerender_handle->AddDuplicate(scoped_prerender_handle.Pass());
796 return prerender_handle;
844 } 797 }
845 798
846 // Do not prerender if there are too many render processes, and we would 799 // Do not prerender if there are too many render processes, and we would
847 // have to use an existing one. We do not want prerendering to happen in 800 // have to use an existing one. We do not want prerendering to happen in
848 // a shared process, so that we can always reliably lower the CPU 801 // a shared process, so that we can always reliably lower the CPU
849 // priority for prerendering. 802 // priority for prerendering.
850 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns 803 // In single-process mode, ShouldTryToUseExistingProcessHost() always returns
851 // true, so that case needs to be explicitly checked for. 804 // true, so that case needs to be explicitly checked for.
852 // TODO(tburkard): Figure out how to cancel prerendering in the opposite 805 // TODO(tburkard): Figure out how to cancel prerendering in the opposite
853 // case, when a new tab is added to a process used for prerendering. 806 // case, when a new tab is added to a process used for prerendering.
854 // On Android we do reuse processes as we have a limited number of them and we 807 // On Android we do reuse processes as we have a limited number of them and we
855 // still want the benefits of prerendering even when several tabs are open. 808 // still want the benefits of prerendering even when several tabs are open.
856 #if !defined(OS_ANDROID) 809 #if !defined(OS_ANDROID)
857 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost( 810 if (content::RenderProcessHost::ShouldTryToUseExistingProcessHost(
858 profile_, url) && 811 profile_, url) &&
859 !content::RenderProcessHost::run_renderer_in_process()) { 812 !content::RenderProcessHost::run_renderer_in_process()) {
860 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES); 813 RecordFinalStatus(origin, experiment, FINAL_STATUS_TOO_MANY_PROCESSES);
861 return false; 814 // TODO: duplicates holding zone?
815 return base::WeakPtr<PrerenderHandle>();
862 } 816 }
863 #endif 817 #endif
864 818
865 // Check if enough time has passed since the last prerender. 819 // Check if enough time has passed since the last prerender.
866 if (!DoesRateLimitAllowPrerender()) { 820 if (!DoesRateLimitAllowPrerender()) {
867 // Cancel the prerender. We could add it to the pending prerender list but 821 // Cancel the prerender. We could add it to the pending prerender list but
868 // this doesn't make sense as the next prerender request will be triggered 822 // this doesn't make sense as the next prerender request will be triggered
869 // by a navigation and is unlikely to be the same site. 823 // by a navigation and is unlikely to be the same site.
870 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED); 824 RecordFinalStatus(origin, experiment, FINAL_STATUS_RATE_LIMIT_EXCEEDED);
871 return false; 825 return base::WeakPtr<PrerenderHandle>();
872 } 826 }
873 827
874 PrerenderContents* prerender_contents = CreatePrerenderContents( 828 PrerenderContents* prerender_contents = CreatePrerenderContents(
875 url, referrer, origin, experiment); 829 url, referrer, origin, experiment);
876 if (!prerender_contents || !prerender_contents->Init()) 830 if (!prerender_contents || !prerender_contents->Init())
877 return false; 831 return base::WeakPtr<PrerenderHandle>();
878 832
879 histograms_->RecordPrerenderStarted(origin); 833 histograms_->RecordPrerenderStarted(origin);
880 834
881 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents? 835 // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
882 PrerenderContentsData data(prerender_contents, GetCurrentTime()); 836 scoped_prerender_handle->SetContents(prerender_contents);
883 837 prerender_map_.insert(
884 prerender_list_.push_back(data); 838 std::make_pair(prerender_contents,
839 make_linked_ptr(scoped_prerender_handle.release())));
885 840
886 last_prerender_start_time_ = GetCurrentTimeTicks(); 841 last_prerender_start_time_ = GetCurrentTimeTicks();
887 842
888 data.contents_->StartPrerendering(process_id, size, session_storage_namespace, 843 prerender_contents->StartPrerendering(process_id, size, session_storage_namesp ace,
889 control_group_behavior); 844 control_group_behavior);
890 845
891 while (prerender_list_.size() > config_.max_elements) { 846 while (prerender_map_.size() > config_.max_elements) {
892 data = prerender_list_.front(); 847 prerender_contents = prerender_map_.begin()->first;
893 prerender_list_.pop_front(); 848 DCHECK(prerender_contents);
894 data.contents_->Destroy(FINAL_STATUS_EVICTED); 849 const size_t old_size = prerender_map_.size();
850 prerender_contents->Destroy(FINAL_STATUS_EVICTED);
851 DCHECK_GT(old_size, prerender_map_.size());
895 } 852 }
853
896 StartSchedulingPeriodicCleanups(); 854 StartSchedulingPeriodicCleanups();
897 return true; 855 return prerender_handle;
898 } 856 }
899 857
900 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) { 858 PrerenderContents* PrerenderManager::GetEntry(const GURL& url) {
901 return GetEntryButNotSpecifiedWC(url, NULL); 859 return GetEntryButNotSpecifiedWC(url, NULL);
902 } 860 }
903 861
904 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC( 862 PrerenderContents* PrerenderManager::GetEntryButNotSpecifiedWC(
905 const GURL& url, 863 const GURL& url,
906 WebContents* wc) { 864 WebContents* web_contents) {
907 DCHECK(CalledOnValidThread()); 865 DCHECK(CalledOnValidThread());
908 DeleteOldEntries(); 866 DeleteOldEntries();
909 DeletePendingDeleteEntries(); 867 DeletePendingDeleteEntries();
910 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 868
911 it != prerender_list_.end(); 869 SessionStorageNamespace* session_storage_namespace = NULL;
870 if (web_contents) {
871 DCHECK(web_contents->GetRenderViewHost());
872 session_storage_namespace =
873 web_contents->GetRenderViewHost()->GetSessionStorageNamespace();
874 DCHECK(session_storage_namespace);
875 }
876
877 for (PrerenderHandleMap::iterator it = prerender_map_.begin();
878 it != prerender_map_.end();
912 ++it) { 879 ++it) {
913 PrerenderContents* prerender_contents = it->contents_; 880 PrerenderContents* prerender_contents = it->first;
914 if (prerender_contents->MatchesURL(url, NULL) && 881 if (!prerender_contents->Matches(url, session_storage_namespace) ||
915 !IsNoSwapInExperiment(prerender_contents->experiment_id())) { 882 IsNoSwapInExperiment(prerender_contents->experiment_id())) {
916 if (!prerender_contents->prerender_contents() || 883 break;
917 !wc || 884 }
918 prerender_contents->prerender_contents()->web_contents() != wc) { 885
919 prerender_list_.erase(it); 886 TabContents* tab_contents = prerender_contents->prerender_contents();
920 return prerender_contents; 887 if (!tab_contents || !web_contents ||
921 } 888 tab_contents->web_contents() != web_contents) {
889 PrerenderHandle* prerender_handle = it->second.get();
890 prerender_handle->SetContents(NULL);
891 prerender_map_.erase(it);
892 return prerender_contents;
922 } 893 }
923 } 894 }
924 // Entry not found. 895 // Entry not found.
925 return NULL; 896 return NULL;
926 } 897 }
927 898
928 void PrerenderManager::StartSchedulingPeriodicCleanups() { 899 void PrerenderManager::StartSchedulingPeriodicCleanups() {
929 DCHECK(CalledOnValidThread()); 900 DCHECK(CalledOnValidThread());
930 if (repeating_timer_.IsRunning()) 901 if (repeating_timer_.IsRunning())
931 return; 902 return;
932 repeating_timer_.Start(FROM_HERE, 903 repeating_timer_.Start(FROM_HERE,
933 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs), 904 base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs),
934 this, 905 this,
935 &PrerenderManager::PeriodicCleanup); 906 &PrerenderManager::PeriodicCleanup);
936 } 907 }
937 908
938 void PrerenderManager::MaybeStopSchedulingPeriodicCleanups() { 909 void PrerenderManager::StopSchedulingPeriodicCleanups() {
939 if (!prerender_list_.empty())
940 return;
941
942 DCHECK(CalledOnValidThread()); 910 DCHECK(CalledOnValidThread());
943 repeating_timer_.Stop(); 911 repeating_timer_.Stop();
944 } 912 }
945 913
946 void PrerenderManager::PeriodicCleanup() { 914 void PrerenderManager::PeriodicCleanup() {
947 DCHECK(CalledOnValidThread()); 915 DCHECK(CalledOnValidThread());
948 DeleteOldTabContents(); 916 DeleteOldTabContents();
949 DeleteOldEntries(); 917 DeleteOldEntries();
918 if (prerender_map_.empty())
919 StopSchedulingPeriodicCleanups();
950 920
951 // Grab a copy of the current PrerenderContents pointers, so that we 921 // Grab a copy of the current PrerenderContents pointers, so that we
952 // will not interfere with potential deletions of the list. 922 // will not interfere with potential deletions of the list.
953 std::vector<PrerenderContents*> prerender_contents; 923 std::vector<PrerenderContents*> prerender_contents;
954 for (PrerenderContentsDataList::iterator it = prerender_list_.begin(); 924 for (PrerenderHandleMap::iterator it = prerender_map_.begin();
955 it != prerender_list_.end(); 925 it != prerender_map_.end();
956 ++it) { 926 ++it) {
957 DCHECK(it->contents_); 927 DCHECK(it->first);
958 prerender_contents.push_back(it->contents_); 928 prerender_contents.push_back(it->first);
959 } 929 }
960 for (std::vector<PrerenderContents*>::iterator it = 930 for (std::vector<PrerenderContents*>::iterator it =
961 prerender_contents.begin(); 931 prerender_contents.begin();
962 it != prerender_contents.end(); 932 it != prerender_contents.end();
963 ++it) { 933 ++it) {
964 (*it)->DestroyWhenUsingTooManyResources(); 934 (*it)->DestroyWhenUsingTooManyResources();
965 } 935 }
966 936
967 DeletePendingDeleteEntries(); 937 DeletePendingDeleteEntries();
968 } 938 }
969 939
970 void PrerenderManager::PostCleanupTask() { 940 void PrerenderManager::PostCleanupTask() {
971 DCHECK(CalledOnValidThread()); 941 DCHECK(CalledOnValidThread());
972 MessageLoop::current()->PostTask( 942 MessageLoop::current()->PostTask(
973 FROM_HERE, 943 FROM_HERE,
974 base::Bind(&PrerenderManager::PeriodicCleanup, 944 base::Bind(&PrerenderManager::PeriodicCleanup,
975 weak_factory_.GetWeakPtr())); 945 weak_factory_.GetWeakPtr()));
976 } 946 }
977 947
978 base::TimeDelta PrerenderManager::GetMaxAge() const { 948 base::TimeDelta PrerenderManager::GetMaxAge() const {
979 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ? 949 return (GetMode() == PRERENDER_MODE_EXPERIMENT_5MIN_TTL_GROUP ?
980 base::TimeDelta::FromSeconds(300) : config_.max_age); 950 base::TimeDelta::FromSeconds(300) : config_.max_age);
981 } 951 }
982 952
983 bool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const { 953 bool PrerenderManager::IsPrerenderFresh(base::TimeTicks start) const {
984 DCHECK(CalledOnValidThread()); 954 DCHECK(CalledOnValidThread());
985 base::Time now = GetCurrentTime(); 955 base::TimeTicks now = GetCurrentTimeTicks();
986 return (now - start < GetMaxAge()); 956 return now - start < GetMaxAge();
987 } 957 }
988 958
989 void PrerenderManager::DeleteOldEntries() { 959 void PrerenderManager::DeleteOldEntries() {
990 DCHECK(CalledOnValidThread()); 960 DCHECK(CalledOnValidThread());
991 while (!prerender_list_.empty()) { 961
992 PrerenderContentsData data = prerender_list_.front(); 962 while (!prerender_map_.empty()) {
993 if (IsPrerenderElementFresh(data.start_time_)) 963 PrerenderContents* contents = prerender_map_.begin()->first;
964 DCHECK(contents);
965 if (IsPrerenderFresh(contents->load_start_time()))
994 return; 966 return;
995 data.contents_->Destroy(FINAL_STATUS_TIMED_OUT); 967 contents->Destroy(FINAL_STATUS_TIMED_OUT);
996 } 968 }
997 MaybeStopSchedulingPeriodicCleanups();
998 } 969 }
999 970
1000 base::Time PrerenderManager::GetCurrentTime() const { 971 base::Time PrerenderManager::GetCurrentTime() const {
1001 return base::Time::Now(); 972 return base::Time::Now();
1002 } 973 }
1003 974
1004 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const { 975 base::TimeTicks PrerenderManager::GetCurrentTimeTicks() const {
1005 return base::TimeTicks::Now(); 976 return base::TimeTicks::Now();
1006 } 977 }
1007 978
1008 PrerenderContents* PrerenderManager::CreatePrerenderContents( 979 PrerenderContents* PrerenderManager::CreatePrerenderContents(
1009 const GURL& url, 980 const GURL& url,
1010 const content::Referrer& referrer, 981 const content::Referrer& referrer,
1011 Origin origin, 982 Origin origin,
1012 uint8 experiment_id) { 983 uint8 experiment_id) {
1013 DCHECK(CalledOnValidThread()); 984 DCHECK(CalledOnValidThread());
1014 return prerender_contents_factory_->CreatePrerenderContents( 985 return prerender_contents_factory_->CreatePrerenderContents(
1015 this, prerender_tracker_, profile_, url, 986 this, prerender_tracker_, profile_, url,
1016 referrer, origin, experiment_id); 987 referrer, origin, experiment_id);
1017 } 988 }
1018 989
1019 void PrerenderManager::DeletePendingDeleteEntries() { 990 void PrerenderManager::DeletePendingDeleteEntries() {
1020 while (!pending_delete_list_.empty()) { 991 while (!pending_delete_list_.empty()) {
1021 PrerenderContents* contents = pending_delete_list_.front(); 992 PrerenderContents* contents = pending_delete_list_.front();
1022 pending_delete_list_.pop_front(); 993 pending_delete_list_.pop_front();
1023 delete contents; 994 delete contents;
1024 } 995 }
1025 } 996 }
1026 997
1027 PrerenderManager::PrerenderContentsData* PrerenderManager::FindEntryData( 998 PrerenderHandle* PrerenderManager::FindHandle(
1028 const GURL& url) { 999 const GURL& url,
1029 DCHECK(CalledOnValidThread()); 1000 const SessionStorageNamespace* session_storage_namespace) {
1030 PrerenderContentsDataList::iterator it = FindPrerenderContentsForURL(url); 1001 for (PrerenderHandleMap::iterator it = prerender_map_.begin();
1031 if (it == prerender_list_.end()) 1002 it != prerender_map_.end();
1032 return NULL;
1033 PrerenderContentsData& prerender_contents_data = *it;
1034 return &prerender_contents_data;
1035 }
1036
1037 PrerenderContents* PrerenderManager::FindEntry(const GURL& url) const {
1038 DCHECK(CalledOnValidThread());
1039 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin();
1040 it != prerender_list_.end();
1041 ++it) { 1003 ++it) {
1042 if (it->contents_->MatchesURL(url, NULL)) 1004 PrerenderContents* prerender_contents = it->first;
1043 return it->contents_; 1005 if (prerender_contents->Matches(url, session_storage_namespace))
1006 return it->second.get();
1044 } 1007 }
1045 // Entry not found.
1046 return NULL; 1008 return NULL;
1047 } 1009 }
1048 1010
1049 PrerenderManager::PrerenderContentsDataList::iterator 1011 PrerenderContents* PrerenderManager::FindContentsForChildAndRoute(
1050 PrerenderManager::FindPrerenderContentsForChildRouteIdPair( 1012 const int child_id, const int route_id) {
1051 const std::pair<int, int>& child_route_id_pair) { 1013 PrerenderHandleMap::iterator it = prerender_map_.begin();
1052 PrerenderContentsDataList::iterator it = prerender_list_.begin(); 1014 for (; it != prerender_map_.end(); ++it) {
1053 for (; it != prerender_list_.end(); ++it) { 1015 PrerenderContents* prerender_contents = it->first;
1054 PrerenderContents* prerender_contents = it->contents_;
1055 1016
1056 int child_id; 1017 int contents_child_id;
1057 int route_id; 1018 if (!prerender_contents->GetChildId(&contents_child_id))
1058 bool has_child_id = prerender_contents->GetChildId(&child_id); 1019 continue;
1059 bool has_route_id = has_child_id && 1020 int contents_route_id;
1060 prerender_contents->GetRouteId(&route_id); 1021 if (!prerender_contents->GetRouteId(&contents_route_id))
1022 continue;
1061 1023
1062 if (has_child_id && has_route_id && 1024 if (contents_child_id == child_id && contents_route_id == route_id)
1063 child_id == child_route_id_pair.first && 1025 return it->first;
1064 route_id == child_route_id_pair.second) {
1065 break;
1066 }
1067 } 1026 }
1068 return it; 1027 return NULL;
1069 }
1070
1071 PrerenderManager::PrerenderContentsDataList::iterator
1072 PrerenderManager::FindPrerenderContentsForURL(const GURL& url) {
1073 for (PrerenderContentsDataList::iterator it = prerender_list_.begin();
1074 it != prerender_list_.end(); ++it) {
1075 if (it->contents_->MatchesURL(url, NULL))
1076 return it;
1077 }
1078 return prerender_list_.end();
1079 } 1028 }
1080 1029
1081 bool PrerenderManager::DoesRateLimitAllowPrerender() const { 1030 bool PrerenderManager::DoesRateLimitAllowPrerender() const {
1082 DCHECK(CalledOnValidThread()); 1031 DCHECK(CalledOnValidThread());
1083 base::TimeDelta elapsed_time = 1032 base::TimeDelta elapsed_time =
1084 GetCurrentTimeTicks() - last_prerender_start_time_; 1033 GetCurrentTimeTicks() - last_prerender_start_time_;
1085 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time); 1034 histograms_->RecordTimeBetweenPrerenderRequests(elapsed_time);
1086 if (!config_.rate_limit_enabled) 1035 if (!config_.rate_limit_enabled)
1087 return true; 1036 return true;
1088 return elapsed_time > 1037 return elapsed_time >
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
1130 void PrerenderManager::AddToHistory(PrerenderContents* contents) { 1079 void PrerenderManager::AddToHistory(PrerenderContents* contents) {
1131 PrerenderHistory::Entry entry(contents->prerender_url(), 1080 PrerenderHistory::Entry entry(contents->prerender_url(),
1132 contents->final_status(), 1081 contents->final_status(),
1133 contents->origin(), 1082 contents->origin(),
1134 base::Time::Now()); 1083 base::Time::Now());
1135 prerender_history_->AddEntry(entry); 1084 prerender_history_->AddEntry(entry);
1136 } 1085 }
1137 1086
1138 Value* PrerenderManager::GetActivePrerendersAsValue() const { 1087 Value* PrerenderManager::GetActivePrerendersAsValue() const {
1139 ListValue* list_value = new ListValue(); 1088 ListValue* list_value = new ListValue();
1140 for (PrerenderContentsDataList::const_iterator it = prerender_list_.begin(); 1089 for (PrerenderHandleMap::const_iterator it = prerender_map_.begin();
1141 it != prerender_list_.end(); 1090 it != prerender_map_.end();
1142 ++it) { 1091 ++it) {
1143 Value* prerender_value = it->contents_->GetAsValue(); 1092 Value* prerender_value = it->first->GetAsValue();
1144 if (!prerender_value) 1093 if (prerender_value)
1145 continue; 1094 list_value->Append(prerender_value);
1146 list_value->Append(prerender_value);
1147 } 1095 }
1148 return list_value; 1096 return list_value;
1149 } 1097 }
1150 1098
1151 void PrerenderManager::DestroyAllContents(FinalStatus final_status) { 1099 void PrerenderManager::DestroyAllContents(FinalStatus final_status) {
1152 DeleteOldTabContents(); 1100 DeleteOldTabContents();
1153 while (!prerender_list_.empty()) { 1101 while (!prerender_map_.empty()) {
1154 PrerenderContentsData data = prerender_list_.front(); 1102 PrerenderContents* contents = prerender_map_.begin()->first;
1155 prerender_list_.pop_front(); 1103 const size_t old_size = prerender_map_.size();
1156 data.contents_->Destroy(final_status); 1104 contents->Destroy(final_status);
1105 DCHECK_GT(old_size, prerender_map_.size());
1157 } 1106 }
1158 DeletePendingDeleteEntries(); 1107 DeletePendingDeleteEntries();
1159 } 1108 }
1160 1109
1161 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed( 1110 void PrerenderManager::DestroyAndMarkMatchCompleteAsUsed(
1162 PrerenderContents* prerender_contents, 1111 PrerenderContents* prerender_contents,
1163 FinalStatus final_status) { 1112 FinalStatus final_status) {
1164 prerender_contents->set_match_complete_status( 1113 prerender_contents->set_match_complete_status(
1165 PrerenderContents::MATCH_COMPLETE_REPLACED); 1114 PrerenderContents::MATCH_COMPLETE_REPLACED);
1166 histograms_->RecordFinalStatus(prerender_contents->origin(), 1115 histograms_->RecordFinalStatus(prerender_contents->origin(),
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1205 if (!render_process_host || !render_process_host->GetBrowserContext()) 1154 if (!render_process_host || !render_process_host->GetBrowserContext())
1206 return NULL; 1155 return NULL;
1207 Profile* profile = Profile::FromBrowserContext( 1156 Profile* profile = Profile::FromBrowserContext(
1208 render_process_host->GetBrowserContext()); 1157 render_process_host->GetBrowserContext());
1209 if (!profile) 1158 if (!profile)
1210 return NULL; 1159 return NULL;
1211 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile); 1160 return PrerenderManagerFactory::GetInstance()->GetForProfile(profile);
1212 } 1161 }
1213 1162
1214 } // namespace prerender 1163 } // namespace prerender
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698