Chromium Code Reviews| 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 |