OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/net/predictor_api.h" | 5 #include "chrome/browser/net/predictor_api.h" |
6 | 6 |
7 #include <map> | 7 #include <map> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 19 matching lines...) Expand all Loading... | |
30 #include "content/common/notification_registrar.h" | 30 #include "content/common/notification_registrar.h" |
31 #include "content/common/notification_service.h" | 31 #include "content/common/notification_service.h" |
32 #include "net/base/host_resolver.h" | 32 #include "net/base/host_resolver.h" |
33 #include "net/base/host_resolver_impl.h" | 33 #include "net/base/host_resolver_impl.h" |
34 | 34 |
35 using base::Time; | 35 using base::Time; |
36 using base::TimeDelta; | 36 using base::TimeDelta; |
37 | 37 |
38 namespace chrome_browser_net { | 38 namespace chrome_browser_net { |
39 | 39 |
40 static void DnsPrefetchMotivatedList(const UrlList& urls, | |
41 UrlInfo::ResolutionMotivation motivation); | |
42 | 40 |
43 static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs, | |
44 PrefService* local_state); | |
45 | 41 |
46 // Given that the underlying Chromium resolver defaults to a total maximum of | 42 // Given that the underlying Chromium resolver defaults to a total maximum of |
47 // 8 paralell resolutions, we will avoid any chance of starving navigational | 43 // 8 paralell resolutions, we will avoid any chance of starving navigational |
48 // resolutions by limiting the number of paralell speculative resolutions. | 44 // resolutions by limiting the number of paralell speculative resolutions. |
49 // TODO(jar): Move this limitation into the resolver. | 45 // TODO(jar): Move this limitation into the resolver. |
50 // static | 46 // static |
51 const size_t PredictorInit::kMaxSpeculativeParallelResolves = 3; | 47 const size_t PredictorInit::kMaxSpeculativeParallelResolves = 3; |
52 | 48 |
53 // To control our congestion avoidance system, which discards a queue when | 49 // To control our congestion avoidance system, which discards a queue when |
54 // resolutions are "taking too long," we need an expected resolution time. | 50 // resolutions are "taking too long," we need an expected resolution time. |
(...skipping 11 matching lines...) Expand all Loading... | |
66 | 62 |
67 // The next constant specifies an amount of queueing delay that is "too large," | 63 // The next constant specifies an amount of queueing delay that is "too large," |
68 // and indicative of problems with resolutions (perhaps due to an overloaded | 64 // and indicative of problems with resolutions (perhaps due to an overloaded |
69 // router, or such). When we exceed this delay, congestion avoidance will kick | 65 // router, or such). When we exceed this delay, congestion avoidance will kick |
70 // in and all speculations in the queue will be discarded. | 66 // in and all speculations in the queue will be discarded. |
71 // static | 67 // static |
72 const int PredictorInit::kMaxSpeculativeResolveQueueDelayMs = | 68 const int PredictorInit::kMaxSpeculativeResolveQueueDelayMs = |
73 (kExpectedResolutionTimeMs * kTypicalSpeculativeGroupSize) / | 69 (kExpectedResolutionTimeMs * kTypicalSpeculativeGroupSize) / |
74 kMaxSpeculativeParallelResolves; | 70 kMaxSpeculativeParallelResolves; |
75 | 71 |
76 // A version number for prefs that are saved. This should be incremented when | |
77 // we change the format so that we discard old data. | |
78 static const int kPredictorStartupFormatVersion = 1; | |
79 | |
80 // There will only be one instance ever created of the following Observer class. | |
81 // The InitialObserver lives on the IO thread, and monitors navigations made by | |
82 // the network stack. This is only used to identify startup time resolutions | |
83 // (for re-resolution during our next process startup). | |
84 // TODO(jar): Consider preconnecting at startup, which may be faster than | |
85 // waiting for render process to start and request a connection. | |
86 class InitialObserver { | |
87 public: | |
88 // Recording of when we observed each navigation. | |
89 typedef std::map<GURL, base::TimeTicks> FirstNavigations; | |
90 | |
91 // Potentially add a new URL to our startup list. | |
92 void Append(const GURL& url); | |
93 | |
94 // Get an HTML version of our current planned first_navigations_. | |
95 void GetFirstResolutionsHtml(std::string* output); | |
96 | |
97 // Persist the current first_navigations_ for storage in a list. | |
98 void GetInitialDnsResolutionList(ListValue* startup_list); | |
99 | |
100 // Discards all initial loading history. | |
101 void DiscardInitialNavigationHistory() { first_navigations_.clear(); } | |
102 | |
103 private: | |
104 // List of the first N URL resolutions observed in this run. | |
105 FirstNavigations first_navigations_; | |
106 | |
107 // The number of URLs we'll save for pre-resolving at next startup. | |
108 static const size_t kStartupResolutionCount = 10; | |
109 }; | |
110 | |
111 // TODO(willchan): Look at killing this global. | |
112 static InitialObserver* g_initial_observer = NULL; | |
113 | |
114 //------------------------------------------------------------------------------ | 72 //------------------------------------------------------------------------------ |
115 // This section contains all the globally accessable API entry points for the | 73 // This section contains all the globally accessable API entry points for the |
116 // DNS Prefetching feature. | 74 // DNS Prefetching feature. |
117 //------------------------------------------------------------------------------ | 75 //------------------------------------------------------------------------------ |
118 | 76 |
119 // Status of speculative DNS resolution and speculative TCP/IP connection | |
120 // feature. | |
121 static bool predictor_enabled = true; | |
122 | |
123 // Cached inverted copy of the off_the_record pref. | |
124 static bool on_the_record_switch = true; | |
125 | |
126 // Enable/disable Dns prefetch activity (either via command line, or via pref). | |
127 void EnablePredictor(bool enable) { | |
128 // NOTE: this is invoked on the UI thread. | |
129 predictor_enabled = enable; | |
130 } | |
131 | |
132 void OnTheRecord(bool enable) { | |
133 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
134 if (on_the_record_switch == enable) | |
135 return; | |
136 on_the_record_switch = enable; | |
137 if (on_the_record_switch) | |
138 g_browser_process->io_thread()->ChangedToOnTheRecord(); | |
139 } | |
140 | |
141 void DiscardInitialNavigationHistory() { | |
142 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
143 if (g_initial_observer) | |
144 g_initial_observer->DiscardInitialNavigationHistory(); | |
145 } | |
146 | |
147 void RegisterUserPrefs(PrefService* user_prefs) { | 77 void RegisterUserPrefs(PrefService* user_prefs) { |
148 user_prefs->RegisterListPref(prefs::kDnsPrefetchingStartupList, | 78 user_prefs->RegisterListPref(prefs::kDnsPrefetchingStartupList, |
149 PrefService::UNSYNCABLE_PREF); | 79 PrefService::UNSYNCABLE_PREF); |
150 user_prefs->RegisterListPref(prefs::kDnsPrefetchingHostReferralList, | 80 user_prefs->RegisterListPref(prefs::kDnsPrefetchingHostReferralList, |
151 PrefService::UNSYNCABLE_PREF); | 81 PrefService::UNSYNCABLE_PREF); |
152 } | 82 } |
153 | 83 |
154 // When enabled, we use the following instance to service all requests in the | |
155 // browser process. | |
156 // TODO(willchan): Look at killing this. | |
157 static Predictor* g_predictor = NULL; | |
158 | 84 |
159 // This API is only used in the browser process. | |
160 // It is called from an IPC message originating in the renderer. It currently | |
161 // includes both Page-Scan, and Link-Hover prefetching. | |
162 // TODO(jar): Separate out link-hover prefetching, and page-scan results. | |
163 void DnsPrefetchList(const NameList& hostnames) { | |
164 // TODO(jar): Push GURL transport further back into renderer, but this will | |
165 // require a Webkit change in the observer :-/. | |
166 UrlList urls; | |
167 for (NameList::const_iterator it = hostnames.begin(); | |
168 it < hostnames.end(); | |
169 ++it) { | |
170 urls.push_back(GURL("http://" + *it + ":80")); | |
171 } | |
172 | |
173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
174 DnsPrefetchMotivatedList(urls, UrlInfo::PAGE_SCAN_MOTIVATED); | |
175 } | |
176 | |
177 static void DnsPrefetchMotivatedList( | |
178 const UrlList& urls, | |
179 UrlInfo::ResolutionMotivation motivation) { | |
180 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || | |
181 BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
182 if (!predictor_enabled || NULL == g_predictor) | |
183 return; | |
184 | |
185 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { | |
186 g_predictor->ResolveList(urls, motivation); | |
187 } else { | |
188 BrowserThread::PostTask( | |
189 BrowserThread::IO, | |
190 FROM_HERE, | |
191 NewRunnableMethod(g_predictor, | |
192 &Predictor::ResolveList, urls, motivation)); | |
193 } | |
194 } | |
195 | |
196 // This API is used by the autocomplete popup box (where URLs are typed). | |
197 void AnticipateOmniboxUrl(const GURL& url, bool preconnectable) { | |
198 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
199 if (!predictor_enabled || NULL == g_predictor) | |
200 return; | |
201 if (!url.is_valid() || !url.has_host()) | |
202 return; | |
203 | |
204 g_predictor->AnticipateOmniboxUrl(url, preconnectable); | |
205 } | |
206 | |
207 void PreconnectUrlAndSubresources(const GURL& url) { | |
208 if (!predictor_enabled || NULL == g_predictor) | |
209 return; | |
210 if (!url.is_valid() || !url.has_host()) | |
211 return; | |
212 | |
213 g_predictor->PreconnectUrlAndSubresources(url); | |
214 } | |
215 | |
216 | |
217 //------------------------------------------------------------------------------ | |
218 // This section intermingles prefetch results with actual browser HTTP | |
219 // network activity. It supports calculating of the benefit of a prefetch, as | |
220 // well as recording what prefetched hostname resolutions might be potentially | |
221 // helpful during the next chrome-startup. | |
222 //------------------------------------------------------------------------------ | |
223 | |
224 void PredictFrameSubresources(const GURL& url) { | |
225 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
226 if (!predictor_enabled || NULL == g_predictor) | |
227 return; | |
228 g_predictor->PredictFrameSubresources(url); | |
229 } | |
230 | |
231 void LearnAboutInitialNavigation(const GURL& url) { | |
232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
233 if (!predictor_enabled || NULL == g_initial_observer ) | |
234 return; | |
235 g_initial_observer->Append(url); | |
236 } | |
237 | |
238 void LearnFromNavigation(const GURL& referring_url, const GURL& target_url) { | |
239 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
240 if (!predictor_enabled || NULL == g_predictor) | |
241 return; | |
242 g_predictor->LearnFromNavigation(referring_url, target_url); | |
243 } | |
244 | 85 |
245 // The observer class needs to connect starts and finishes of HTTP network | 86 // The observer class needs to connect starts and finishes of HTTP network |
246 // resolutions. We use the following type for that map. | 87 // resolutions. We use the following type for that map. |
247 typedef std::map<int, UrlInfo> ObservedResolutionMap; | 88 typedef std::map<int, UrlInfo> ObservedResolutionMap; |
248 | 89 |
249 //------------------------------------------------------------------------------ | 90 //------------------------------------------------------------------------------ |
250 // Member definitions for InitialObserver class. | |
251 | |
252 void InitialObserver::Append(const GURL& url) { | |
253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
254 | |
255 if (!on_the_record_switch || NULL == g_predictor) | |
256 return; | |
257 if (kStartupResolutionCount <= first_navigations_.size()) | |
258 return; | |
259 | |
260 DCHECK(url.SchemeIs("http") || url.SchemeIs("https")); | |
261 DCHECK_EQ(url, Predictor::CanonicalizeUrl(url)); | |
262 if (first_navigations_.find(url) == first_navigations_.end()) | |
263 first_navigations_[url] = base::TimeTicks::Now(); | |
264 } | |
265 | |
266 void InitialObserver::GetInitialDnsResolutionList(ListValue* startup_list) { | |
267 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
268 DCHECK(startup_list); | |
269 startup_list->Clear(); | |
270 DCHECK_EQ(0u, startup_list->GetSize()); | |
271 startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion)); | |
272 for (FirstNavigations::iterator it = first_navigations_.begin(); | |
273 it != first_navigations_.end(); | |
274 ++it) { | |
275 DCHECK(it->first == Predictor::CanonicalizeUrl(it->first)); | |
276 startup_list->Append(new StringValue(it->first.spec())); | |
277 } | |
278 } | |
279 | |
280 void InitialObserver::GetFirstResolutionsHtml(std::string* output) { | |
281 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
282 | |
283 UrlInfo::UrlInfoTable resolution_list; | |
284 { | |
285 for (FirstNavigations::iterator it(first_navigations_.begin()); | |
286 it != first_navigations_.end(); | |
287 it++) { | |
288 UrlInfo info; | |
289 info.SetUrl(it->first); | |
290 info.set_time(it->second); | |
291 resolution_list.push_back(info); | |
292 } | |
293 } | |
294 UrlInfo::GetHtmlTable(resolution_list, | |
295 "Future startups will prefetch DNS records for ", false, output); | |
296 } | |
297 | |
298 //------------------------------------------------------------------------------ | |
299 // Support observer to detect opening and closing of OffTheRecord windows. | 91 // Support observer to detect opening and closing of OffTheRecord windows. |
300 // This object lives on the UI thread. | 92 // This object lives on the UI thread. |
301 | 93 |
302 class OffTheRecordObserver : public NotificationObserver { | 94 class OffTheRecordObserver : public NotificationObserver { |
303 public: | 95 public: |
304 void Register() { | 96 void Register() { |
305 // TODO(pkasting): This test should not be necessary. See crbug.com/12475. | 97 // TODO(pkasting): This test should not be necessary. See crbug.com/12475. |
306 if (registrar_.IsEmpty()) { | 98 if (registrar_.IsEmpty()) { |
307 registrar_.Add(this, NotificationType::BROWSER_CLOSED, | 99 registrar_.Add(this, NotificationType::BROWSER_CLOSED, |
308 NotificationService::AllSources()); | 100 NotificationService::AllSources()); |
309 registrar_.Add(this, NotificationType::BROWSER_OPENED, | 101 registrar_.Add(this, NotificationType::BROWSER_OPENED, |
310 NotificationService::AllSources()); | 102 NotificationService::AllSources()); |
311 } | 103 } |
312 } | 104 } |
313 | 105 |
314 void Observe(NotificationType type, const NotificationSource& source, | 106 void Observe(NotificationType type, const NotificationSource& source, |
315 const NotificationDetails& details) { | 107 const NotificationDetails& details) { |
108 Profile* profile = NULL; | |
316 switch (type.value) { | 109 switch (type.value) { |
317 case NotificationType::BROWSER_OPENED: | 110 case NotificationType::BROWSER_OPENED: |
318 if (!Source<Browser>(source)->profile()->IsOffTheRecord()) | 111 profile = Source<Browser>(source)->profile(); |
112 if (!profile->IsOffTheRecord()) | |
319 break; | 113 break; |
320 ++count_off_the_record_windows_; | 114 profile->GetPredictor()->HandleIncognitoBrowserOpened(); |
321 OnTheRecord(false); | 115 profile->PredictorOnTheRecord(false); |
322 break; | 116 break; |
323 | 117 |
324 case NotificationType::BROWSER_CLOSED: | 118 case NotificationType::BROWSER_CLOSED: |
325 if (!Source<Browser>(source)->profile()->IsOffTheRecord()) | 119 profile = Source<Browser>(source)->profile(); |
120 if (!profile->IsOffTheRecord()) | |
326 break; // Ignore ordinary windows. | 121 break; // Ignore ordinary windows. |
Miranda Callahan
2011/07/21 14:38:04
indent "break;
rpetterson
2011/08/10 02:24:46
Done.
| |
327 DCHECK_LT(0, count_off_the_record_windows_); | 122 if (profile->GetPredictor()->HandleIncognitoBrowserClosed()) |
328 if (0 >= count_off_the_record_windows_) // Defensive coding. | 123 profile->PredictorOnTheRecord(true); |
329 break; | |
330 if (--count_off_the_record_windows_) | |
331 break; // Still some windows are incognito. | |
332 OnTheRecord(true); | |
333 break; | 124 break; |
334 | 125 |
335 default: | 126 default: |
336 break; | 127 break; |
337 } | 128 } |
338 } | 129 } |
339 | 130 |
340 private: | 131 private: |
341 friend struct base::DefaultLazyInstanceTraits<OffTheRecordObserver>; | 132 friend struct base::DefaultLazyInstanceTraits<OffTheRecordObserver>; |
342 | 133 |
343 OffTheRecordObserver() : count_off_the_record_windows_(0) {} | 134 OffTheRecordObserver() {} |
344 ~OffTheRecordObserver() {} | 135 ~OffTheRecordObserver() {} |
345 | 136 |
346 NotificationRegistrar registrar_; | 137 NotificationRegistrar registrar_; |
347 int count_off_the_record_windows_; | |
348 | 138 |
349 DISALLOW_COPY_AND_ASSIGN(OffTheRecordObserver); | 139 DISALLOW_COPY_AND_ASSIGN(OffTheRecordObserver); |
350 }; | 140 }; |
351 | 141 |
352 static base::LazyInstance<OffTheRecordObserver> g_off_the_record_observer( | 142 static base::LazyInstance<OffTheRecordObserver> g_off_the_record_observer( |
353 base::LINKER_INITIALIZED); | 143 base::LINKER_INITIALIZED); |
354 | 144 |
355 //------------------------------------------------------------------------------ | |
356 // This section supports the about:dns page. | |
357 //------------------------------------------------------------------------------ | |
358 | |
359 // Provide global support for the about:dns page. | |
360 void PredictorGetHtmlInfo(std::string* output) { | |
361 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
362 | |
363 output->append("<html><head><title>About DNS</title>" | |
364 // We'd like the following no-cache... but it doesn't work. | |
365 // "<META HTTP-EQUIV=\"Pragma\" CONTENT=\"no-cache\">" | |
366 "</head><body>"); | |
367 if (!predictor_enabled || NULL == g_predictor) { | |
368 output->append("DNS pre-resolution and TCP pre-connection is disabled."); | |
369 } else { | |
370 if (!on_the_record_switch) { | |
371 output->append("Incognito mode is active in a window."); | |
372 } else { | |
373 // List items fetched at startup. | |
374 if (g_initial_observer) | |
375 g_initial_observer->GetFirstResolutionsHtml(output); | |
376 // Show list of subresource predictions and stats. | |
377 g_predictor->GetHtmlReferrerLists(output); | |
378 // Show list of prediction results. | |
379 g_predictor->GetHtmlInfo(output); | |
380 } | |
381 } | |
382 output->append("</body></html>"); | |
383 } | |
384 | |
385 void ClearPredictorCache() { | |
386 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
387 if (!predictor_enabled || NULL == g_predictor) | |
388 return; | |
389 g_predictor->DiscardAllResults(); | |
390 } | |
391 | 145 |
392 //------------------------------------------------------------------------------ | 146 //------------------------------------------------------------------------------ |
393 // This section intializes global DNS prefetch services. | 147 // This section intializes DNS prefetch services. |
394 //------------------------------------------------------------------------------ | 148 //------------------------------------------------------------------------------ |
395 | 149 |
396 static void InitNetworkPredictor(TimeDelta max_dns_queue_delay, | 150 static void InitNetworkPredictor(TimeDelta max_dns_queue_delay, |
397 size_t max_parallel_resolves, | 151 size_t max_parallel_resolves, |
398 PrefService* user_prefs, | 152 PrefService* user_prefs, |
399 PrefService* local_state, | 153 PrefService* local_state, |
154 Profile* profile, | |
400 bool preconnect_enabled) { | 155 bool preconnect_enabled) { |
401 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 156 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
402 | 157 |
403 bool prefetching_enabled = | 158 bool prefetching_enabled = |
404 user_prefs->GetBoolean(prefs::kNetworkPredictionEnabled); | 159 user_prefs->GetBoolean(prefs::kNetworkPredictionEnabled); |
405 | 160 |
406 // Gather the list of hostnames to prefetch on startup. | 161 // Gather the list of hostnames to prefetch on startup. |
162 // There is no predictor if the profile is off the record, but a predictor | |
163 // should not be initialized in that case. | |
164 DCHECK(!profile->IsOffTheRecord()); | |
407 UrlList urls = | 165 UrlList urls = |
408 GetPredictedUrlListAtStartup(user_prefs, local_state); | 166 profile->GetPredictor()->GetPredictedUrlListAtStartup(user_prefs, |
167 local_state); | |
409 | 168 |
410 ListValue* referral_list = | 169 ListValue* referral_list = |
411 static_cast<ListValue*>(user_prefs->GetList( | 170 static_cast<ListValue*>(user_prefs->GetList( |
412 prefs::kDnsPrefetchingHostReferralList)->DeepCopy()); | 171 prefs::kDnsPrefetchingHostReferralList)->DeepCopy()); |
413 | 172 |
414 // Remove obsolete preferences from local state if necessary. | 173 // Remove obsolete preferences from local state if necessary. |
415 int current_version = | 174 int current_version = |
416 local_state->GetInteger(prefs::kMultipleProfilePrefMigration); | 175 local_state->GetInteger(prefs::kMultipleProfilePrefMigration); |
417 if ((current_version & browser::DNS_PREFS) == 0) { | 176 if ((current_version & browser::DNS_PREFS) == 0) { |
418 local_state->RegisterListPref(prefs::kDnsStartupPrefetchList, | 177 local_state->RegisterListPref(prefs::kDnsStartupPrefetchList, |
419 PrefService::UNSYNCABLE_PREF); | 178 PrefService::UNSYNCABLE_PREF); |
420 local_state->RegisterListPref(prefs::kDnsHostReferralList, | 179 local_state->RegisterListPref(prefs::kDnsHostReferralList, |
421 PrefService::UNSYNCABLE_PREF); | 180 PrefService::UNSYNCABLE_PREF); |
422 local_state->ClearPref(prefs::kDnsStartupPrefetchList); | 181 local_state->ClearPref(prefs::kDnsStartupPrefetchList); |
423 local_state->ClearPref(prefs::kDnsHostReferralList); | 182 local_state->ClearPref(prefs::kDnsHostReferralList); |
424 local_state->SetInteger(prefs::kMultipleProfilePrefMigration, | 183 local_state->SetInteger(prefs::kMultipleProfilePrefMigration, |
425 current_version | browser::DNS_PREFS); | 184 current_version | browser::DNS_PREFS); |
426 } | 185 } |
427 | 186 |
428 g_browser_process->io_thread()->InitNetworkPredictor( | 187 g_browser_process->io_thread()->InitNetworkPredictor( |
429 prefetching_enabled, max_dns_queue_delay, max_parallel_resolves, urls, | 188 prefetching_enabled, max_dns_queue_delay, max_parallel_resolves, urls, |
430 referral_list, preconnect_enabled); | 189 referral_list, profile, preconnect_enabled); |
431 } | 190 } |
432 | 191 |
433 void FinalizePredictorInitialization( | |
434 Predictor* global_predictor, | |
435 const UrlList& startup_urls, | |
436 ListValue* referral_list) { | |
437 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
438 g_predictor = global_predictor; | |
439 g_initial_observer = new InitialObserver(); | |
440 | |
441 // Prefetch these hostnames on startup. | |
442 DnsPrefetchMotivatedList(startup_urls, | |
443 UrlInfo::STARTUP_LIST_MOTIVATED); | |
444 g_predictor->DeserializeReferrersThenDelete(referral_list); | |
445 } | |
446 | |
447 void FreePredictorResources() { | |
448 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
449 g_predictor = NULL; // Owned and released by io_thread.cc. | |
450 delete g_initial_observer; | |
451 g_initial_observer = NULL; | |
452 } | |
453 | |
454 //------------------------------------------------------------------------------ | |
455 // Functions to handle saving of hostnames from one session to the next, to | |
456 // expedite startup times. | |
457 | |
458 static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread( | |
459 ListValue* startup_list, | |
460 ListValue* referral_list, | |
461 base::WaitableEvent* completion) { | |
462 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
463 | |
464 if (NULL == g_predictor) { | |
465 completion->Signal(); | |
466 return; | |
467 } | |
468 | |
469 if (g_initial_observer) | |
470 g_initial_observer->GetInitialDnsResolutionList(startup_list); | |
471 | |
472 // Do at least one trim at shutdown, in case the user wasn't running long | |
473 // enough to do any regular trimming of referrers. | |
474 g_predictor->TrimReferrersNow(); | |
475 g_predictor->SerializeReferrers(referral_list); | |
476 | |
477 completion->Signal(); | |
478 } | |
479 | |
480 void SavePredictorStateForNextStartupAndTrim(PrefService* prefs) { | |
481 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
482 | |
483 if (!predictor_enabled || g_predictor == NULL) | |
484 return; | |
485 | |
486 base::WaitableEvent completion(true, false); | |
487 | |
488 ListPrefUpdate update_startup_list(prefs, prefs::kDnsPrefetchingStartupList); | |
489 ListPrefUpdate update_referral_list(prefs, | |
490 prefs::kDnsPrefetchingHostReferralList); | |
491 bool posted = BrowserThread::PostTask( | |
492 BrowserThread::IO, | |
493 FROM_HERE, | |
494 NewRunnableFunction(SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread, | |
495 update_startup_list.Get(), | |
496 update_referral_list.Get(), | |
497 &completion)); | |
498 | |
499 // TODO(jar): Synchronous waiting for the IO thread is a potential source | |
500 // to deadlocks and should be investigated. See http://crbug.com/78451. | |
501 DCHECK(posted); | |
502 if (posted) | |
503 completion.Wait(); | |
504 } | |
505 | |
506 static UrlList GetPredictedUrlListAtStartup(PrefService* user_prefs, | |
507 PrefService* local_state) { | |
508 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | |
509 UrlList urls; | |
510 // Recall list of URLs we learned about during last session. | |
511 // This may catch secondary hostnames, pulled in by the homepages. It will | |
512 // also catch more of the "primary" home pages, since that was (presumably) | |
513 // rendered first (and will be rendered first this time too). | |
514 const ListValue* startup_list = | |
515 user_prefs->GetList(prefs::kDnsPrefetchingStartupList); | |
516 | |
517 if (startup_list) { | |
518 ListValue::const_iterator it = startup_list->begin(); | |
519 int format_version = -1; | |
520 if (it != startup_list->end() && | |
521 (*it)->GetAsInteger(&format_version) && | |
522 format_version == kPredictorStartupFormatVersion) { | |
523 ++it; | |
524 for (; it != startup_list->end(); ++it) { | |
525 std::string url_spec; | |
526 if (!(*it)->GetAsString(&url_spec)) { | |
527 LOG(DFATAL); | |
528 break; // Format incompatibility. | |
529 } | |
530 GURL url(url_spec); | |
531 if (!url.has_host() || !url.has_scheme()) { | |
532 LOG(DFATAL); | |
533 break; // Format incompatibility. | |
534 } | |
535 | |
536 urls.push_back(url); | |
537 } | |
538 } | |
539 } | |
540 | |
541 // Prepare for any static home page(s) the user has in prefs. The user may | |
542 // have a LOT of tab's specified, so we may as well try to warm them all. | |
543 SessionStartupPref tab_start_pref = | |
544 SessionStartupPref::GetStartupPref(user_prefs); | |
545 if (SessionStartupPref::URLS == tab_start_pref.type) { | |
546 for (size_t i = 0; i < tab_start_pref.urls.size(); i++) { | |
547 GURL gurl = tab_start_pref.urls[i]; | |
548 if (!gurl.is_valid() || gurl.SchemeIsFile() || gurl.host().empty()) | |
549 continue; | |
550 if (gurl.SchemeIs("http") || gurl.SchemeIs("https")) | |
551 urls.push_back(gurl.GetWithEmptyPath()); | |
552 } | |
553 } | |
554 | |
555 if (urls.empty()) | |
556 urls.push_back(GURL("http://www.google.com:80")); | |
557 | |
558 return urls; | |
559 } | |
560 | 192 |
561 //------------------------------------------------------------------------------ | 193 //------------------------------------------------------------------------------ |
562 // Methods for the helper class that is used to startup and teardown the whole | 194 // Methods for the helper class that is used to startup and teardown the whole |
563 // g_predictor system (both DNS pre-resolution and TCP/IP pre-connection). | 195 // g_predictor system (both DNS pre-resolution and TCP/IP pre-connection). |
564 | 196 |
565 PredictorInit::PredictorInit(PrefService* user_prefs, | 197 PredictorInit::PredictorInit(PrefService* user_prefs, |
willchan no longer on Chromium
2011/07/21 12:10:53
PredictorInit() is doing 2 different things. It's
rpetterson
2011/08/10 02:24:46
Done.
| |
566 PrefService* local_state, | 198 PrefService* local_state, |
199 Profile* profile, | |
Miranda Callahan
2011/07/21 14:38:04
Not sure if this is valid after you make the chang
rpetterson
2011/08/10 02:24:46
Done.
| |
567 bool preconnect_enabled) { | 200 bool preconnect_enabled) { |
568 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 201 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
569 // Set up a field trial to see what disabling DNS pre-resolution does to | 202 // Set up a field trial to see what disabling DNS pre-resolution does to |
570 // latency of page loads. | 203 // latency of page loads. |
571 base::FieldTrial::Probability kDivisor = 1000; | 204 base::FieldTrial::Probability kDivisor = 1000; |
572 // For each option (i.e., non-default), we have a fixed probability. | 205 // For each option (i.e., non-default), we have a fixed probability. |
573 base::FieldTrial::Probability kProbabilityPerGroup = 1; // 0.1% probability. | 206 base::FieldTrial::Probability kProbabilityPerGroup = 1; // 0.1% probability. |
574 | 207 |
575 // After June 30, 2011 builds, it will always be in default group | 208 // After June 30, 2011 builds, it will always be in default group |
576 // (default_enabled_prefetch). | 209 // (default_enabled_prefetch). |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
635 max_queueing_delay_ms = | 268 max_queueing_delay_ms = |
636 (750 * kTypicalSpeculativeGroupSize) / max_parallel_resolves; | 269 (750 * kTypicalSpeculativeGroupSize) / max_parallel_resolves; |
637 } else if (trial_->group() == max_2s_prefetch) { | 270 } else if (trial_->group() == max_2s_prefetch) { |
638 max_queueing_delay_ms = | 271 max_queueing_delay_ms = |
639 (2000 * kTypicalSpeculativeGroupSize) / max_parallel_resolves; | 272 (2000 * kTypicalSpeculativeGroupSize) / max_parallel_resolves; |
640 } | 273 } |
641 | 274 |
642 TimeDelta max_queueing_delay( | 275 TimeDelta max_queueing_delay( |
643 TimeDelta::FromMilliseconds(max_queueing_delay_ms)); | 276 TimeDelta::FromMilliseconds(max_queueing_delay_ms)); |
644 | 277 |
645 DCHECK(!g_predictor); | 278 DCHECK(!profile->GetPredictor()); |
646 InitNetworkPredictor(max_queueing_delay, max_parallel_resolves, user_prefs, | 279 InitNetworkPredictor(max_queueing_delay, max_parallel_resolves, user_prefs, |
647 local_state, preconnect_enabled); | 280 local_state, profile, preconnect_enabled); |
648 } | 281 } |
649 } | 282 } |
650 | 283 |
651 PredictorInit::~PredictorInit() { | 284 PredictorInit::~PredictorInit() { |
652 } | 285 } |
653 | 286 |
654 } // namespace chrome_browser_net | 287 } // namespace chrome_browser_net |
OLD | NEW |