172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// Use of this source code is governed by a BSD-style license that can be
321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen// found in the LICENSE file.
421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/prerender/prerender_manager.h"
621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/logging.h"
8ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/metrics/field_trial.h"
972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/metrics/histogram.h"
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/time.h"
1121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/utf_string_conversions.h"
1221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/prerender/prerender_contents.h"
13dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "chrome/browser/prerender/prerender_final_status.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/profiles/profile.h"
15dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
16dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_view_host.h"
17dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/renderer_host/render_process_host.h"
18ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/renderer_host/resource_dispatcher_host.h"
19dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/tab_contents/render_view_host_manager.h"
20ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/browser/tab_contents/tab_contents.h"
21ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
22ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/view_messages.h"
23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "googleurl/src/url_parse.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "googleurl/src/url_canon.h"
25ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "googleurl/src/url_util.h"
26dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsennamespace prerender {
2872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
2972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenint PrerenderManager::prerenders_per_session_count_ = 0;
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
32ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
3372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenbase::TimeTicks PrerenderManager::last_prefetch_seen_time_;
3472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
3572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
3672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenPrerenderManager::PrerenderManagerMode PrerenderManager::mode_ =
3772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    PRERENDER_MODE_ENABLED;
3872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
3972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
4072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenPrerenderManager::PrerenderManagerMode PrerenderManager::GetMode() {
4172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return mode_;
4272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
4372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
4472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
4572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid PrerenderManager::SetMode(PrerenderManagerMode mode) {
4672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  mode_ = mode;
4772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
4872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
4972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen// static
50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PrerenderManager::IsPrerenderingPossible() {
5172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return
5272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      GetMode() == PRERENDER_MODE_ENABLED ||
53ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetMode() == PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP ||
54ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP;
55ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
56ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
57ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
58ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PrerenderManager::IsControlGroup() {
59ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return GetMode() == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP;
60ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
61ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
62ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// static
63ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PrerenderManager::MaybeGetQueryStringBasedAliasURL(
64ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const GURL& url, GURL* alias_url) {
65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(alias_url);
66ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  url_parse::Parsed parsed;
67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  url_parse::ParseStandardURL(url.spec().c_str(), url.spec().length(),
68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                              &parsed);
69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  url_parse::Component query = parsed.query;
70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  url_parse::Component key, value;
71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  while (url_parse::ExtractQueryKeyValue(url.spec().c_str(), &query, &key,
72ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                         &value)) {
73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (key.len != 3 || strncmp(url.spec().c_str() + key.begin, "url", key.len))
74ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
75ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // We found a url= query string component.
76ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (value.len < 1)
77ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      continue;
78ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    url_canon::RawCanonOutputW<1024> decoded_url;
79ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    url_util::DecodeURLEscapeSequences(url.spec().c_str() + value.begin,
80ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                       value.len, &decoded_url);
81ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    GURL new_url(string16(decoded_url.data(), decoded_url.length()));
82ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!new_url.is_empty() && new_url.is_valid()) {
83ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      *alias_url = new_url;
84ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      return true;
85ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
86ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
87ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
88ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return false;
8972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
9021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
9121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstruct PrerenderManager::PrerenderContentsData {
9221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  PrerenderContents* contents_;
9321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::Time start_time_;
94dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  PrerenderContentsData(PrerenderContents* contents, base::Time start_time)
9521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      : contents_(contents),
96dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen        start_time_(start_time) {
9721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
9821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen};
9921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
100ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenstruct PrerenderManager::PendingContentsData {
101ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PendingContentsData(const GURL& url, const std::vector<GURL>& alias_urls,
102ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                      const GURL& referrer)
103ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      : url_(url), alias_urls_(alias_urls), referrer_(referrer) { }
104ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ~PendingContentsData() {}
105ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GURL url_;
106ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<GURL> alias_urls_;
107ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GURL referrer_;
108ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen};
109ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
110ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
11121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenPrerenderManager::PrerenderManager(Profile* profile)
112ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    : rate_limit_enabled_(true),
113ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      enabled_(true),
114ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      profile_(profile),
11521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      max_prerender_age_(base::TimeDelta::FromSeconds(
11621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          kDefaultMaxPrerenderAgeSeconds)),
11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      max_elements_(kDefaultMaxPrerenderElements),
118ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      prerender_contents_factory_(PrerenderContents::CreateFactory()),
119ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      last_prerender_start_time_(GetCurrentTimeTicks() -
120ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs)) {
12121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
12221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
12321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenPrerenderManager::~PrerenderManager() {
124dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  while (!prerender_list_.empty()) {
12521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    PrerenderContentsData data = prerender_list_.front();
12621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    prerender_list_.pop_front();
127dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    data.contents_->set_final_status(FINAL_STATUS_MANAGER_SHUTDOWN);
12821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    delete data.contents_;
12921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
13021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
13121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid PrerenderManager::SetPrerenderContentsFactory(
13372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    PrerenderContents::Factory* prerender_contents_factory) {
13472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  prerender_contents_factory_.reset(prerender_contents_factory);
13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
137dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenbool PrerenderManager::AddPreload(const GURL& url,
138dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  const std::vector<GURL>& alias_urls,
139dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                                  const GURL& referrer) {
14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
14121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DeleteOldEntries();
142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (FindEntry(url))
143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
144ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Local copy, since we may have to add an additional entry to it.
146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::vector<GURL> all_alias_urls = alias_urls;
147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  GURL additional_alias_url;
149ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsControlGroup() &&
150ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      PrerenderManager::MaybeGetQueryStringBasedAliasURL(
151ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          url, &additional_alias_url))
152ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    all_alias_urls.push_back(additional_alias_url);
153ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
154dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Do not prerender if there are too many render processes, and we would
155dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // have to use an existing one.  We do not want prerendering to happen in
156dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // a shared process, so that we can always reliably lower the CPU
157dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // priority for prerendering.
158ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // In single-process mode, ShouldTryToUseExistingProcessHost() always returns
159ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // true, so that case needs to be explicitly checked for.
160dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO(tburkard): Figure out how to cancel prerendering in the opposite
161dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // case, when a new tab is added to a process used for prerendering.
162ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (RenderProcessHost::ShouldTryToUseExistingProcessHost() &&
163ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      !RenderProcessHost::run_renderer_in_process()) {
164ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Only record the status if we are not in the control group.
165ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (!IsControlGroup())
166ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      RecordFinalStatus(FINAL_STATUS_TOO_MANY_PROCESSES);
167ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
168ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
169ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
170ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Check if enough time has passed since the last prerender.
171ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!DoesRateLimitAllowPrerender()) {
172ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // Cancel the prerender. We could add it to the pending prerender list but
173ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // this doesn't make sense as the next prerender request will be triggered
174ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    // by a navigation and is unlikely to be the same site.
175ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    RecordFinalStatus(FINAL_STATUS_RATE_LIMIT_EXCEEDED);
176ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
177dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return false;
17821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
179ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
180dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // TODO(cbentzel): Move invalid checks here instead of PrerenderContents?
181ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PrerenderContentsData data(CreatePrerenderContents(url, all_alias_urls,
182ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                                     referrer),
183dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen                             GetCurrentTime());
184ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
18521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  prerender_list_.push_back(data);
186ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (IsControlGroup()) {
187ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    data.contents_->set_final_status(FINAL_STATUS_CONTROL_GROUP);
188ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
189ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    last_prerender_start_time_ = GetCurrentTimeTicks();
190ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    data.contents_->StartPrerendering();
191ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
19221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  while (prerender_list_.size() > max_elements_) {
19321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    data = prerender_list_.front();
19421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    prerender_list_.pop_front();
195dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    data.contents_->set_final_status(FINAL_STATUS_EVICTED);
19621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    delete data.contents_;
19721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
198dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  StartSchedulingPeriodicCleanups();
199dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  return true;
20021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
20121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
202ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid PrerenderManager::AddPendingPreload(
203ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::pair<int,int>& child_route_id_pair,
204ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const GURL& url,
205ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const std::vector<GURL>& alias_urls,
206ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    const GURL& referrer) {
207ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Check if this is coming from a valid prerender rvh.
208ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool is_valid_prerender = false;
209ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
210ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       it != prerender_list_.end(); ++it) {
211ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PrerenderContents* pc = it->contents_;
212ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
213ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int child_id;
214ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    int route_id;
215ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool has_child_id = pc->GetChildId(&child_id);
216ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    bool has_route_id = has_child_id && pc->GetRouteId(&route_id);
217ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
218ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (has_child_id && has_route_id &&
219ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        child_id == child_route_id_pair.first &&
220ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        route_id == child_route_id_pair.second) {
221ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      is_valid_prerender = true;
222ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      break;
223ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
224ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
225ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
226ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If not, we could check to see if the RenderViewHost specified by the
227ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // child_route_id_pair exists and if so just start prerendering, as this
228ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // suggests that the link was clicked, though this might prerender something
229ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // that the user has already navigated away from. For now, we'll be
230ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // conservative and skip the prerender which will mean some prerender requests
231ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // from prerendered pages will be missed if the user navigates quickly.
232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!is_valid_prerender) {
233ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    RecordFinalStatus(FINAL_STATUS_PENDING_SKIPPED);
234ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
235ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
237ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PendingPrerenderList::iterator it =
238ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      pending_prerender_list_.find(child_route_id_pair);
239ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (it == pending_prerender_list_.end()) {
240ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PendingPrerenderList::value_type el = std::make_pair(child_route_id_pair,
241ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                            std::vector<PendingContentsData>());
242ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    it = pending_prerender_list_.insert(el).first;
243ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
244ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
245ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  it->second.push_back(PendingContentsData(url, alias_urls, referrer));
246ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
24821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid PrerenderManager::DeleteOldEntries() {
249dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  while (!prerender_list_.empty()) {
25021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    PrerenderContentsData data = prerender_list_.front();
25121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (IsPrerenderElementFresh(data.start_time_))
25221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return;
25321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    prerender_list_.pop_front();
254dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    data.contents_->set_final_status(FINAL_STATUS_TIMED_OUT);
25521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    delete data.contents_;
25621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
257dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (prerender_list_.empty())
258dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    StopSchedulingPeriodicCleanups();
25921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
26021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
26121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian MonsenPrerenderContents* PrerenderManager::GetEntry(const GURL& url) {
26221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DeleteOldEntries();
26321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
26421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen       it != prerender_list_.end();
26521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen       ++it) {
26672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    PrerenderContents* pc = it->contents_;
26772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (pc->MatchesURL(url)) {
26821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      prerender_list_.erase(it);
26921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      return pc;
27021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
27121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
27221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Entry not found.
27321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return NULL;
27421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
27521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
27621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool PrerenderManager::MaybeUsePreloadedPage(TabContents* tc, const GURL& url) {
27772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
27821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  scoped_ptr<PrerenderContents> pc(GetEntry(url));
27921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (pc.get() == NULL)
28021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    return false;
28121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
282ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If we are just in the control group (which can be detected by noticing
283ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // that prerendering hasn't even started yet), record that this TC now would
284ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // be showing a prerendered contents, but otherwise, don't do anything.
285ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!pc->prerendering_has_started()) {
286ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    MarkTabContentsAsWouldBePrerendered(tc);
287ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return false;
288ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
289ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
29072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!pc->load_start_time().is_null())
291ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    RecordTimeUntilUsed(GetCurrentTimeTicks() - pc->load_start_time());
292ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
293ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UMA_HISTOGRAM_COUNTS("Prerender.PrerendersPerSessionCount",
294ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                       ++prerenders_per_session_count_);
295dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  pc->set_final_status(FINAL_STATUS_USED);
29672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
297ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int child_id;
298ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int route_id;
299ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(pc->GetChildId(&child_id));
300ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  CHECK(pc->GetRouteId(&route_id));
301ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
30221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  RenderViewHost* rvh = pc->render_view_host();
303dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // RenderViewHosts in PrerenderContents start out hidden.
304dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Since we are actually using it now, restore it.
305dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  rvh->WasRestored();
30621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  pc->set_render_view_host(NULL);
30772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  rvh->Send(new ViewMsg_DisplayPrerenderedPage(rvh->routing_id()));
30821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  tc->SwapInRenderViewHost(rvh);
309ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  MarkTabContentsAsPrerendered(tc);
310ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
311ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // See if we have any pending prerender requests for this routing id and start
312ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // the preload if we do.
313ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id);
314ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PendingPrerenderList::iterator pending_it =
315ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      pending_prerender_list_.find(child_route_pair);
316ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (pending_it != pending_prerender_list_.end()) {
317ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (std::vector<PendingContentsData>::iterator content_it =
318ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            pending_it->second.begin();
319ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         content_it != pending_it->second.end(); ++content_it) {
320ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      AddPreload(content_it->url_, content_it->alias_urls_,
321ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                 content_it->referrer_);
322ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
323ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pending_prerender_list_.erase(pending_it);
324ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
325ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
326ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  NotificationService::current()->Notify(
327ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NotificationType::PRERENDER_CONTENTS_USED,
328ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      Source<std::pair<int, int> >(&child_route_pair),
329ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      NotificationService::NoDetails());
33021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
33121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  ViewHostMsg_FrameNavigate_Params* p = pc->navigate_params();
33221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (p != NULL)
33321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    tc->DidNavigate(rvh, *p);
33421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
33521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  string16 title = pc->title();
33621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  if (!title.empty())
33721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    tc->UpdateTitle(rvh, pc->page_id(), UTF16ToWideHack(title));
33821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
33972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  GURL icon_url = pc->icon_url();
340ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!icon_url.is_empty()) {
341ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::vector<FaviconURL> urls;
342ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    urls.push_back(FaviconURL(icon_url, FaviconURL::FAVICON));
343ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    tc->favicon_helper().OnUpdateFaviconURL(pc->page_id(), urls);
344ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
34572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
34672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (pc->has_stopped_loading())
34772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    tc->DidStopLoading();
34872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
34921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return true;
35021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
35121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
35221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenvoid PrerenderManager::RemoveEntry(PrerenderContents* entry) {
35372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
35421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
35521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen       it != prerender_list_.end();
35621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen       ++it) {
35721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    if (it->contents_ == entry) {
358ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      RemovePendingPreload(entry);
35921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      prerender_list_.erase(it);
36021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen      break;
36121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    }
36221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
36321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  DeleteOldEntries();
36421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
36521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
36621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbase::Time PrerenderManager::GetCurrentTime() const {
36721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return base::Time::Now();
36821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
36921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
370ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbase::TimeTicks PrerenderManager::GetCurrentTimeTicks() const {
371ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return base::TimeTicks::Now();
372ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
373ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
37421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenbool PrerenderManager::IsPrerenderElementFresh(const base::Time start) const {
37521d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  base::Time now = GetCurrentTime();
37621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  return (now - start < max_prerender_age_);
37721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
37821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
37972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenPrerenderContents* PrerenderManager::CreatePrerenderContents(
38072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const GURL& url,
381dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const std::vector<GURL>& alias_urls,
382dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    const GURL& referrer) {
38372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return prerender_contents_factory_->CreatePrerenderContents(
384dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      this, profile_, url, alias_urls, referrer);
38572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
38672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Helper macro for histograms.
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#define RECORD_PLT(tag, perceived_page_load_time) { \
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    UMA_HISTOGRAM_CUSTOM_TIMES( \
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        base::FieldTrial::MakeName(std::string("Prerender.") + tag, \
391ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                   "Prefetch"), \
392ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        perceived_page_load_time, \
393ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        base::TimeDelta::FromMilliseconds(10), \
394ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        base::TimeDelta::FromSeconds(60), \
395ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        100); \
396ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
397ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
398dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static
399ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid PrerenderManager::RecordPerceivedPageLoadTime(
400ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    base::TimeDelta perceived_page_load_time,
401ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    TabContents* tab_contents) {
402ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool within_window = WithinWindow();
403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  PrerenderManager* prerender_manager =
404ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      tab_contents->profile()->GetPrerenderManager();
405ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!prerender_manager)
406ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
407ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!prerender_manager->is_enabled())
408ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
409ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  RECORD_PLT("PerceivedPLT", perceived_page_load_time);
410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (within_window)
411ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    RECORD_PLT("PerceivedPLTWindowed", perceived_page_load_time);
412ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (prerender_manager &&
413ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      ((mode_ == PRERENDER_MODE_EXPERIMENT_CONTROL_GROUP &&
414ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        prerender_manager->WouldTabContentsBePrerendered(tab_contents)) ||
415ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       (mode_ == PRERENDER_MODE_EXPERIMENT_PRERENDER_GROUP &&
416ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        prerender_manager->IsTabContentsPrerendered(tab_contents)))) {
417ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    RECORD_PLT("PerceivedPLTMatched", perceived_page_load_time);
418ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  } else {
419ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    if (within_window)
420ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      RECORD_PLT("PerceivedPLTWindowNotMatched", perceived_page_load_time);
42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
42372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
42472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid PrerenderManager::RecordTimeUntilUsed(base::TimeDelta time_until_used) {
425ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UMA_HISTOGRAM_CUSTOM_TIMES(
426ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      "Prerender.TimeUntilUsed",
427ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      time_until_used,
428ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      base::TimeDelta::FromMilliseconds(10),
429ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      base::TimeDelta::FromSeconds(kDefaultMaxPrerenderAgeSeconds),
430ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      50);
431ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
432ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
433ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PrerenderManager::is_enabled() const {
434ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
435ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return enabled_;
436ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
437ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
438ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid PrerenderManager::set_enabled(bool enabled) {
439ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
440ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  enabled_ = enabled;
44172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
44272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
44372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenPrerenderContents* PrerenderManager::FindEntry(const GURL& url) {
44472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
44572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       it != prerender_list_.end();
44672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen       ++it) {
44772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    if (it->contents_->MatchesURL(url))
44872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      return it->contents_;
44972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
45072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Entry not found.
45172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  return NULL;
45272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
45372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
454ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian MonsenPrerenderManager::PendingContentsData*
455ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    PrerenderManager::FindPendingEntry(const GURL& url) {
456ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  for (PendingPrerenderList::iterator map_it = pending_prerender_list_.begin();
457ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       map_it != pending_prerender_list_.end();
458ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen       ++map_it) {
459ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    for (std::vector<PendingContentsData>::iterator content_it =
460ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen            map_it->second.begin();
461ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         content_it != map_it->second.end();
462ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen         ++content_it) {
463ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      if (content_it->url_ == url) {
464ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen        return &(*content_it);
465ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      }
466ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    }
467ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
468ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
469ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return NULL;
470ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
472dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static
47372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid PrerenderManager::RecordPrefetchTagObserved() {
47472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Ensure that we are in the UI thread, and post to the UI thread if
47572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // necessary.
47672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
47772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    BrowserThread::PostTask(
47872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        BrowserThread::UI,
47972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        FROM_HERE,
48072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        NewRunnableFunction(
48172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen            &PrerenderManager::RecordPrefetchTagObservedOnUIThread));
48272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  } else {
48372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    RecordPrefetchTagObservedOnUIThread();
48472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  }
48572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
48672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
487dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static
48872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsenvoid PrerenderManager::RecordPrefetchTagObservedOnUIThread() {
48972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // Once we get here, we have to be on the UI thread.
49072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
49172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
49272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // If we observe multiple tags within the 30 second window, we will still
49372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // reset the window to begin at the most recent occurrence, so that we will
49472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // always be in a window in the 30 seconds from each occurrence.
49572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  last_prefetch_seen_time_ = base::TimeTicks::Now();
49672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen}
49772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen
498ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid PrerenderManager::RemovePendingPreload(PrerenderContents* entry) {
499ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int child_id;
500ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  int route_id;
501ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool has_child_id = entry->GetChildId(&child_id);
502ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  bool has_route_id = has_child_id && entry->GetRouteId(&route_id);
503ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
504ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // If the entry doesn't have a RenderViewHost then it didn't start
505ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // prerendering and there shouldn't be any pending preloads to remove.
506ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (has_child_id && has_route_id) {
507ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    std::pair<int, int> child_route_pair = std::make_pair(child_id, route_id);
508ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    pending_prerender_list_.erase(child_route_pair);
509ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  }
510ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
512dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen// static
513ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PrerenderManager::WithinWindow() {
51472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
51572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if (last_prefetch_seen_time_.is_null())
51672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    return false;
51772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  base::TimeDelta elapsed_time =
51872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      base::TimeTicks::Now() - last_prefetch_seen_time_;
519ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return elapsed_time <= base::TimeDelta::FromSeconds(kWindowDurationSeconds);
520ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
521ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
522ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PrerenderManager::DoesRateLimitAllowPrerender() const {
523ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
524ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  base::TimeDelta elapsed_time =
525ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      GetCurrentTimeTicks() - last_prerender_start_time_;
526ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  UMA_HISTOGRAM_TIMES("Prerender.TimeBetweenPrerenderRequests",
527ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                      elapsed_time);
528ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!rate_limit_enabled_)
529ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return true;
530ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return elapsed_time >
531ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      base::TimeDelta::FromMilliseconds(kMinTimeBetweenPrerendersMs);
53221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen}
533dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
534dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid PrerenderManager::StartSchedulingPeriodicCleanups() {
535dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (repeating_timer_.IsRunning())
536dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    return;
537dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  repeating_timer_.Start(
538dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      base::TimeDelta::FromMilliseconds(kPeriodicCleanupIntervalMs),
539dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      this,
540dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen      &PrerenderManager::PeriodicCleanup);
541dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
542dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
543dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid PrerenderManager::StopSchedulingPeriodicCleanups() {
544dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  repeating_timer_.Stop();
545dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
546dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
547dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid PrerenderManager::PeriodicCleanup() {
548dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DeleteOldEntries();
549dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Grab a copy of the current PrerenderContents pointers, so that we
550dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // will not interfere with potential deletions of the list.
551dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  std::vector<PrerenderContents*> prerender_contents;
552dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  for (std::list<PrerenderContentsData>::iterator it = prerender_list_.begin();
553dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       it != prerender_list_.end();
554dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       ++it) {
555dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    prerender_contents.push_back(it->contents_);
556dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
557dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  for (std::vector<PrerenderContents*>::iterator it =
558dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen           prerender_contents.begin();
559dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       it != prerender_contents.end();
560dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen       ++it) {
561dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    (*it)->DestroyWhenUsingTooManyResources();
562dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  }
563dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
564dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
565ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid PrerenderManager::MarkTabContentsAsPrerendered(TabContents* tc) {
566ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  prerendered_tc_set_.insert(tc);
567ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
568ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
569ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid PrerenderManager::MarkTabContentsAsWouldBePrerendered(TabContents* tc) {
570ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  would_be_prerendered_tc_set_.insert(tc);
571ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
572ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
573ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid PrerenderManager::MarkTabContentsAsNotPrerendered(TabContents* tc) {
574ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  prerendered_tc_set_.erase(tc);
575ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  would_be_prerendered_tc_set_.erase(tc);
576ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
577ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
578ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PrerenderManager::IsTabContentsPrerendered(TabContents* tc) const {
579ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return prerendered_tc_set_.count(tc) > 0;
580ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
581ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
582ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenbool PrerenderManager::WouldTabContentsBePrerendered(TabContents* tc) const {
583ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  return would_be_prerendered_tc_set_.count(tc) > 0;
584ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
585ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
586dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}  // namespace prerender
587