blob: 91490956339705bcaa4ec5240afd08100771d0e8 [file] [log] [blame]
[email protected]835d7c82010-10-14 04:38:381// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commit09911bf2008-07-26 23:55:294
[email protected]3530cd92010-06-27 06:22:015#include "chrome/browser/net/predictor_api.h"
initial.commit09911bf2008-07-26 23:55:296
7#include <map>
8#include <string>
9
[email protected]835d7c82010-10-14 04:38:3810#include "base/metrics/field_trial.h"
[email protected]94dc2282009-05-26 19:32:3211#include "base/singleton.h"
[email protected]760d970a2010-05-18 00:39:1812#include "base/stl_util-inl.h"
[email protected]528c56d2010-07-30 19:28:4413#include "base/string_number_conversions.h"
[email protected]fd2f8afe2009-06-11 21:53:5514#include "base/thread.h"
initial.commit09911bf2008-07-26 23:55:2915#include "base/values.h"
[email protected]37858e52010-08-26 00:22:0216#include "base/waitable_event.h"
initial.commit09911bf2008-07-26 23:55:2917#include "chrome/browser/browser.h"
[email protected]0ac83682010-01-22 17:46:2718#include "chrome/browser/browser_process.h"
[email protected]017a7a112010-10-12 16:38:2719#include "chrome/browser/browser_thread.h"
[email protected]0ac83682010-01-22 17:46:2720#include "chrome/browser/io_thread.h"
[email protected]760d970a2010-05-18 00:39:1821#include "chrome/browser/net/preconnect.h"
[email protected]21dae9b2008-11-06 23:32:5322#include "chrome/browser/net/referrer.h"
[email protected]37858e52010-08-26 00:22:0223#include "chrome/browser/net/url_info.h"
24#include "chrome/browser/prefs/pref_service.h"
25#include "chrome/browser/prefs/session_startup_pref.h"
[email protected]505323e22009-01-24 02:47:5826#include "chrome/browser/profile.h"
[email protected]f1c8a2b2009-05-22 01:52:4327#include "chrome/common/notification_registrar.h"
initial.commit09911bf2008-07-26 23:55:2928#include "chrome/common/notification_service.h"
29#include "chrome/common/pref_names.h"
[email protected]fd2f8afe2009-06-11 21:53:5530#include "net/base/host_resolver.h"
[email protected]123ab1e32009-10-21 19:12:5731#include "net/base/host_resolver_impl.h"
initial.commit09911bf2008-07-26 23:55:2932
[email protected]602faf3c2009-06-27 14:35:4433using base::Time;
[email protected]e1acf6f2008-10-27 20:43:3334using base::TimeDelta;
35
initial.commit09911bf2008-07-26 23:55:2936namespace chrome_browser_net {
37
[email protected]c5629c32010-06-23 01:22:4338static void DnsPrefetchMotivatedList(const UrlList& urls,
[email protected]f4ef861ba2010-07-28 22:37:2339 UrlInfo::ResolutionMotivation motivation);
initial.commit09911bf2008-07-26 23:55:2940
[email protected]f4ef861ba2010-07-28 22:37:2341static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
42 PrefService* local_state);
[email protected]0ac83682010-01-22 17:46:2743
[email protected]e085c302009-06-01 18:31:3644// static
[email protected]74be069e82010-06-25 00:12:4945const size_t PredictorInit::kMaxPrefetchConcurrentLookups = 8;
[email protected]e085c302009-06-01 18:31:3646
[email protected]602faf3c2009-06-27 14:35:4447// static
[email protected]74be069e82010-06-25 00:12:4948const int PredictorInit::kMaxPrefetchQueueingDelayMs = 500;
[email protected]602faf3c2009-06-27 14:35:4449
[email protected]760d970a2010-05-18 00:39:1850// A version number for prefs that are saved. This should be incremented when
51// we change the format so that we discard old data.
[email protected]74be069e82010-06-25 00:12:4952static const int kPredictorStartupFormatVersion = 1;
[email protected]c5629c32010-06-23 01:22:4353
[email protected]bff1f512010-08-15 15:13:4954// There will only be one instance ever created of the following Observer class.
55// The InitialObserver lives on the IO thread, and monitors navigations made by
56// the network stack. This is only used to identify startup time resolutions
57// (for re-resolution during our next process startup).
58// TODO(jar): Consider preconnecting at startup, which may be faster than
59// waiting for render process to start and request a connection.
60class InitialObserver {
61 public:
62 // Recording of when we observed each navigation.
63 typedef std::map<GURL, base::TimeTicks> FirstNavigations;
64
65 // Potentially add a new URL to our startup list.
66 void Append(const GURL& url);
67
68 // Get an HTML version of our current planned first_navigations_.
69 void GetFirstResolutionsHtml(std::string* output);
70
71 // Persist the current first_navigations_ for storage in a list.
72 void GetInitialDnsResolutionList(ListValue* startup_list);
73
74 private:
75 // List of the first N URL resolutions observed in this run.
76 FirstNavigations first_navigations_;
77
78 // The number of URLs we'll save for pre-resolving at next startup.
79 static const size_t kStartupResolutionCount = 10;
80};
81
82// TODO(willchan): Look at killing this global.
83static InitialObserver* g_initial_observer = NULL;
84
[email protected]c5629c32010-06-23 01:22:4385//------------------------------------------------------------------------------
initial.commit09911bf2008-07-26 23:55:2986// This section contains all the globally accessable API entry points for the
87// DNS Prefetching feature.
88//------------------------------------------------------------------------------
89
[email protected]bff1f512010-08-15 15:13:4990// Status of speculative DNS resolution and speculative TCP/IP connection
91// feature.
92static bool predictor_enabled = true;
initial.commit09911bf2008-07-26 23:55:2993
94// Cached inverted copy of the off_the_record pref.
95static bool on_the_record_switch = true;
96
97// Enable/disable Dns prefetch activity (either via command line, or via pref).
[email protected]74be069e82010-06-25 00:12:4998void EnablePredictor(bool enable) {
[email protected]847e54f2010-01-23 16:37:5699 // NOTE: this is invoked on the UI thread.
[email protected]bff1f512010-08-15 15:13:49100 predictor_enabled = enable;
initial.commit09911bf2008-07-26 23:55:29101}
102
103void OnTheRecord(bool enable) {
[email protected]ba4f1132010-10-09 02:02:35104 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29105 if (on_the_record_switch == enable)
106 return;
107 on_the_record_switch = enable;
[email protected]0ac83682010-01-22 17:46:27108 if (on_the_record_switch)
109 g_browser_process->io_thread()->ChangedToOnTheRecord();
initial.commit09911bf2008-07-26 23:55:29110}
111
112void RegisterPrefs(PrefService* local_state) {
113 local_state->RegisterListPref(prefs::kDnsStartupPrefetchList);
[email protected]03c5e862009-02-17 22:50:14114 local_state->RegisterListPref(prefs::kDnsHostReferralList);
initial.commit09911bf2008-07-26 23:55:29115}
116
117void RegisterUserPrefs(PrefService* user_prefs) {
118 user_prefs->RegisterBooleanPref(prefs::kDnsPrefetchingEnabled, true);
119}
120
121// When enabled, we use the following instance to service all requests in the
122// browser process.
[email protected]0ac83682010-01-22 17:46:27123// TODO(willchan): Look at killing this.
[email protected]1455ccf12010-08-18 16:32:14124static Predictor* g_predictor = NULL;
initial.commit09911bf2008-07-26 23:55:29125
126// This API is only used in the browser process.
[email protected]21dae9b2008-11-06 23:32:53127// It is called from an IPC message originating in the renderer. It currently
128// includes both Page-Scan, and Link-Hover prefetching.
[email protected]03c5e862009-02-17 22:50:14129// TODO(jar): Separate out link-hover prefetching, and page-scan results.
initial.commit09911bf2008-07-26 23:55:29130void DnsPrefetchList(const NameList& hostnames) {
[email protected]bff1f512010-08-15 15:13:49131 // TODO(jar): Push GURL transport further back into renderer, but this will
132 // require a Webkit change in the observer :-/.
[email protected]c5629c32010-06-23 01:22:43133 UrlList urls;
134 for (NameList::const_iterator it = hostnames.begin();
135 it < hostnames.end();
136 ++it) {
137 urls.push_back(GURL("http://" + *it + ":80"));
138 }
139
[email protected]ba4f1132010-10-09 02:02:35140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]74be069e82010-06-25 00:12:49141 DnsPrefetchMotivatedList(urls, UrlInfo::PAGE_SCAN_MOTIVATED);
[email protected]21dae9b2008-11-06 23:32:53142}
143
144static void DnsPrefetchMotivatedList(
[email protected]c5629c32010-06-23 01:22:43145 const UrlList& urls,
[email protected]74be069e82010-06-25 00:12:49146 UrlInfo::ResolutionMotivation motivation) {
[email protected]ba4f1132010-10-09 02:02:35147 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) ||
148 BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]1455ccf12010-08-18 16:32:14149 if (!predictor_enabled || NULL == g_predictor)
initial.commit09911bf2008-07-26 23:55:29150 return;
[email protected]ec86bea2009-12-08 18:35:14151
[email protected]ba4f1132010-10-09 02:02:35152 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
[email protected]1455ccf12010-08-18 16:32:14153 g_predictor->ResolveList(urls, motivation);
[email protected]ec86bea2009-12-08 18:35:14154 } else {
[email protected]ba4f1132010-10-09 02:02:35155 BrowserThread::PostTask(
156 BrowserThread::IO,
[email protected]ec86bea2009-12-08 18:35:14157 FROM_HERE,
[email protected]1455ccf12010-08-18 16:32:14158 NewRunnableMethod(g_predictor,
[email protected]74be069e82010-06-25 00:12:49159 &Predictor::ResolveList, urls, motivation));
[email protected]ec86bea2009-12-08 18:35:14160 }
initial.commit09911bf2008-07-26 23:55:29161}
162
[email protected]e7a5b7872008-12-10 23:52:43163// This API is used by the autocomplete popup box (where URLs are typed).
[email protected]e326922d2010-09-03 09:08:10164void AnticipateOmniboxUrl(const GURL& url, bool preconnectable) {
[email protected]ba4f1132010-10-09 02:02:35165 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]1455ccf12010-08-18 16:32:14166 if (!predictor_enabled || NULL == g_predictor)
initial.commit09911bf2008-07-26 23:55:29167 return;
[email protected]1455ccf12010-08-18 16:32:14168 if (!url.is_valid() || !url.has_host())
[email protected]760d970a2010-05-18 00:39:18169 return;
170
[email protected]1455ccf12010-08-18 16:32:14171 g_predictor->AnticipateOmniboxUrl(url, preconnectable);
initial.commit09911bf2008-07-26 23:55:29172}
173
[email protected]e326922d2010-09-03 09:08:10174void PreconnectUrlAndSubresources(const GURL& url) {
[email protected]e326922d2010-09-03 09:08:10175 if (!predictor_enabled || NULL == g_predictor)
176 return;
177 if (!url.is_valid() || !url.has_host())
178 return;
179
180 g_predictor->PreconnectUrlAndSubresources(url);
181}
182
183
initial.commit09911bf2008-07-26 23:55:29184//------------------------------------------------------------------------------
185// This section intermingles prefetch results with actual browser HTTP
186// network activity. It supports calculating of the benefit of a prefetch, as
187// well as recording what prefetched hostname resolutions might be potentially
188// helpful during the next chrome-startup.
189//------------------------------------------------------------------------------
190
[email protected]74be069e82010-06-25 00:12:49191void PredictFrameSubresources(const GURL& url) {
[email protected]ba4f1132010-10-09 02:02:35192 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]1455ccf12010-08-18 16:32:14193 if (!predictor_enabled || NULL == g_predictor)
[email protected]c5629c32010-06-23 01:22:43194 return;
[email protected]1455ccf12010-08-18 16:32:14195 g_predictor->PredictFrameSubresources(url);
[email protected]c5629c32010-06-23 01:22:43196}
197
[email protected]bff1f512010-08-15 15:13:49198void LearnAboutInitialNavigation(const GURL& url) {
[email protected]ba4f1132010-10-09 02:02:35199 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]bff1f512010-08-15 15:13:49200 if (!predictor_enabled || NULL == g_initial_observer )
201 return;
202 g_initial_observer->Append(url);
203}
204
[email protected]74be069e82010-06-25 00:12:49205void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) {
[email protected]ba4f1132010-10-09 02:02:35206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]1455ccf12010-08-18 16:32:14207 if (!predictor_enabled || NULL == g_predictor)
[email protected]c5629c32010-06-23 01:22:43208 return;
[email protected]1455ccf12010-08-18 16:32:14209 g_predictor->LearnFromNavigation(referring_url, target_url);
initial.commit09911bf2008-07-26 23:55:29210}
211
212// The observer class needs to connect starts and finishes of HTTP network
213// resolutions. We use the following type for that map.
[email protected]74be069e82010-06-25 00:12:49214typedef std::map<int, UrlInfo> ObservedResolutionMap;
initial.commit09911bf2008-07-26 23:55:29215
initial.commit09911bf2008-07-26 23:55:29216//------------------------------------------------------------------------------
[email protected]bff1f512010-08-15 15:13:49217// Member definitions for InitialObserver class.
initial.commit09911bf2008-07-26 23:55:29218
[email protected]bff1f512010-08-15 15:13:49219void InitialObserver::Append(const GURL& url) {
[email protected]ba4f1132010-10-09 02:02:35220 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]ec86bea2009-12-08 18:35:14221
[email protected]1455ccf12010-08-18 16:32:14222 if (!on_the_record_switch || NULL == g_predictor)
initial.commit09911bf2008-07-26 23:55:29223 return;
[email protected]bff1f512010-08-15 15:13:49224 if (kStartupResolutionCount <= first_navigations_.size())
225 return;
[email protected]f4ef861ba2010-07-28 22:37:23226
[email protected]bff1f512010-08-15 15:13:49227 if (url.SchemeIs("http") || url.SchemeIs("https")) {
228 const GURL url_without_path(url.GetWithEmptyPath());
229 if (first_navigations_.find(url_without_path) == first_navigations_.end())
230 first_navigations_[url_without_path] = base::TimeTicks::Now();
231 }
initial.commit09911bf2008-07-26 23:55:29232}
233
[email protected]bff1f512010-08-15 15:13:49234void InitialObserver::GetInitialDnsResolutionList(ListValue* startup_list) {
[email protected]ba4f1132010-10-09 02:02:35235 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
initial.commit09911bf2008-07-26 23:55:29236 DCHECK(startup_list);
initial.commit09911bf2008-07-26 23:55:29237 startup_list->Clear();
[email protected]602faf3c2009-06-27 14:35:44238 DCHECK_EQ(0u, startup_list->GetSize());
[email protected]74be069e82010-06-25 00:12:49239 startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion));
[email protected]bff1f512010-08-15 15:13:49240 for (FirstNavigations::iterator it = first_navigations_.begin();
241 it != first_navigations_.end();
[email protected]760d970a2010-05-18 00:39:18242 ++it) {
[email protected]1455ccf12010-08-18 16:32:14243 DCHECK(it->first == Predictor::CanonicalizeUrl(it->first));
[email protected]bff1f512010-08-15 15:13:49244 startup_list->Append(new StringValue(it->first.spec()));
initial.commit09911bf2008-07-26 23:55:29245 }
246}
247
[email protected]bff1f512010-08-15 15:13:49248void InitialObserver::GetFirstResolutionsHtml(std::string* output) {
[email protected]ba4f1132010-10-09 02:02:35249 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]ec86bea2009-12-08 18:35:14250
[email protected]f4ef861ba2010-07-28 22:37:23251 UrlInfo::UrlInfoTable resolution_list;
initial.commit09911bf2008-07-26 23:55:29252 {
[email protected]bff1f512010-08-15 15:13:49253 for (FirstNavigations::iterator it(first_navigations_.begin());
254 it != first_navigations_.end();
initial.commit09911bf2008-07-26 23:55:29255 it++) {
[email protected]f4ef861ba2010-07-28 22:37:23256 UrlInfo info;
[email protected]bff1f512010-08-15 15:13:49257 info.SetUrl(it->first);
258 info.set_time(it->second);
[email protected]f4ef861ba2010-07-28 22:37:23259 resolution_list.push_back(info);
initial.commit09911bf2008-07-26 23:55:29260 }
261 }
[email protected]74be069e82010-06-25 00:12:49262 UrlInfo::GetHtmlTable(resolution_list,
initial.commit09911bf2008-07-26 23:55:29263 "Future startups will prefetch DNS records for ", false, output);
264}
265
initial.commit09911bf2008-07-26 23:55:29266//------------------------------------------------------------------------------
267// Support observer to detect opening and closing of OffTheRecord windows.
[email protected]ec86bea2009-12-08 18:35:14268// This object lives on the UI thread.
initial.commit09911bf2008-07-26 23:55:29269
270class OffTheRecordObserver : public NotificationObserver {
271 public:
initial.commit09911bf2008-07-26 23:55:29272 void Register() {
[email protected]eca71da2009-05-22 03:06:57273 // TODO(pkasting): This test should not be necessary. See crbug.com/12475.
274 if (registrar_.IsEmpty()) {
275 registrar_.Add(this, NotificationType::BROWSER_CLOSED,
276 NotificationService::AllSources());
277 registrar_.Add(this, NotificationType::BROWSER_OPENED,
278 NotificationService::AllSources());
279 }
initial.commit09911bf2008-07-26 23:55:29280 }
281
282 void Observe(NotificationType type, const NotificationSource& source,
283 const NotificationDetails& details) {
[email protected]bfd04a62009-02-01 18:16:56284 switch (type.value) {
285 case NotificationType::BROWSER_OPENED:
initial.commit09911bf2008-07-26 23:55:29286 if (!Source<Browser>(source)->profile()->IsOffTheRecord())
287 break;
[email protected]ec86bea2009-12-08 18:35:14288 ++count_off_the_record_windows_;
initial.commit09911bf2008-07-26 23:55:29289 OnTheRecord(false);
290 break;
291
[email protected]bfd04a62009-02-01 18:16:56292 case NotificationType::BROWSER_CLOSED:
initial.commit09911bf2008-07-26 23:55:29293 if (!Source<Browser>(source)->profile()->IsOffTheRecord())
[email protected]ec86bea2009-12-08 18:35:14294 break; // Ignore ordinary windows.
295 DCHECK_LT(0, count_off_the_record_windows_);
296 if (0 >= count_off_the_record_windows_) // Defensive coding.
297 break;
298 if (--count_off_the_record_windows_)
299 break; // Still some windows are incognito.
initial.commit09911bf2008-07-26 23:55:29300 OnTheRecord(true);
301 break;
302
303 default:
304 break;
305 }
306 }
307
308 private:
[email protected]94dc2282009-05-26 19:32:32309 friend struct DefaultSingletonTraits<OffTheRecordObserver>;
[email protected]ec86bea2009-12-08 18:35:14310 OffTheRecordObserver() : count_off_the_record_windows_(0) {}
311 ~OffTheRecordObserver() {}
[email protected]94dc2282009-05-26 19:32:32312
[email protected]f1c8a2b2009-05-22 01:52:43313 NotificationRegistrar registrar_;
initial.commit09911bf2008-07-26 23:55:29314 int count_off_the_record_windows_;
315
[email protected]e8013b32008-10-27 18:55:52316 DISALLOW_COPY_AND_ASSIGN(OffTheRecordObserver);
initial.commit09911bf2008-07-26 23:55:29317};
318
initial.commit09911bf2008-07-26 23:55:29319//------------------------------------------------------------------------------
320// This section supports the about:dns page.
321//------------------------------------------------------------------------------
322
323// Provide global support for the about:dns page.
[email protected]74be069e82010-06-25 00:12:49324void PredictorGetHtmlInfo(std::string* output) {
[email protected]ba4f1132010-10-09 02:02:35325 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]ec86bea2009-12-08 18:35:14326
initial.commit09911bf2008-07-26 23:55:29327 output->append("<html><head><title>About DNS</title>"
328 // We'd like the following no-cache... but it doesn't work.
329 // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">"
330 "</head><body>");
[email protected]1455ccf12010-08-18 16:32:14331 if (!predictor_enabled || NULL == g_predictor) {
[email protected]c45662492010-10-05 00:45:22332 output->append("DNS pre-resolution and TCP pre-connection is disabled.");
initial.commit09911bf2008-07-26 23:55:29333 } else {
334 if (!on_the_record_switch) {
335 output->append("Incognito mode is active in a window.");
336 } else {
[email protected]bff1f512010-08-15 15:13:49337 // List items fetched at startup.
338 if (g_initial_observer)
339 g_initial_observer->GetFirstResolutionsHtml(output);
340 // Show list of subresource predictions and stats.
[email protected]1455ccf12010-08-18 16:32:14341 g_predictor->GetHtmlReferrerLists(output);
[email protected]bff1f512010-08-15 15:13:49342 // Show list of prediction results.
[email protected]1455ccf12010-08-18 16:32:14343 g_predictor->GetHtmlInfo(output);
initial.commit09911bf2008-07-26 23:55:29344 }
345 }
346 output->append("</body></html>");
347}
348
349//------------------------------------------------------------------------------
[email protected]0ac83682010-01-22 17:46:27350// This section intializes global DNS prefetch services.
initial.commit09911bf2008-07-26 23:55:29351//------------------------------------------------------------------------------
352
[email protected]74be069e82010-06-25 00:12:49353static void InitNetworkPredictor(TimeDelta max_dns_queue_delay,
354 size_t max_concurrent, PrefService* user_prefs, PrefService* local_state,
[email protected]760d970a2010-05-18 00:39:18355 bool preconnect_enabled) {
[email protected]ba4f1132010-10-09 02:02:35356 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
initial.commit09911bf2008-07-26 23:55:29357
[email protected]0ac83682010-01-22 17:46:27358 bool prefetching_enabled =
359 user_prefs->GetBoolean(prefs::kDnsPrefetchingEnabled);
[email protected]cf5a15c82008-09-28 18:01:34360
[email protected]0ac83682010-01-22 17:46:27361 // Gather the list of hostnames to prefetch on startup.
[email protected]c5629c32010-06-23 01:22:43362 UrlList urls =
[email protected]74be069e82010-06-25 00:12:49363 GetPredictedUrlListAtStartup(user_prefs, local_state);
[email protected]cf5a15c82008-09-28 18:01:34364
[email protected]0ac83682010-01-22 17:46:27365 ListValue* referral_list =
366 static_cast<ListValue*>(
367 local_state->GetMutableList(prefs::kDnsHostReferralList)->DeepCopy());
368
[email protected]74be069e82010-06-25 00:12:49369 g_browser_process->io_thread()->InitNetworkPredictor(
370 prefetching_enabled, max_dns_queue_delay, max_concurrent, urls,
[email protected]760d970a2010-05-18 00:39:18371 referral_list, preconnect_enabled);
initial.commit09911bf2008-07-26 23:55:29372}
373
[email protected]74be069e82010-06-25 00:12:49374void FinalizePredictorInitialization(
375 Predictor* global_predictor,
[email protected]c5629c32010-06-23 01:22:43376 const UrlList& startup_urls,
[email protected]0ac83682010-01-22 17:46:27377 ListValue* referral_list) {
[email protected]ba4f1132010-10-09 02:02:35378 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]1455ccf12010-08-18 16:32:14379 g_predictor = global_predictor;
[email protected]bff1f512010-08-15 15:13:49380 g_initial_observer = new InitialObserver();
[email protected]ec86bea2009-12-08 18:35:14381
[email protected]847e54f2010-01-23 16:37:56382 // Prefetch these hostnames on startup.
[email protected]c5629c32010-06-23 01:22:43383 DnsPrefetchMotivatedList(startup_urls,
[email protected]74be069e82010-06-25 00:12:49384 UrlInfo::STARTUP_LIST_MOTIVATED);
[email protected]1455ccf12010-08-18 16:32:14385 g_predictor->DeserializeReferrersThenDelete(referral_list);
[email protected]1933eb202009-02-19 18:23:25386}
387
[email protected]74be069e82010-06-25 00:12:49388void FreePredictorResources() {
[email protected]ba4f1132010-10-09 02:02:35389 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]1455ccf12010-08-18 16:32:14390 g_predictor = NULL; // Owned and released by io_thread.cc.
[email protected]bff1f512010-08-15 15:13:49391 delete g_initial_observer;
392 g_initial_observer = NULL;
[email protected]fd2f8afe2009-06-11 21:53:55393}
394
[email protected]fd2f8afe2009-06-11 21:53:55395//------------------------------------------------------------------------------
initial.commit09911bf2008-07-26 23:55:29396// Functions to handle saving of hostnames from one session to the next, to
397// expedite startup times.
398
[email protected]ec86bea2009-12-08 18:35:14399static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread(
400 ListValue* startup_list,
401 ListValue* referral_list,
402 base::WaitableEvent* completion) {
[email protected]ba4f1132010-10-09 02:02:35403 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
[email protected]ec86bea2009-12-08 18:35:14404
[email protected]1455ccf12010-08-18 16:32:14405 if (NULL == g_predictor) {
[email protected]ec86bea2009-12-08 18:35:14406 completion->Signal();
initial.commit09911bf2008-07-26 23:55:29407 return;
[email protected]ec86bea2009-12-08 18:35:14408 }
409
[email protected]bff1f512010-08-15 15:13:49410 if (g_initial_observer)
411 g_initial_observer->GetInitialDnsResolutionList(startup_list);
[email protected]ec86bea2009-12-08 18:35:14412
413 // TODO(jar): Trimming should be done more regularly, such as every 48 hours
414 // of physical time, or perhaps after 48 hours of running (excluding time
415 // between sessions possibly).
416 // For now, we'll just trim at shutdown.
[email protected]1455ccf12010-08-18 16:32:14417 g_predictor->TrimReferrers();
418 g_predictor->SerializeReferrers(referral_list);
[email protected]ec86bea2009-12-08 18:35:14419
420 completion->Signal();
initial.commit09911bf2008-07-26 23:55:29421}
422
[email protected]74be069e82010-06-25 00:12:49423void SavePredictorStateForNextStartupAndTrim(PrefService* prefs) {
[email protected]ba4f1132010-10-09 02:02:35424 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]ec86bea2009-12-08 18:35:14425
[email protected]1455ccf12010-08-18 16:32:14426 if (!predictor_enabled || g_predictor == NULL)
[email protected]ec86bea2009-12-08 18:35:14427 return;
428
429 base::WaitableEvent completion(true, false);
430
[email protected]ba4f1132010-10-09 02:02:35431 bool posted = BrowserThread::PostTask(
432 BrowserThread::IO,
[email protected]ec86bea2009-12-08 18:35:14433 FROM_HERE,
434 NewRunnableFunction(SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread,
435 prefs->GetMutableList(prefs::kDnsStartupPrefetchList),
436 prefs->GetMutableList(prefs::kDnsHostReferralList),
437 &completion));
438
439 DCHECK(posted);
440 if (posted)
441 completion.Wait();
442}
443
[email protected]74be069e82010-06-25 00:12:49444static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs,
445 PrefService* local_state) {
[email protected]ba4f1132010-10-09 02:02:35446 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]c5629c32010-06-23 01:22:43447 UrlList urls;
448 // Recall list of URLs we learned about during last session.
initial.commit09911bf2008-07-26 23:55:29449 // This may catch secondary hostnames, pulled in by the homepages. It will
450 // also catch more of the "primary" home pages, since that was (presumably)
451 // rendered first (and will be rendered first this time too).
452 ListValue* startup_list =
453 local_state->GetMutableList(prefs::kDnsStartupPrefetchList);
454 if (startup_list) {
[email protected]760d970a2010-05-18 00:39:18455 ListValue::iterator it = startup_list->begin();
456 int format_version = -1;
457 if (it != startup_list->end() &&
458 (*it)->GetAsInteger(&format_version) &&
[email protected]74be069e82010-06-25 00:12:49459 format_version == kPredictorStartupFormatVersion) {
[email protected]760d970a2010-05-18 00:39:18460 ++it;
461 for (; it != startup_list->end(); ++it) {
[email protected]c5629c32010-06-23 01:22:43462 std::string url_spec;
463 if (!(*it)->GetAsString(&url_spec)) {
464 LOG(DFATAL);
[email protected]760d970a2010-05-18 00:39:18465 break; // Format incompatibility.
[email protected]c5629c32010-06-23 01:22:43466 }
467 GURL url(url_spec);
468 if (!url.has_host() || !url.has_scheme()) {
469 LOG(DFATAL);
[email protected]760d970a2010-05-18 00:39:18470 break; // Format incompatibility.
[email protected]c5629c32010-06-23 01:22:43471 }
[email protected]760d970a2010-05-18 00:39:18472
[email protected]c5629c32010-06-23 01:22:43473 urls.push_back(url);
[email protected]760d970a2010-05-18 00:39:18474 }
initial.commit09911bf2008-07-26 23:55:29475 }
476 }
477
478 // Prepare for any static home page(s) the user has in prefs. The user may
479 // have a LOT of tab's specified, so we may as well try to warm them all.
480 SessionStartupPref tab_start_pref =
481 SessionStartupPref::GetStartupPref(user_prefs);
482 if (SessionStartupPref::URLS == tab_start_pref.type) {
483 for (size_t i = 0; i < tab_start_pref.urls.size(); i++) {
484 GURL gurl = tab_start_pref.urls[i];
[email protected]c5629c32010-06-23 01:22:43485 if (!gurl.is_valid() || gurl.SchemeIsFile() || gurl.host().empty())
486 continue;
487 if (gurl.SchemeIs("http") || gurl.SchemeIs("https"))
488 urls.push_back(gurl.GetWithEmptyPath());
initial.commit09911bf2008-07-26 23:55:29489 }
490 }
491
[email protected]c5629c32010-06-23 01:22:43492 if (urls.empty())
493 urls.push_back(GURL("http://www.google.com:80"));
initial.commit09911bf2008-07-26 23:55:29494
[email protected]c5629c32010-06-23 01:22:43495 return urls;
[email protected]03c5e862009-02-17 22:50:14496}
initial.commit09911bf2008-07-26 23:55:29497
[email protected]602faf3c2009-06-27 14:35:44498//------------------------------------------------------------------------------
499// Methods for the helper class that is used to startup and teardown the whole
[email protected]1455ccf12010-08-18 16:32:14500// g_predictor system (both DNS pre-resolution and TCP/IP connection
501// prewarming).
[email protected]602faf3c2009-06-27 14:35:44502
[email protected]74be069e82010-06-25 00:12:49503PredictorInit::PredictorInit(PrefService* user_prefs,
[email protected]760d970a2010-05-18 00:39:18504 PrefService* local_state,
[email protected]e326922d2010-09-03 09:08:10505 bool preconnect_enabled) {
[email protected]ba4f1132010-10-09 02:02:35506 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
[email protected]602faf3c2009-06-27 14:35:44507 // Set up a field trial to see what disabling DNS pre-resolution does to
508 // latency of page loads.
[email protected]835d7c82010-10-14 04:38:38509 base::FieldTrial::Probability kDivisor = 1000;
[email protected]602faf3c2009-06-27 14:35:44510 // For each option (i.e., non-default), we have a fixed probability.
[email protected]1e9bbd22010-10-15 16:42:45511 base::FieldTrial::Probability kProbabilityPerGroup = 100; // 10% probability.
[email protected]602faf3c2009-06-27 14:35:44512
[email protected]835d7c82010-10-14 04:38:38513 trial_ = new base::FieldTrial("DnsImpact", kDivisor);
[email protected]602faf3c2009-06-27 14:35:44514
515 // First option is to disable prefetching completely.
[email protected]58d2d2d2010-08-05 22:46:33516 int disabled_prefetch = trial_->AppendGroup("disabled_prefetch",
[email protected]602faf3c2009-06-27 14:35:44517 kProbabilityPerGroup);
[email protected]f9f4841b2010-03-20 05:41:42518
519
520 // We're running two experiments at the same time. The first set of trials
521 // modulates the delay-time until we declare a congestion event (and purge
522 // our queue). The second modulates the number of concurrent resolutions
523 // we do at any time. Users are in exactly one trial (or the default) during
524 // any one run, and hence only one experiment at a time.
525 // Experiment 1:
[email protected]85d48aef2009-07-18 06:17:19526 // Set congestion detection at 250, 500, or 750ms, rather than the 1 second
527 // default.
[email protected]58d2d2d2010-08-05 22:46:33528 int max_250ms_prefetch = trial_->AppendGroup("max_250ms_queue_prefetch",
[email protected]85d48aef2009-07-18 06:17:19529 kProbabilityPerGroup);
[email protected]58d2d2d2010-08-05 22:46:33530 int max_500ms_prefetch = trial_->AppendGroup("max_500ms_queue_prefetch",
[email protected]602faf3c2009-06-27 14:35:44531 kProbabilityPerGroup);
[email protected]58d2d2d2010-08-05 22:46:33532 int max_750ms_prefetch = trial_->AppendGroup("max_750ms_queue_prefetch",
[email protected]85d48aef2009-07-18 06:17:19533 kProbabilityPerGroup);
[email protected]602faf3c2009-06-27 14:35:44534 // Set congestion detection at 2 seconds instead of the 1 second default.
[email protected]58d2d2d2010-08-05 22:46:33535 int max_2s_prefetch = trial_->AppendGroup("max_2s_queue_prefetch",
[email protected]602faf3c2009-06-27 14:35:44536 kProbabilityPerGroup);
[email protected]f9f4841b2010-03-20 05:41:42537 // Experiment 2:
538 // Set max simultaneous resoultions to 2, 4, or 6, and scale the congestion
539 // limit proportionally (so we don't impact average probability of asserting
540 // congesion very much).
541 int max_2_concurrent_prefetch = trial_->AppendGroup(
[email protected]58d2d2d2010-08-05 22:46:33542 "max_2 concurrent_prefetch", kProbabilityPerGroup);
[email protected]f9f4841b2010-03-20 05:41:42543 int max_4_concurrent_prefetch = trial_->AppendGroup(
[email protected]58d2d2d2010-08-05 22:46:33544 "max_4 concurrent_prefetch", kProbabilityPerGroup);
[email protected]f9f4841b2010-03-20 05:41:42545 int max_6_concurrent_prefetch = trial_->AppendGroup(
[email protected]58d2d2d2010-08-05 22:46:33546 "max_6 concurrent_prefetch", kProbabilityPerGroup);
[email protected]602faf3c2009-06-27 14:35:44547
[email protected]58d2d2d2010-08-05 22:46:33548 trial_->AppendGroup("default_enabled_prefetch",
[email protected]835d7c82010-10-14 04:38:38549 base::FieldTrial::kAllRemainingProbability);
[email protected]e695fbd62009-06-30 16:31:54550
[email protected]8d53d502010-01-11 19:13:08551 // We will register the incognito observer regardless of whether prefetching
552 // is enabled, as it is also used to clear the host cache.
553 Singleton<OffTheRecordObserver>::get()->Register();
554
[email protected]602faf3c2009-06-27 14:35:44555 if (trial_->group() != disabled_prefetch) {
556 // Initialize the DNS prefetch system.
[email protected]8d53d502010-01-11 19:13:08557 size_t max_concurrent = kMaxPrefetchConcurrentLookups;
[email protected]8d53d502010-01-11 19:13:08558 int max_queueing_delay_ms = kMaxPrefetchQueueingDelayMs;
[email protected]602faf3c2009-06-27 14:35:44559
[email protected]85d48aef2009-07-18 06:17:19560 if (trial_->group() == max_250ms_prefetch)
561 max_queueing_delay_ms = 250;
[email protected]602faf3c2009-06-27 14:35:44562 else if (trial_->group() == max_500ms_prefetch)
563 max_queueing_delay_ms = 500;
[email protected]85d48aef2009-07-18 06:17:19564 else if (trial_->group() == max_750ms_prefetch)
565 max_queueing_delay_ms = 750;
[email protected]602faf3c2009-06-27 14:35:44566 else if (trial_->group() == max_2s_prefetch)
567 max_queueing_delay_ms = 2000;
[email protected]f9f4841b2010-03-20 05:41:42568 if (trial_->group() == max_2_concurrent_prefetch)
569 max_concurrent = 2;
570 else if (trial_->group() == max_4_concurrent_prefetch)
571 max_concurrent = 4;
572 else if (trial_->group() == max_6_concurrent_prefetch)
573 max_concurrent = 6;
574 // Scale acceptable delay so we don't cause congestion limits to fire as
575 // we modulate max_concurrent (*if* we are modulating it at all).
576 max_queueing_delay_ms = (kMaxPrefetchQueueingDelayMs *
577 kMaxPrefetchConcurrentLookups) / max_concurrent;
[email protected]602faf3c2009-06-27 14:35:44578
579 TimeDelta max_queueing_delay(
580 TimeDelta::FromMilliseconds(max_queueing_delay_ms));
581
[email protected]1455ccf12010-08-18 16:32:14582 DCHECK(!g_predictor);
[email protected]74be069e82010-06-25 00:12:49583 InitNetworkPredictor(max_queueing_delay, max_concurrent, user_prefs,
584 local_state, preconnect_enabled);
[email protected]602faf3c2009-06-27 14:35:44585 }
586}
587
[email protected]835d7c82010-10-14 04:38:38588PredictorInit::~PredictorInit() {
589}
[email protected]760d970a2010-05-18 00:39:18590
initial.commit09911bf2008-07-26 23:55:29591} // namespace chrome_browser_net