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.h" | 5 #include "chrome/browser/net/predictor.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <set> | 9 #include <set> |
10 #include <sstream> | 10 #include <sstream> |
11 | 11 |
12 #include "base/compiler_specific.h" | 12 #include "base/compiler_specific.h" |
13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
14 #include "base/stringprintf.h" | 14 #include "base/stringprintf.h" |
| 15 #include "base/synchronization/waitable_event.h" |
15 #include "base/time.h" | 16 #include "base/time.h" |
16 #include "base/values.h" | 17 #include "base/values.h" |
17 #include "chrome/browser/net/preconnect.h" | 18 #include "chrome/browser/net/preconnect.h" |
| 19 #include "chrome/browser/prefs/pref_service.h" |
| 20 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
| 21 #include "chrome/browser/prefs/session_startup_pref.h" |
| 22 #include "chrome/browser/profiles/profile.h" |
| 23 #include "chrome/common/pref_names.h" |
18 #include "content/browser/browser_thread.h" | 24 #include "content/browser/browser_thread.h" |
19 #include "net/base/address_list.h" | 25 #include "net/base/address_list.h" |
20 #include "net/base/completion_callback.h" | 26 #include "net/base/completion_callback.h" |
21 #include "net/base/host_port_pair.h" | 27 #include "net/base/host_port_pair.h" |
22 #include "net/base/host_resolver.h" | 28 #include "net/base/host_resolver.h" |
23 #include "net/base/net_errors.h" | 29 #include "net/base/net_errors.h" |
24 #include "net/base/net_log.h" | 30 #include "net/base/net_log.h" |
25 #include "net/base/single_request_host_resolver.h" | 31 #include "net/base/single_request_host_resolver.h" |
26 | 32 |
27 using base::TimeDelta; | 33 using base::TimeDelta; |
28 | 34 |
29 namespace chrome_browser_net { | 35 namespace chrome_browser_net { |
30 | 36 |
| 37 static void DnsPrefetchMotivatedList(const UrlList& urls, |
| 38 UrlInfo::ResolutionMotivation motivation); |
31 // static | 39 // static |
32 const double Predictor::kPreconnectWorthyExpectedValue = 0.8; | 40 const double Predictor::kPreconnectWorthyExpectedValue = 0.8; |
33 // static | 41 // static |
34 const double Predictor::kDNSPreresolutionWorthyExpectedValue = 0.1; | 42 const double Predictor::kDNSPreresolutionWorthyExpectedValue = 0.1; |
35 // static | 43 // static |
36 const double Predictor::kDiscardableExpectedValue = 0.05; | 44 const double Predictor::kDiscardableExpectedValue = 0.05; |
37 // The goal is of trimming is to to reduce the importance (number of expected | 45 // The goal is of trimming is to to reduce the importance (number of expected |
38 // subresources needed) by a factor of 2 after about 24 hours of uptime. We will | 46 // subresources needed) by a factor of 2 after about 24 hours of uptime. We will |
39 // trim roughly once-an-hour of uptime. The ratio to use in each trim operation | 47 // trim roughly once-an-hour of uptime. The ratio to use in each trim operation |
40 // is then the 24th root of 0.5. If a user only surfs for 4 hours a day, then | 48 // is then the 24th root of 0.5. If a user only surfs for 4 hours a day, then |
41 // after about 6 days they will have halved all their estimates of subresource | 49 // after about 6 days they will have halved all their estimates of subresource |
42 // connections. Once this falls below kDiscardableExpectedValue the referrer | 50 // connections. Once this falls below kDiscardableExpectedValue the referrer |
43 // will be discarded. | 51 // will be discarded. |
44 // TODO(jar): Measure size of referrer lists in the field. Consider an adaptive | 52 // TODO(jar): Measure size of referrer lists in the field. Consider an adaptive |
45 // system that uses a higher trim ratio when the list is large. | 53 // system that uses a higher trim ratio when the list is large. |
46 // static | 54 // static |
47 const double Predictor::kReferrerTrimRatio = 0.97153; | 55 const double Predictor::kReferrerTrimRatio = 0.97153; |
48 | 56 |
49 // static | 57 // static |
50 const TimeDelta Predictor::kDurationBetweenTrimmings = TimeDelta::FromHours(1); | 58 const TimeDelta Predictor::kDurationBetweenTrimmings = TimeDelta::FromHours(1); |
51 // static | 59 // static |
52 const TimeDelta Predictor::kDurationBetweenTrimmingIncrements = | 60 const TimeDelta Predictor::kDurationBetweenTrimmingIncrements = |
53 TimeDelta::FromSeconds(15); | 61 TimeDelta::FromSeconds(15); |
54 // static | 62 // static |
55 const size_t Predictor::kUrlsTrimmedPerIncrement = 5u; | 63 const size_t Predictor::kUrlsTrimmedPerIncrement = 5u; |
56 | 64 |
| 65 // A version number for prefs that are saved. This should be incremented when |
| 66 // we change the format so that we discard old data. |
| 67 static const int kPredictorStartupFormatVersion = 1; |
| 68 |
57 class Predictor::LookupRequest { | 69 class Predictor::LookupRequest { |
58 public: | 70 public: |
59 LookupRequest(Predictor* predictor, | 71 LookupRequest(Predictor* predictor, |
60 net::HostResolver* host_resolver, | 72 net::HostResolver* host_resolver, |
61 const GURL& url) | 73 const GURL& url) |
62 : ALLOW_THIS_IN_INITIALIZER_LIST( | 74 : ALLOW_THIS_IN_INITIALIZER_LIST( |
63 net_callback_(this, &LookupRequest::OnLookupFinished)), | 75 net_callback_(this, &LookupRequest::OnLookupFinished)), |
64 predictor_(predictor), | 76 predictor_(predictor), |
65 url_(url), | 77 url_(url), |
66 resolver_(host_resolver) { | 78 resolver_(host_resolver) { |
(...skipping 28 matching lines...) Expand all Loading... |
95 const GURL url_; // Hostname to resolve. | 107 const GURL url_; // Hostname to resolve. |
96 net::SingleRequestHostResolver resolver_; | 108 net::SingleRequestHostResolver resolver_; |
97 net::AddressList addresses_; | 109 net::AddressList addresses_; |
98 | 110 |
99 DISALLOW_COPY_AND_ASSIGN(LookupRequest); | 111 DISALLOW_COPY_AND_ASSIGN(LookupRequest); |
100 }; | 112 }; |
101 | 113 |
102 Predictor::Predictor(net::HostResolver* host_resolver, | 114 Predictor::Predictor(net::HostResolver* host_resolver, |
103 TimeDelta max_dns_queue_delay, | 115 TimeDelta max_dns_queue_delay, |
104 size_t max_concurrent, | 116 size_t max_concurrent, |
105 bool preconnect_enabled) | 117 bool preconnect_enabled, |
106 : peak_pending_lookups_(0), | 118 bool predictor_enabled) |
| 119 : predictor_enabled_(true), |
| 120 off_the_record_windows_count_(0), |
| 121 on_the_record_(true), |
| 122 peak_pending_lookups_(0), |
107 shutdown_(false), | 123 shutdown_(false), |
108 max_concurrent_dns_lookups_(max_concurrent), | 124 max_concurrent_dns_lookups_(max_concurrent), |
109 max_dns_queue_delay_(max_dns_queue_delay), | 125 max_dns_queue_delay_(max_dns_queue_delay), |
110 host_resolver_(host_resolver), | 126 host_resolver_(host_resolver), |
111 preconnect_enabled_(preconnect_enabled), | 127 preconnect_enabled_(preconnect_enabled), |
112 consecutive_omnibox_preconnect_count_(0), | 128 consecutive_omnibox_preconnect_count_(0), |
113 next_trim_time_(base::TimeTicks::Now() + kDurationBetweenTrimmings), | 129 next_trim_time_(base::TimeTicks::Now() + kDurationBetweenTrimmings), |
114 ALLOW_THIS_IN_INITIALIZER_LIST(trim_task_factory_(this)) { | 130 ALLOW_THIS_IN_INITIALIZER_LIST(trim_task_factory_(this)) { |
| 131 initial_observer_.reset(new InitialObserver()); |
115 } | 132 } |
116 | 133 |
117 Predictor::~Predictor() { | 134 Predictor::~Predictor() { |
118 DCHECK(shutdown_); | 135 DCHECK(shutdown_); |
119 } | 136 } |
120 | 137 |
121 void Predictor::Shutdown() { | 138 void Predictor::Shutdown() { |
122 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
123 DCHECK(!shutdown_); | 140 DCHECK(!shutdown_); |
124 shutdown_ = true; | 141 shutdown_ = true; |
(...skipping 19 matching lines...) Expand all Loading... |
144 UrlInfo::ResolutionMotivation motivation) { | 161 UrlInfo::ResolutionMotivation motivation) { |
145 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 162 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
146 if (!url.has_host()) | 163 if (!url.has_host()) |
147 return; | 164 return; |
148 AppendToResolutionQueue(url, motivation); | 165 AppendToResolutionQueue(url, motivation); |
149 } | 166 } |
150 | 167 |
151 void Predictor::LearnFromNavigation(const GURL& referring_url, | 168 void Predictor::LearnFromNavigation(const GURL& referring_url, |
152 const GURL& target_url) { | 169 const GURL& target_url) { |
153 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 170 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 171 if (!predictor_enabled_) |
| 172 return; |
154 DCHECK_EQ(referring_url, Predictor::CanonicalizeUrl(referring_url)); | 173 DCHECK_EQ(referring_url, Predictor::CanonicalizeUrl(referring_url)); |
155 DCHECK_NE(referring_url, GURL::EmptyGURL()); | 174 DCHECK_NE(referring_url, GURL::EmptyGURL()); |
156 DCHECK_EQ(target_url, Predictor::CanonicalizeUrl(target_url)); | 175 DCHECK_EQ(target_url, Predictor::CanonicalizeUrl(target_url)); |
157 DCHECK_NE(target_url, GURL::EmptyGURL()); | 176 DCHECK_NE(target_url, GURL::EmptyGURL()); |
158 | 177 |
159 referrers_[referring_url].SuggestHost(target_url); | 178 referrers_[referring_url].SuggestHost(target_url); |
160 // Possibly do some referrer trimming. | 179 // Possibly do some referrer trimming. |
161 TrimReferrers(); | 180 TrimReferrers(); |
162 } | 181 } |
163 | 182 |
164 enum SubresourceValue { | 183 enum SubresourceValue { |
165 PRECONNECTION, | 184 PRECONNECTION, |
166 PRERESOLUTION, | 185 PRERESOLUTION, |
167 TOO_NEW, | 186 TOO_NEW, |
168 SUBRESOURCE_VALUE_MAX | 187 SUBRESOURCE_VALUE_MAX |
169 }; | 188 }; |
170 | 189 |
171 void Predictor::AnticipateOmniboxUrl(const GURL& url, bool preconnectable) { | 190 void Predictor::AnticipateOmniboxUrl(const GURL& url, bool preconnectable) { |
| 191 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 192 if (!predictor_enabled_) |
| 193 return; |
| 194 if (!url.is_valid() || !url.has_host()) |
| 195 return; |
172 std::string host = url.HostNoBrackets(); | 196 std::string host = url.HostNoBrackets(); |
173 bool is_new_host_request = (host != last_omnibox_host_); | 197 bool is_new_host_request = (host != last_omnibox_host_); |
174 last_omnibox_host_ = host; | 198 last_omnibox_host_ = host; |
175 | 199 |
176 UrlInfo::ResolutionMotivation motivation(UrlInfo::OMNIBOX_MOTIVATED); | 200 UrlInfo::ResolutionMotivation motivation(UrlInfo::OMNIBOX_MOTIVATED); |
177 base::TimeTicks now = base::TimeTicks::Now(); | 201 base::TimeTicks now = base::TimeTicks::Now(); |
178 | 202 |
179 if (preconnect_enabled()) { | 203 if (preconnect_enabled()) { |
180 if (preconnectable && !is_new_host_request) { | 204 if (preconnectable && !is_new_host_request) { |
181 ++consecutive_omnibox_preconnect_count_; | 205 ++consecutive_omnibox_preconnect_count_; |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
230 | 254 |
231 // Perform at least DNS pre-resolution. | 255 // Perform at least DNS pre-resolution. |
232 BrowserThread::PostTask( | 256 BrowserThread::PostTask( |
233 BrowserThread::IO, | 257 BrowserThread::IO, |
234 FROM_HERE, | 258 FROM_HERE, |
235 NewRunnableMethod(this, &Predictor::Resolve, CanonicalizeUrl(url), | 259 NewRunnableMethod(this, &Predictor::Resolve, CanonicalizeUrl(url), |
236 motivation)); | 260 motivation)); |
237 } | 261 } |
238 | 262 |
239 void Predictor::PreconnectUrlAndSubresources(const GURL& url) { | 263 void Predictor::PreconnectUrlAndSubresources(const GURL& url) { |
| 264 if (!predictor_enabled_) |
| 265 return; |
| 266 if (!url.is_valid() || !url.has_host()) |
| 267 return; |
240 if (preconnect_enabled()) { | 268 if (preconnect_enabled()) { |
241 std::string host = url.HostNoBrackets(); | 269 std::string host = url.HostNoBrackets(); |
242 UrlInfo::ResolutionMotivation motivation(UrlInfo::EARLY_LOAD_MOTIVATED); | 270 UrlInfo::ResolutionMotivation motivation(UrlInfo::EARLY_LOAD_MOTIVATED); |
243 const int kConnectionsNeeded = 1; | 271 const int kConnectionsNeeded = 1; |
244 PreconnectOnUIThread(CanonicalizeUrl(url), motivation, | 272 PreconnectOnUIThread(CanonicalizeUrl(url), motivation, |
245 kConnectionsNeeded); | 273 kConnectionsNeeded); |
246 PredictFrameSubresources(url.GetWithEmptyPath()); | 274 PredictFrameSubresources(url.GetWithEmptyPath()); |
247 } | 275 } |
248 } | 276 } |
249 | 277 |
250 void Predictor::PredictFrameSubresources(const GURL& url) { | 278 void Predictor::PredictFrameSubresources(const GURL& url) { |
| 279 if (!predictor_enabled_) |
| 280 return; |
251 DCHECK_EQ(url.GetWithEmptyPath(), url); | 281 DCHECK_EQ(url.GetWithEmptyPath(), url); |
252 // Add one pass through the message loop to allow current navigation to | 282 // Add one pass through the message loop to allow current navigation to |
253 // proceed. | 283 // proceed. |
254 BrowserThread::PostTask( | 284 BrowserThread::PostTask( |
255 BrowserThread::IO, | 285 BrowserThread::IO, |
256 FROM_HERE, | 286 FROM_HERE, |
257 NewRunnableMethod(this, &Predictor::PrepareFrameSubresources, url)); | 287 NewRunnableMethod(this, &Predictor::PrepareFrameSubresources, url)); |
258 } | 288 } |
259 | 289 |
260 void Predictor::PrepareFrameSubresources(const GURL& url) { | 290 void Predictor::PrepareFrameSubresources(const GURL& url) { |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
416 static_cast<int>(future_url->second.preresolution_count()), | 446 static_cast<int>(future_url->second.preresolution_count()), |
417 static_cast<double>(future_url->second.subresource_use_rate()), | 447 static_cast<double>(future_url->second.subresource_use_rate()), |
418 future_url->first.spec().c_str()); | 448 future_url->first.spec().c_str()); |
419 } | 449 } |
420 } | 450 } |
421 output->append("</table>"); | 451 output->append("</table>"); |
422 } | 452 } |
423 | 453 |
424 void Predictor::GetHtmlInfo(std::string* output) { | 454 void Predictor::GetHtmlInfo(std::string* output) { |
425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | 455 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 456 if (initial_observer_.get()) |
| 457 initial_observer_->GetFirstResolutionsHtml(output); |
| 458 // Show list of subresource predictions and stats. |
| 459 GetHtmlReferrerLists(output); |
| 460 |
426 // Local lists for calling UrlInfo | 461 // Local lists for calling UrlInfo |
427 UrlInfo::UrlInfoTable name_not_found; | 462 UrlInfo::UrlInfoTable name_not_found; |
428 UrlInfo::UrlInfoTable name_preresolved; | 463 UrlInfo::UrlInfoTable name_preresolved; |
429 | 464 |
430 // Get copies of all useful data. | 465 // Get copies of all useful data. |
431 typedef std::map<GURL, UrlInfo, RightToLeftStringSorter> SortedUrlInfo; | 466 typedef std::map<GURL, UrlInfo, RightToLeftStringSorter> SortedUrlInfo; |
432 SortedUrlInfo snapshot; | 467 SortedUrlInfo snapshot; |
433 // UrlInfo supports value semantics, so we can do a shallow copy. | 468 // UrlInfo supports value semantics, so we can do a shallow copy. |
434 for (Results::iterator it(results_.begin()); it != results_.end(); it++) | 469 for (Results::iterator it(results_.begin()); it != results_.end(); it++) |
435 snapshot[it->first] = it->second; | 470 snapshot[it->first] = it->second; |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
696 Referrers::iterator it = referrers_.find(urls_being_trimmed_.back()); | 731 Referrers::iterator it = referrers_.find(urls_being_trimmed_.back()); |
697 urls_being_trimmed_.pop_back(); | 732 urls_being_trimmed_.pop_back(); |
698 if (it == referrers_.end()) | 733 if (it == referrers_.end()) |
699 continue; // Defensive code: It got trimmed away already. | 734 continue; // Defensive code: It got trimmed away already. |
700 if (!it->second.Trim(kReferrerTrimRatio, kDiscardableExpectedValue)) | 735 if (!it->second.Trim(kReferrerTrimRatio, kDiscardableExpectedValue)) |
701 referrers_.erase(it); | 736 referrers_.erase(it); |
702 } | 737 } |
703 PostIncrementalTrimTask(); | 738 PostIncrementalTrimTask(); |
704 } | 739 } |
705 | 740 |
| 741 void Predictor::DiscardInitialNavigationHistory() { |
| 742 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 743 if (initial_observer_.get()) |
| 744 initial_observer_->DiscardInitialNavigationHistory(); |
| 745 } |
| 746 |
| 747 void Predictor::FinalizeInitialization( |
| 748 const UrlList& startup_urls, |
| 749 ListValue* referral_list) { |
| 750 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 751 |
| 752 // Prefetch these hostnames on startup. |
| 753 DnsPrefetchMotivatedList(startup_urls, UrlInfo::STARTUP_LIST_MOTIVATED); |
| 754 DeserializeReferrersThenDelete(referral_list); |
| 755 } |
| 756 |
| 757 //------------------------------------------------------------------------------ |
| 758 // This section intermingles prefetch results with actual browser HTTP |
| 759 // network activity. It supports calculating of the benefit of a prefetch, as |
| 760 // well as recording what prefetched hostname resolutions might be potentially |
| 761 // helpful during the next chrome-startup. |
| 762 //------------------------------------------------------------------------------ |
| 763 |
| 764 void Predictor::LearnAboutInitialNavigation(const GURL& url) { |
| 765 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 766 if (!predictor_enabled_ || NULL == initial_observer_.get() ) |
| 767 return; |
| 768 initial_observer_->Append(url, this); |
| 769 } |
| 770 |
| 771 // This API is only used in the browser process. |
| 772 // It is called from an IPC message originating in the renderer. It currently |
| 773 // includes both Page-Scan, and Link-Hover prefetching. |
| 774 // TODO(jar): Separate out link-hover prefetching, and page-scan results. |
| 775 void Predictor::DnsPrefetchList(const NameList& hostnames) { |
| 776 // TODO(jar): Push GURL transport further back into renderer, but this will |
| 777 // require a Webkit change in the observer :-/. |
| 778 UrlList urls; |
| 779 for (NameList::const_iterator it = hostnames.begin(); |
| 780 it < hostnames.end(); |
| 781 ++it) { |
| 782 urls.push_back(GURL("http://" + *it + ":80")); |
| 783 } |
| 784 |
| 785 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 786 DnsPrefetchMotivatedList(urls, UrlInfo::PAGE_SCAN_MOTIVATED); |
| 787 } |
| 788 |
| 789 void Predictor::DnsPrefetchMotivatedList( |
| 790 const UrlList& urls, |
| 791 UrlInfo::ResolutionMotivation motivation) { |
| 792 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI) || |
| 793 BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 794 if (!predictor_enabled_) |
| 795 return; |
| 796 |
| 797 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 798 ResolveList(urls, motivation); |
| 799 } else { |
| 800 BrowserThread::PostTask( |
| 801 BrowserThread::IO, |
| 802 FROM_HERE, |
| 803 NewRunnableMethod(this, &Predictor::ResolveList, urls, motivation)); |
| 804 } |
| 805 } |
| 806 |
| 807 //------------------------------------------------------------------------------ |
| 808 // Functions to handle saving of hostnames from one session to the next, to |
| 809 // expedite startup times. |
| 810 |
| 811 static void SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread( |
| 812 ListValue* startup_list, |
| 813 ListValue* referral_list, |
| 814 base::WaitableEvent* completion, |
| 815 Profile* profile) { |
| 816 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 817 |
| 818 if (NULL == profile->GetPredictor()) { |
| 819 completion->Signal(); |
| 820 return; |
| 821 } |
| 822 profile->GetPredictor()->SaveDnsPrefetchStateForNextStartupAndTrim( |
| 823 startup_list, referral_list, completion); |
| 824 } |
| 825 |
| 826 void Predictor::SaveDnsPrefetchStateForNextStartupAndTrim( |
| 827 ListValue* startup_list, |
| 828 ListValue* referral_list, |
| 829 base::WaitableEvent* completion) { |
| 830 if (initial_observer_.get()) |
| 831 initial_observer_->GetInitialDnsResolutionList(startup_list); |
| 832 |
| 833 // Do at least one trim at shutdown, in case the user wasn't running long |
| 834 // enough to do any regular trimming of referrers. |
| 835 TrimReferrersNow(); |
| 836 SerializeReferrers(referral_list); |
| 837 |
| 838 completion->Signal(); |
| 839 } |
| 840 |
| 841 void Predictor::SaveStateForNextStartupAndTrim(PrefService* prefs, |
| 842 Profile* profile) { |
| 843 if (!predictor_enabled_) |
| 844 return; |
| 845 |
| 846 base::WaitableEvent completion(true, false); |
| 847 |
| 848 ListPrefUpdate update_startup_list(prefs, prefs::kDnsPrefetchingStartupList); |
| 849 ListPrefUpdate update_referral_list(prefs, |
| 850 prefs::kDnsPrefetchingHostReferralList); |
| 851 if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
| 852 SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread( |
| 853 update_startup_list.Get(), |
| 854 update_referral_list.Get(), |
| 855 &completion, |
| 856 profile); |
| 857 } else { |
| 858 bool posted = BrowserThread::PostTask( |
| 859 BrowserThread::IO, |
| 860 FROM_HERE, |
| 861 NewRunnableFunction( |
| 862 SaveDnsPrefetchStateForNextStartupAndTrimOnIOThread, |
| 863 update_startup_list.Get(), |
| 864 update_referral_list.Get(), |
| 865 &completion, |
| 866 profile)); |
| 867 |
| 868 // TODO(jar): Synchronous waiting for the IO thread is a potential source |
| 869 // to deadlocks and should be investigated. See http://crbug.com/78451. |
| 870 DCHECK(posted); |
| 871 if (posted) |
| 872 completion.Wait(); |
| 873 } |
| 874 } |
| 875 |
| 876 UrlList Predictor::GetPredictedUrlListAtStartup( |
| 877 PrefService* user_prefs, |
| 878 PrefService* local_state) { |
| 879 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 880 UrlList urls; |
| 881 // Recall list of URLs we learned about during last session. |
| 882 // This may catch secondary hostnames, pulled in by the homepages. It will |
| 883 // also catch more of the "primary" home pages, since that was (presumably) |
| 884 // rendered first (and will be rendered first this time too). |
| 885 const ListValue* startup_list = |
| 886 user_prefs->GetList(prefs::kDnsPrefetchingStartupList); |
| 887 |
| 888 if (startup_list) { |
| 889 ListValue::const_iterator it = startup_list->begin(); |
| 890 int format_version = -1; |
| 891 if (it != startup_list->end() && |
| 892 (*it)->GetAsInteger(&format_version) && |
| 893 format_version == kPredictorStartupFormatVersion) { |
| 894 ++it; |
| 895 for (; it != startup_list->end(); ++it) { |
| 896 std::string url_spec; |
| 897 if (!(*it)->GetAsString(&url_spec)) { |
| 898 LOG(DFATAL); |
| 899 break; // Format incompatibility. |
| 900 } |
| 901 GURL url(url_spec); |
| 902 if (!url.has_host() || !url.has_scheme()) { |
| 903 LOG(DFATAL); |
| 904 break; // Format incompatibility. |
| 905 } |
| 906 |
| 907 urls.push_back(url); |
| 908 } |
| 909 } |
| 910 } |
| 911 |
| 912 // Prepare for any static home page(s) the user has in prefs. The user may |
| 913 // have a LOT of tab's specified, so we may as well try to warm them all. |
| 914 SessionStartupPref tab_start_pref = |
| 915 SessionStartupPref::GetStartupPref(user_prefs); |
| 916 if (SessionStartupPref::URLS == tab_start_pref.type) { |
| 917 for (size_t i = 0; i < tab_start_pref.urls.size(); i++) { |
| 918 GURL gurl = tab_start_pref.urls[i]; |
| 919 if (!gurl.is_valid() || gurl.SchemeIsFile() || gurl.host().empty()) |
| 920 continue; |
| 921 if (gurl.SchemeIs("http") || gurl.SchemeIs("https")) |
| 922 urls.push_back(gurl.GetWithEmptyPath()); |
| 923 } |
| 924 } |
| 925 |
| 926 if (urls.empty()) |
| 927 urls.push_back(GURL("http://www.google.com:80")); |
| 928 |
| 929 return urls; |
| 930 } |
| 931 |
| 932 bool Predictor::HandleIncognitoBrowserClosed() { |
| 933 DCHECK_LT(0, off_the_record_windows_count_); |
| 934 if (0 >= off_the_record_windows_count_) // Defensive coding. |
| 935 return false; |
| 936 if (--off_the_record_windows_count_) |
| 937 return false; // Still some windows are incognito. |
| 938 return true; |
| 939 } |
| 940 |
| 941 void Predictor::HandleIncognitoBrowserOpened() { |
| 942 off_the_record_windows_count_++; |
| 943 } |
| 944 |
706 //------------------------------------------------------------------------------ | 945 //------------------------------------------------------------------------------ |
707 | 946 |
708 Predictor::HostNameQueue::HostNameQueue() { | 947 Predictor::HostNameQueue::HostNameQueue() { |
709 } | 948 } |
710 | 949 |
711 Predictor::HostNameQueue::~HostNameQueue() { | 950 Predictor::HostNameQueue::~HostNameQueue() { |
712 } | 951 } |
713 | 952 |
714 void Predictor::HostNameQueue::Push(const GURL& url, | 953 void Predictor::HostNameQueue::Push(const GURL& url, |
715 UrlInfo::ResolutionMotivation motivation) { | 954 UrlInfo::ResolutionMotivation motivation) { |
(...skipping 21 matching lines...) Expand all Loading... |
737 GURL url(queue->front()); | 976 GURL url(queue->front()); |
738 queue->pop(); | 977 queue->pop(); |
739 return url; | 978 return url; |
740 } | 979 } |
741 | 980 |
742 void Predictor::DeserializeReferrersThenDelete(ListValue* referral_list) { | 981 void Predictor::DeserializeReferrersThenDelete(ListValue* referral_list) { |
743 DeserializeReferrers(*referral_list); | 982 DeserializeReferrers(*referral_list); |
744 delete referral_list; | 983 delete referral_list; |
745 } | 984 } |
746 | 985 |
| 986 //------------------------------------------------------------------------------ |
| 987 // Member definitions for InitialObserver class. |
| 988 |
| 989 void Predictor::InitialObserver::Append(const GURL& url, |
| 990 Predictor* predictor) { |
| 991 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 992 |
| 993 // TODO(rlp): Do we really need the predictor check here? |
| 994 if (!predictor->on_the_record() || NULL == predictor) |
| 995 return; |
| 996 if (kStartupResolutionCount <= first_navigations_.size()) |
| 997 return; |
| 998 |
| 999 DCHECK(url.SchemeIs("http") || url.SchemeIs("https")); |
| 1000 DCHECK_EQ(url, Predictor::CanonicalizeUrl(url)); |
| 1001 if (first_navigations_.find(url) == first_navigations_.end()) |
| 1002 first_navigations_[url] = base::TimeTicks::Now(); |
| 1003 } |
| 1004 |
| 1005 void Predictor::InitialObserver::GetInitialDnsResolutionList( |
| 1006 ListValue* startup_list) { |
| 1007 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 1008 DCHECK(startup_list); |
| 1009 startup_list->Clear(); |
| 1010 DCHECK_EQ(0u, startup_list->GetSize()); |
| 1011 startup_list->Append(new FundamentalValue(kPredictorStartupFormatVersion)); |
| 1012 for (FirstNavigations::iterator it = first_navigations_.begin(); |
| 1013 it != first_navigations_.end(); |
| 1014 ++it) { |
| 1015 DCHECK(it->first == Predictor::CanonicalizeUrl(it->first)); |
| 1016 startup_list->Append(new StringValue(it->first.spec())); |
| 1017 } |
| 1018 } |
| 1019 |
| 1020 void Predictor::InitialObserver::GetFirstResolutionsHtml( |
| 1021 std::string* output) { |
| 1022 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| 1023 |
| 1024 UrlInfo::UrlInfoTable resolution_list; |
| 1025 { |
| 1026 for (FirstNavigations::iterator it(first_navigations_.begin()); |
| 1027 it != first_navigations_.end(); |
| 1028 it++) { |
| 1029 UrlInfo info; |
| 1030 info.SetUrl(it->first); |
| 1031 info.set_time(it->second); |
| 1032 resolution_list.push_back(info); |
| 1033 } |
| 1034 } |
| 1035 UrlInfo::GetHtmlTable(resolution_list, |
| 1036 "Future startups will prefetch DNS records for ", false, output); |
| 1037 } |
747 | 1038 |
748 //------------------------------------------------------------------------------ | 1039 //------------------------------------------------------------------------------ |
749 // Helper functions | 1040 // Helper functions |
750 //------------------------------------------------------------------------------ | 1041 //------------------------------------------------------------------------------ |
751 | 1042 |
752 // static | 1043 // static |
753 GURL Predictor::CanonicalizeUrl(const GURL& url) { | 1044 GURL Predictor::CanonicalizeUrl(const GURL& url) { |
754 if (!url.has_host()) | 1045 if (!url.has_host()) |
755 return GURL::EmptyGURL(); | 1046 return GURL::EmptyGURL(); |
756 | 1047 |
(...skipping 11 matching lines...) Expand all Loading... |
768 // If we omit a port, it will default to 80 or 443 as appropriate. | 1059 // If we omit a port, it will default to 80 or 443 as appropriate. |
769 std::string colon_plus_port; | 1060 std::string colon_plus_port; |
770 if (url.has_port()) | 1061 if (url.has_port()) |
771 colon_plus_port = ":" + url.port(); | 1062 colon_plus_port = ":" + url.port(); |
772 | 1063 |
773 return GURL(scheme + "://" + url.host() + colon_plus_port); | 1064 return GURL(scheme + "://" + url.host() + colon_plus_port); |
774 } | 1065 } |
775 | 1066 |
776 | 1067 |
777 } // namespace chrome_browser_net | 1068 } // namespace chrome_browser_net |
OLD | NEW |