1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved.
2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file.
4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/predictor_api.h"
6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <map>
8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include <string>
9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "base/lazy_instance.h"
11ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/metrics/field_trial.h"
12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/stl_util-inl.h"
133345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "base/string_number_conversions.h"
14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/synchronization/waitable_event.h"
153f50c38dc070f4bb515c1b64450dae14f316474eKristian Monsen#include "base/threading/thread.h"
16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "base/values.h"
17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/browser_process.h"
18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/io_thread.h"
19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/preconnect.h"
20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/browser/net/referrer.h"
213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/net/url_info.h"
2272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "chrome/browser/prefs/browser_prefs.h"
233345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/pref_service.h"
24ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/browser/prefs/scoped_user_pref_update.h"
253345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#include "chrome/browser/prefs/session_startup_pref.h"
2621d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen#include "chrome/browser/profiles/profile.h"
274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/ui/browser.h"
28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "chrome/common/pref_names.h"
29dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h"
30ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_registrar.h"
31ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "content/common/notification_service.h"
32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/host_resolver.h"
33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch#include "net/base/host_resolver_impl.h"
34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::Time;
36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochusing base::TimeDelta;
37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochnamespace chrome_browser_net {
39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void DnsPrefetchMotivatedList(const UrlList& urls,
413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                     UrlInfo::ResolutionMotivation motivation);
42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
443345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                                            PrefService* local_state);
45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
46513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Given that the underlying Chromium resolver defaults to a total maximum of
47513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// 8 paralell resolutions, we will avoid any chance of starving navigational
48513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// resolutions by limiting the number of paralell speculative resolutions.
49513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// TODO(jar): Move this limitation into the resolver.
50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
51513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst size_t PredictorInit::kMaxSpeculativeParallelResolves = 3;
52513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
53513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// To control our congestion avoidance system, which discards a queue when
54513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// resolutions are "taking too long," we need an expected resolution time.
55513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// Common average is in the range of 300-500ms.
56513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic const int kExpectedResolutionTimeMs = 500;
57513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
58513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// To control the congestion avoidance system, we need an estimate of how many
59513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// speculative requests may arrive at once.  Since we currently only keep 8
60513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// subresource names for each frame, we'll use that as our basis.  Note that
61513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// when scanning search results lists, we might actually get 10 at a time, and
62513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// wikipedia can often supply (during a page scan) upwards of 50.  In those odd
63513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// cases, we may discard some of the later speculative requests mistakenly
64513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// assuming that the resolutions took too long.
65513209b27ff55e2841eac0e4120199c23acce758Ben Murdochstatic const int kTypicalSpeculativeGroupSize = 8;
66513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
67513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// The next constant specifies an amount of queueing delay that is "too large,"
68513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// and indicative of problems with resolutions (perhaps due to an overloaded
69513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// router, or such).  When we exceed this delay, congestion avoidance will kick
70513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch// in and all speculations in the queue will be discarded.
71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// static
72513209b27ff55e2841eac0e4120199c23acce758Ben Murdochconst int PredictorInit::kMaxSpeculativeResolveQueueDelayMs =
73513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    (kExpectedResolutionTimeMs * kTypicalSpeculativeGroupSize) /
74513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    kMaxSpeculativeParallelResolves;
75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// A version number for prefs that are saved. This should be incremented when
77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// we change the format so that we discard old data.
78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic const int kPredictorStartupFormatVersion = 1;
79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// There will only be one instance ever created of the following Observer class.
813345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// The InitialObserver lives on the IO thread, and monitors navigations made by
823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// the network stack.  This is only used to identify startup time resolutions
833345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// (for re-resolution during our next process startup).
843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// TODO(jar): Consider preconnecting at startup, which may be faster than
853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// waiting for render process to start and request a connection.
863345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickclass InitialObserver {
873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick public:
883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Recording of when we observed each navigation.
893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  typedef std::map<GURL, base::TimeTicks> FirstNavigations;
90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Potentially add a new URL to our startup list.
923345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void Append(const GURL& url);
93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
943345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Get an HTML version of our current planned first_navigations_.
953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void GetFirstResolutionsHtml(std::string* output);
96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // Persist the current first_navigations_ for storage in a list.
983345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  void GetInitialDnsResolutionList(ListValue* startup_list);
993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
100dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  // Discards all initial loading history.
101dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  void DiscardInitialNavigationHistory() { first_navigations_.clear(); }
102dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
1033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick private:
1043345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // List of the first N URL resolutions observed in this run.
1053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  FirstNavigations first_navigations_;
1063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // The number of URLs we'll save for pre-resolving at next startup.
1083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  static const size_t kStartupResolutionCount = 10;
1093345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick};
1103345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
1113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// TODO(willchan): Look at killing this global.
1123345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic InitialObserver* g_initial_observer = NULL;
113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This section contains all the globally accessable API entry points for the
116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// DNS Prefetching feature.
117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
1193345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Status of speculative DNS resolution and speculative TCP/IP connection
1203345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// feature.
1213345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic bool predictor_enabled = true;
122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Cached inverted copy of the off_the_record pref.
124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic bool on_the_record_switch = true;
125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Enable/disable Dns prefetch activity (either via command line, or via pref).
127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid EnablePredictor(bool enable) {
128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // NOTE: this is invoked on the UI thread.
1293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  predictor_enabled = enable;
130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid OnTheRecord(bool enable) {
133731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (on_the_record_switch == enable)
135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  on_the_record_switch = enable;
137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (on_the_record_switch)
138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    g_browser_process->io_thread()->ChangedToOnTheRecord();
139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
141dc0f95d653279beabeb9817299e2902918ba123eKristian Monsenvoid DiscardInitialNavigationHistory() {
142dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
143dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen  if (g_initial_observer)
144dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen    g_initial_observer->DiscardInitialNavigationHistory();
145dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen}
146dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen
147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid RegisterUserPrefs(PrefService* user_prefs) {
14821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  user_prefs->RegisterListPref(prefs::kDnsPrefetchingStartupList);
14921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  user_prefs->RegisterListPref(prefs::kDnsPrefetchingHostReferralList);
150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// When enabled, we use the following instance to service all requests in the
153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// browser process.
154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(willchan): Look at killing this.
1553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickstatic Predictor* g_predictor = NULL;
156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This API is only used in the browser process.
158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// It is called from an IPC message originating in the renderer.  It currently
159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// includes both Page-Scan, and Link-Hover prefetching.
160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// TODO(jar): Separate out link-hover prefetching, and page-scan results.
161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid DnsPrefetchList(const NameList& hostnames) {
1623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // TODO(jar): Push GURL transport further back into renderer, but this will
1633345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  // require a Webkit change in the observer :-/.
164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UrlList urls;
165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  for (NameList::const_iterator it = hostnames.begin();
166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       it < hostnames.end();
167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++it) {
168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    urls.push_back(GURL("http://" + *it + ":80"));
169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
171731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DnsPrefetchMotivatedList(urls, UrlInfo::PAGE_SCAN_MOTIVATED);
173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void DnsPrefetchMotivatedList(
176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const UrlList& urls,
177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    UrlInfo::ResolutionMotivation motivation) {
178731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
179731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick         BrowserThread::CurrentlyOn(BrowserThread::IO));
1803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!predictor_enabled || NULL == g_predictor)
181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
183731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
1843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    g_predictor->ResolveList(urls, motivation);
185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
186731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    BrowserThread::PostTask(
187731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick        BrowserThread::IO,
188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        FROM_HERE,
1893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        NewRunnableMethod(g_predictor,
190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                          &Predictor::ResolveList, urls, motivation));
191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This API is used by the autocomplete popup box (where URLs are typed).
1953345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid AnticipateOmniboxUrl(const GURL& url, bool preconnectable) {
196731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1973345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!predictor_enabled || NULL == g_predictor)
198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
1993345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!url.is_valid() || !url.has_host())
200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2023345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_predictor->AnticipateOmniboxUrl(url, preconnectable);
203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid PreconnectUrlAndSubresources(const GURL& url) {
2063345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!predictor_enabled || NULL == g_predictor)
2073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    return;
2083345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!url.is_valid() || !url.has_host())
209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2113345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_predictor->PreconnectUrlAndSubresources(url);
212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2143345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick
215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This section intermingles prefetch results with actual browser HTTP
217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// network activity.  It supports calculating of the benefit of a prefetch, as
218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// well as recording what prefetched hostname resolutions might be potentially
219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// helpful during the next chrome-startup.
220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2223345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid PredictFrameSubresources(const GURL& url) {
223731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2243345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!predictor_enabled || NULL == g_predictor)
225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2263345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_predictor->PredictFrameSubresources(url);
227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2293345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid LearnAboutInitialNavigation(const GURL& url) {
230731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2313345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!predictor_enabled || NULL == g_initial_observer )
232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2333345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_initial_observer->Append(url);
234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
237731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
2383345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!predictor_enabled || NULL == g_predictor)
239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2403345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_predictor->LearnFromNavigation(referring_url, target_url);
241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// The observer class needs to connect starts and finishes of HTTP network
244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// resolutions.  We use the following type for that map.
245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochtypedef std::map<int, UrlInfo> ObservedResolutionMap;
246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
2483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick// Member definitions for InitialObserver class.
249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2503345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid InitialObserver::Append(const GURL& url) {
251731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2533345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!on_the_record_switch || NULL == g_predictor)
254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
2553345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (kStartupResolutionCount <= first_navigations_.size())
256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2583345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (url.SchemeIs("http") || url.SchemeIs("https")) {
25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    const GURL url_without_path(Predictor::CanonicalizeUrl(url));
2603345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    if (first_navigations_.find(url_without_path) == first_navigations_.end())
2613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      first_navigations_[url_without_path] = base::TimeTicks::Now();
2623345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  }
263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2653345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid InitialObserver::GetInitialDnsResolutionList(ListValue* startup_list) {
266731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(startup_list);
268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  startup_list->Clear();
269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK_EQ(0u, startup_list->GetSize());
270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion));
2713345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  for (FirstNavigations::iterator it = first_navigations_.begin();
2723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick       it != first_navigations_.end();
273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch       ++it) {
2743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(it->first == Predictor::CanonicalizeUrl(it->first));
275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    startup_list->Append(new StringValue(it->first.spec()));
276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2793345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrickvoid InitialObserver::GetFirstResolutionsHtml(std::string* output) {
280731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
2823345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  UrlInfo::UrlInfoTable resolution_list;
283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  {
2843345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    for (FirstNavigations::iterator it(first_navigations_.begin());
2853345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick         it != first_navigations_.end();
286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch         it++) {
2873345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      UrlInfo info;
2883345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      info.SetUrl(it->first);
2893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      info.set_time(it->second);
2903345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      resolution_list.push_back(info);
291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UrlInfo::GetHtmlTable(resolution_list,
294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      "Future startups will prefetch DNS records for ", false, output);
295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Support observer to detect opening and closing of OffTheRecord windows.
299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This object lives on the UI thread.
300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochclass OffTheRecordObserver : public NotificationObserver {
302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch public:
303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Register() {
304c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // TODO(pkasting): This test should not be necessary.  See crbug.com/12475.
305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (registrar_.IsEmpty()) {
306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      registrar_.Add(this, NotificationType::BROWSER_CLOSED,
307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     NotificationService::AllSources());
308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      registrar_.Add(this, NotificationType::BROWSER_OPENED,
309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                     NotificationService::AllSources());
310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  void Observe(NotificationType type, const NotificationSource& source,
314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch               const NotificationDetails& details) {
315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    switch (type.value) {
316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case NotificationType::BROWSER_OPENED:
317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!Source<Browser>(source)->profile()->IsOffTheRecord())
318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        ++count_off_the_record_windows_;
320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnTheRecord(false);
321c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      case NotificationType::BROWSER_CLOSED:
324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!Source<Browser>(source)->profile()->IsOffTheRecord())
325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;  // Ignore ordinary windows.
326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        DCHECK_LT(0, count_off_the_record_windows_);
327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (0 >= count_off_the_record_windows_)  // Defensive coding.
328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;
329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (--count_off_the_record_windows_)
330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;  // Still some windows are incognito.
331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        OnTheRecord(true);
332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      default:
335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        break;
336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch private:
34021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  friend struct base::DefaultLazyInstanceTraits<OffTheRecordObserver>;
34121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  OffTheRecordObserver() : count_off_the_record_windows_(0) {}
343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ~OffTheRecordObserver() {}
344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  NotificationRegistrar registrar_;
346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int count_off_the_record_windows_;
347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DISALLOW_COPY_AND_ASSIGN(OffTheRecordObserver);
349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch};
350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
35121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsenstatic base::LazyInstance<OffTheRecordObserver> g_off_the_record_observer(
35221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    base::LINKER_INITIALIZED);
35321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This section supports the about:dns page.
356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Provide global support for the about:dns page.
359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid PredictorGetHtmlInfo(std::string* output) {
360731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  output->append("<html><head><title>About DNS</title>"
363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 // We'd like the following no-cache... but it doesn't work.
364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"
365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                 "</head><body>");
3663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!predictor_enabled  || NULL == g_predictor) {
367731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick    output->append("DNS pre-resolution and TCP pre-connection is disabled.");
368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  } else {
369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (!on_the_record_switch) {
370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      output->append("Incognito mode is active in a window.");
371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    } else {
3723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // List items fetched at startup.
3733345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      if (g_initial_observer)
3743345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick        g_initial_observer->GetFirstResolutionsHtml(output);
3753345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Show list of subresource predictions and stats.
3763345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      g_predictor->GetHtmlReferrerLists(output);
3773345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      // Show list of prediction results.
3783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      g_predictor->GetHtmlInfo(output);
379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  output->append("</body></html>");
382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
384ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenvoid ClearPredictorCache() {
385ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
386ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  if (!predictor_enabled || NULL == g_predictor)
387ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    return;
388ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  g_predictor->DiscardAllResults();
389ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen}
390ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen
391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// This section intializes global DNS prefetch services.
393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void InitNetworkPredictor(TimeDelta max_dns_queue_delay,
396513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                 size_t max_parallel_resolves,
397513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                 PrefService* user_prefs,
398513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                 PrefService* local_state,
399513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch                                 bool preconnect_enabled) {
400731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  bool prefetching_enabled =
403ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      user_prefs->GetBoolean(prefs::kNetworkPredictionEnabled);
404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Gather the list of hostnames to prefetch on startup.
406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UrlList urls =
407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GetPredictedUrlListAtStartup(user_prefs, local_state);
408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  ListValue* referral_list =
410ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      static_cast<ListValue*>(user_prefs->GetList(
41121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          prefs::kDnsPrefetchingHostReferralList)->DeepCopy());
41221d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
41321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  // Remove obsolete preferences from local state if necessary.
41472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  int current_version =
41572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen      local_state->GetInteger(prefs::kMultipleProfilePrefMigration);
41672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  if ((current_version & browser::DNS_PREFS) == 0) {
41721d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    local_state->RegisterListPref(prefs::kDnsStartupPrefetchList);
41821d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    local_state->RegisterListPref(prefs::kDnsHostReferralList);
41921d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    local_state->ClearPref(prefs::kDnsStartupPrefetchList);
42021d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen    local_state->ClearPref(prefs::kDnsHostReferralList);
42172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen    local_state->SetInteger(prefs::kMultipleProfilePrefMigration,
42272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen        current_version | browser::DNS_PREFS);
42321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  }
424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  g_browser_process->io_thread()->InitNetworkPredictor(
426513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      prefetching_enabled, max_dns_queue_delay, max_parallel_resolves, urls,
427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      referral_list, preconnect_enabled);
428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FinalizePredictorInitialization(
431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    Predictor* global_predictor,
432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    const UrlList& startup_urls,
433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ListValue* referral_list) {
434731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
4353345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_predictor = global_predictor;
4363345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_initial_observer = new InitialObserver();
437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Prefetch these hostnames on startup.
439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DnsPrefetchMotivatedList(startup_urls,
440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                           UrlInfo::STARTUP_LIST_MOTIVATED);
4413345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_predictor->DeserializeReferrersThenDelete(referral_list);
442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid FreePredictorResources() {
445731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
4463345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_predictor = NULL;  // Owned and released by io_thread.cc.
4473345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  delete g_initial_observer;
4483345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_initial_observer = NULL;
449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Functions to handle saving of hostnames from one session to the next, to
453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// expedite startup times.
454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ListValue* startup_list,
457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    ListValue* referral_list,
458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    base::WaitableEvent* completion) {
459731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4613345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (NULL == g_predictor) {
462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    completion->Signal();
463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4663345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (g_initial_observer)
4673345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    g_initial_observer->GetInitialDnsResolutionList(startup_list);
468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
469ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // Do at least one trim at shutdown, in case the user wasn't running long
470ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // enough to do any regular trimming of referrers.
471ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  g_predictor->TrimReferrersNow();
4723345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  g_predictor->SerializeReferrers(referral_list);
473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  completion->Signal();
475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochvoid SavePredictorStateForNextStartupAndTrim(PrefService* prefs) {
478731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
4803345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  if (!predictor_enabled || g_predictor == NULL)
481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    return;
482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  base::WaitableEvent completion(true, false);
484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
485ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ListPrefUpdate update_startup_list(prefs, prefs::kDnsPrefetchingStartupList);
486ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  ListPrefUpdate update_referral_list(prefs,
487ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen                                      prefs::kDnsPrefetchingHostReferralList);
488731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  bool posted = BrowserThread::PostTask(
489731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick      BrowserThread::IO,
490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      FROM_HERE,
491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      NewRunnableFunction(SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread,
492ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          update_startup_list.Get(),
493ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen          update_referral_list.Get(),
49421d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen          &completion));
495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
496ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // TODO(jar): Synchronous waiting for the IO thread is a potential source
497ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  // to deadlocks and should be investigated. See http://crbug.com/78451.
498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  DCHECK(posted);
499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (posted)
500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    completion.Wait();
501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochstatic UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            PrefService* local_state) {
505731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  UrlList urls;
507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Recall list of URLs we learned about during last session.
508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // This may catch secondary hostnames, pulled in by the homepages.  It will
509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // also catch more of the "primary" home pages, since that was (presumably)
510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // rendered first (and will be rendered first this time too).
511ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen  const ListValue* startup_list =
512ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen      user_prefs->GetList(prefs::kDnsPrefetchingStartupList);
51321d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen
514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (startup_list) {
515ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen    ListValue::const_iterator it = startup_list->begin();
516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    int format_version = -1;
517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (it != startup_list->end() &&
518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        (*it)->GetAsInteger(&format_version) &&
519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        format_version == kPredictorStartupFormatVersion) {
520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      ++it;
521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      for (; it != startup_list->end(); ++it) {
522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        std::string url_spec;
523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!(*it)->GetAsString(&url_spec)) {
524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          LOG(DFATAL);
525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;  // Format incompatibility.
526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        GURL url(url_spec);
528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        if (!url.has_host() || !url.has_scheme()) {
529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          LOG(DFATAL);
530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch          break;  // Format incompatibility.
531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        }
532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        urls.push_back(url);
534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      }
535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Prepare for any static home page(s) the user has in prefs.  The user may
539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // have a LOT of tab's specified, so we may as well try to warm them all.
540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  SessionStartupPref tab_start_pref =
541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      SessionStartupPref::GetStartupPref(user_prefs);
542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (SessionStartupPref::URLS == tab_start_pref.type) {
543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    for (size_t i = 0; i < tab_start_pref.urls.size(); i++) {
544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      GURL gurl = tab_start_pref.urls[i];
545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (!gurl.is_valid() || gurl.SchemeIsFile() || gurl.host().empty())
546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        continue;
547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch      if (gurl.SchemeIs("http") || gurl.SchemeIs("https"))
548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        urls.push_back(gurl.GetWithEmptyPath());
549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    }
550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (urls.empty())
553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    urls.push_back(GURL("http://www.google.com:80"));
554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  return urls;
556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
557c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch//------------------------------------------------------------------------------
559c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Methods for the helper class that is used to startup and teardown the whole
560ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// g_predictor system (both DNS pre-resolution and TCP/IP pre-connection).
561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
562c407dc5cd9bdc5668497f21b26b09d988ab439deBen MurdochPredictorInit::PredictorInit(PrefService* user_prefs,
563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                             PrefService* local_state,
5643345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick                             bool preconnect_enabled) {
565731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set up a field trial to see what disabling DNS pre-resolution does to
567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // latency of page loads.
568731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::FieldTrial::Probability kDivisor = 1000;
569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // For each option (i.e., non-default), we have a fixed probability.
570731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick  base::FieldTrial::Probability kProbabilityPerGroup = 100;  // 10% probability.
571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
57272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // After June 30, 2011 builds, it will always be in default group
57372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  // (default_enabled_prefetch).
57472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen  trial_ = new base::FieldTrial("DnsImpact", kDivisor,
57572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen                                "default_enabled_prefetch", 2011, 6, 30);
576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // First option is to disable prefetching completely.
5783345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int disabled_prefetch = trial_->AppendGroup("disabled_prefetch",
579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                              kProbabilityPerGroup);
580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We're running two experiments at the same time.  The first set of trials
582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // modulates the delay-time until we declare a congestion event (and purge
583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // our queue).  The second modulates the number of concurrent resolutions
584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // we do at any time.  Users are in exactly one trial (or the default) during
585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // any one run, and hence only one experiment at a time.
586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Experiment 1:
587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set congestion detection at 250, 500, or 750ms, rather than the 1 second
588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // default.
5893345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int max_250ms_prefetch = trial_->AppendGroup("max_250ms_queue_prefetch",
590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               kProbabilityPerGroup);
5913345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int max_500ms_prefetch = trial_->AppendGroup("max_500ms_queue_prefetch",
592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               kProbabilityPerGroup);
5933345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int max_750ms_prefetch = trial_->AppendGroup("max_750ms_queue_prefetch",
594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                               kProbabilityPerGroup);
595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set congestion detection at 2 seconds instead of the 1 second default.
5963345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick  int max_2s_prefetch = trial_->AppendGroup("max_2s_queue_prefetch",
597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                                            kProbabilityPerGroup);
598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Experiment 2:
599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // Set max simultaneous resoultions to 2, 4, or 6, and scale the congestion
600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // limit proportionally (so we don't impact average probability of asserting
601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // congesion very much).
602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int max_2_concurrent_prefetch = trial_->AppendGroup(
6033345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      "max_2 concurrent_prefetch", kProbabilityPerGroup);
604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int max_4_concurrent_prefetch = trial_->AppendGroup(
6053345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      "max_4 concurrent_prefetch", kProbabilityPerGroup);
606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  int max_6_concurrent_prefetch = trial_->AppendGroup(
6073345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick      "max_6 concurrent_prefetch", kProbabilityPerGroup);
608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // We will register the incognito observer regardless of whether prefetching
610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  // is enabled, as it is also used to clear the host cache.
61121d179b334e59e9a3bfcaed4c4430bef1bc5759dKristian Monsen  g_off_the_record_observer.Get().Register();
612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  if (trial_->group() != disabled_prefetch) {
614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    // Initialize the DNS prefetch system.
615513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    size_t max_parallel_resolves = kMaxSpeculativeParallelResolves;
616513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    int max_queueing_delay_ms = kMaxSpeculativeResolveQueueDelayMs;
617513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    if (trial_->group() == max_2_concurrent_prefetch)
619513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      max_parallel_resolves = 2;
620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else if (trial_->group() == max_4_concurrent_prefetch)
621513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      max_parallel_resolves = 4;
622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    else if (trial_->group() == max_6_concurrent_prefetch)
623513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      max_parallel_resolves = 6;
624513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch
625513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    if (trial_->group() == max_250ms_prefetch) {
626513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      max_queueing_delay_ms =
627513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch         (250 * kTypicalSpeculativeGroupSize) /  max_parallel_resolves;
628513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else if (trial_->group() == max_500ms_prefetch) {
629513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      max_queueing_delay_ms =
630513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          (500 * kTypicalSpeculativeGroupSize) /  max_parallel_resolves;
631513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else if (trial_->group() == max_750ms_prefetch) {
632513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      max_queueing_delay_ms =
633513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          (750 * kTypicalSpeculativeGroupSize) /  max_parallel_resolves;
634513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    } else if (trial_->group() == max_2s_prefetch) {
635513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch      max_queueing_delay_ms =
636513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch          (2000 * kTypicalSpeculativeGroupSize) /  max_parallel_resolves;
637513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    }
638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch    TimeDelta max_queueing_delay(
640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch        TimeDelta::FromMilliseconds(max_queueing_delay_ms));
641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
6423345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick    DCHECK(!g_predictor);
643513209b27ff55e2841eac0e4120199c23acce758Ben Murdoch    InitNetworkPredictor(max_queueing_delay, max_parallel_resolves, user_prefs,
644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch                         local_state, preconnect_enabled);
645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch  }
646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}
647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
648731df977c0511bca2206b5f333555b1205ff1f43Iain MerrickPredictorInit::~PredictorInit() {
649731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick}
650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch
651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}  // namespace chrome_browser_net
652