Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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 "net/base/network_quality_estimator.h" | 5 #include "net/base/network_quality_estimator.h" |
| 6 | 6 |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/memory/scoped_ptr.h" | |
| 10 #include "base/metrics/histogram.h" | 9 #include "base/metrics/histogram.h" |
| 10 #include "build/build_config.h" | |
| 11 #include "net/base/net_util.h" | 11 #include "net/base/net_util.h" |
| 12 #include "net/base/network_quality.h" | 12 #include "net/base/network_interfaces.h" |
| 13 #include "net/url_request/url_request.h" | 13 #include "net/url_request/url_request.h" |
| 14 #include "url/gurl.h" | 14 #include "url/gurl.h" |
| 15 | 15 |
| 16 #if defined(OS_ANDROID) | |
| 17 #include "net/android/network_library.h" | |
| 18 #endif // OS_ANDROID | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 // Maximum size of the cache that holds network quality estimates. | |
| 23 // Smaller size may reduce the cache hit rate due to frequent evictions. | |
| 24 // Larger size may affect performance. | |
| 25 const uint32_t kMaximumNetworkQualityCacheSize = 10; | |
| 26 | |
| 27 } // namespace | |
| 28 | |
| 16 namespace net { | 29 namespace net { |
| 17 | 30 |
| 18 NetworkQualityEstimator::NetworkQualityEstimator() | 31 NetworkQualityEstimator::NetworkQualityEstimator() |
| 19 : NetworkQualityEstimator(false) { | 32 : NetworkQualityEstimator(false) { |
| 20 } | 33 } |
| 21 | 34 |
| 22 NetworkQualityEstimator::NetworkQualityEstimator( | 35 NetworkQualityEstimator::NetworkQualityEstimator( |
| 23 bool allow_local_host_requests_for_tests) | 36 bool allow_local_host_requests_for_tests) |
| 24 : allow_localhost_requests_(allow_local_host_requests_for_tests), | 37 : allow_localhost_requests_(allow_local_host_requests_for_tests), |
| 25 last_connection_change_(base::TimeTicks::Now()), | 38 last_connection_change_(base::TimeTicks::Now()), |
| 26 current_connection_type_(NetworkChangeNotifier::GetConnectionType()), | |
| 27 bytes_read_since_last_connection_change_(false), | 39 bytes_read_since_last_connection_change_(false), |
| 28 peak_kbps_since_last_connection_change_(0) { | 40 peak_kbps_since_last_connection_change_(0), |
| 41 current_network_id_(NetworkID(NetworkChangeNotifier::GetConnectionType(), | |
| 42 std::string())) { | |
| 29 static_assert(kMinRequestDurationMicroseconds > 0, | 43 static_assert(kMinRequestDurationMicroseconds > 0, |
| 30 "Minimum request duration must be > 0"); | 44 "Minimum request duration must be > 0"); |
| 45 static_assert(kMaximumNetworkQualityCacheSize > 0, | |
| 46 "Size of the network quality cache must be > 0"); | |
| 31 NetworkChangeNotifier::AddConnectionTypeObserver(this); | 47 NetworkChangeNotifier::AddConnectionTypeObserver(this); |
| 48 current_network_id_.id = GetCurrentNetworkName(); | |
| 32 } | 49 } |
| 33 | 50 |
| 34 NetworkQualityEstimator::~NetworkQualityEstimator() { | 51 NetworkQualityEstimator::~NetworkQualityEstimator() { |
| 35 DCHECK(thread_checker_.CalledOnValidThread()); | 52 DCHECK(thread_checker_.CalledOnValidThread()); |
| 36 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 53 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); |
| 37 } | 54 } |
| 38 | 55 |
| 39 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request, | 56 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request, |
| 40 int64_t prefilter_bytes_read) { | 57 int64_t prefilter_bytes_read) { |
| 41 DCHECK(thread_checker_.CalledOnValidThread()); | 58 DCHECK(thread_checker_.CalledOnValidThread()); |
| (...skipping 28 matching lines...) Expand all Loading... | |
| 70 request_duration.InMicroseconds()); | 87 request_duration.InMicroseconds()); |
| 71 if (kbps > peak_kbps_since_last_connection_change_) | 88 if (kbps > peak_kbps_since_last_connection_change_) |
| 72 peak_kbps_since_last_connection_change_ = kbps; | 89 peak_kbps_since_last_connection_change_ = kbps; |
| 73 } | 90 } |
| 74 } | 91 } |
| 75 | 92 |
| 76 void NetworkQualityEstimator::OnConnectionTypeChanged( | 93 void NetworkQualityEstimator::OnConnectionTypeChanged( |
| 77 NetworkChangeNotifier::ConnectionType type) { | 94 NetworkChangeNotifier::ConnectionType type) { |
| 78 DCHECK(thread_checker_.CalledOnValidThread()); | 95 DCHECK(thread_checker_.CalledOnValidThread()); |
| 79 if (bytes_read_since_last_connection_change_) { | 96 if (bytes_read_since_last_connection_change_) { |
| 80 switch (current_connection_type_) { | 97 switch (current_network_id_.type) { |
| 81 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | 98 case NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| 82 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", | 99 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown", |
| 83 fastest_RTT_since_last_connection_change_); | 100 fastest_RTT_since_last_connection_change_); |
| 84 break; | 101 break; |
| 85 case NetworkChangeNotifier::CONNECTION_ETHERNET: | 102 case NetworkChangeNotifier::CONNECTION_ETHERNET: |
| 86 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", | 103 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet", |
| 87 fastest_RTT_since_last_connection_change_); | 104 fastest_RTT_since_last_connection_change_); |
| 88 break; | 105 break; |
| 89 case NetworkChangeNotifier::CONNECTION_WIFI: | 106 case NetworkChangeNotifier::CONNECTION_WIFI: |
| 90 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", | 107 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi", |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 104 break; | 121 break; |
| 105 case NetworkChangeNotifier::CONNECTION_NONE: | 122 case NetworkChangeNotifier::CONNECTION_NONE: |
| 106 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", | 123 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", |
| 107 fastest_RTT_since_last_connection_change_); | 124 fastest_RTT_since_last_connection_change_); |
| 108 break; | 125 break; |
| 109 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | 126 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| 110 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", | 127 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", |
| 111 fastest_RTT_since_last_connection_change_); | 128 fastest_RTT_since_last_connection_change_); |
| 112 break; | 129 break; |
| 113 default: | 130 default: |
| 114 NOTREACHED(); | 131 NOTREACHED() << "Unexpected connection type = " |
| 132 << current_network_id_.type; | |
| 115 break; | 133 break; |
| 116 } | 134 } |
| 117 } | 135 } |
| 118 | 136 |
| 119 if (peak_kbps_since_last_connection_change_) { | 137 if (peak_kbps_since_last_connection_change_) { |
| 120 switch (current_connection_type_) { | 138 switch (current_network_id_.type) { |
| 121 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | 139 case NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| 122 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", | 140 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", |
| 123 peak_kbps_since_last_connection_change_); | 141 peak_kbps_since_last_connection_change_); |
| 124 break; | 142 break; |
| 125 case NetworkChangeNotifier::CONNECTION_ETHERNET: | 143 case NetworkChangeNotifier::CONNECTION_ETHERNET: |
| 126 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet", | 144 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet", |
| 127 peak_kbps_since_last_connection_change_); | 145 peak_kbps_since_last_connection_change_); |
| 128 break; | 146 break; |
| 129 case NetworkChangeNotifier::CONNECTION_WIFI: | 147 case NetworkChangeNotifier::CONNECTION_WIFI: |
| 130 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi", | 148 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi", |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 144 break; | 162 break; |
| 145 case NetworkChangeNotifier::CONNECTION_NONE: | 163 case NetworkChangeNotifier::CONNECTION_NONE: |
| 146 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", | 164 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", |
| 147 peak_kbps_since_last_connection_change_); | 165 peak_kbps_since_last_connection_change_); |
| 148 break; | 166 break; |
| 149 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | 167 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| 150 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", | 168 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", |
| 151 peak_kbps_since_last_connection_change_); | 169 peak_kbps_since_last_connection_change_); |
| 152 break; | 170 break; |
| 153 default: | 171 default: |
| 154 NOTREACHED(); | 172 NOTREACHED() << "Unexpected connection type = " |
| 173 << current_network_id_.type; | |
| 155 break; | 174 break; |
| 156 } | 175 } |
| 157 } | 176 } |
| 158 | 177 |
| 178 // Write the estimates of the previous network to the cache. | |
| 179 CacheNetworkQualityEstimate(); | |
|
mmenke
2015/06/09 19:48:07
Should we verify that the network actually changed
tbansal1
2015/06/10 00:23:28
I think that would complicate the logic without mu
| |
| 180 | |
| 159 last_connection_change_ = base::TimeTicks::Now(); | 181 last_connection_change_ = base::TimeTicks::Now(); |
| 160 bytes_read_since_last_connection_change_ = false; | 182 bytes_read_since_last_connection_change_ = false; |
| 161 peak_kbps_since_last_connection_change_ = 0; | 183 peak_kbps_since_last_connection_change_ = 0; |
| 162 current_connection_type_ = type; | 184 current_network_id_.type = type; |
| 185 current_network_id_.id = GetCurrentNetworkName(); | |
| 186 | |
| 187 // Read any cached estimates for the new network. | |
| 188 ReadCachedNetworkQualityEstimate(); | |
| 189 } | |
| 190 | |
| 191 size_t NetworkQualityEstimator::GetCacheSizeForTests() const { | |
| 192 return cached_network_quality_.size(); | |
| 163 } | 193 } |
| 164 | 194 |
| 165 NetworkQuality NetworkQualityEstimator::GetEstimate() const { | 195 NetworkQuality NetworkQualityEstimator::GetEstimate() const { |
| 166 DCHECK(thread_checker_.CalledOnValidThread()); | 196 DCHECK(thread_checker_.CalledOnValidThread()); |
| 167 | 197 |
| 168 if (!bytes_read_since_last_connection_change_) { | 198 if (!bytes_read_since_last_connection_change_) { |
| 169 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0, | 199 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0, |
| 170 peak_kbps_since_last_connection_change_, 0); | 200 peak_kbps_since_last_connection_change_, 0); |
| 171 } | 201 } |
| 172 if (!peak_kbps_since_last_connection_change_) { | 202 if (!peak_kbps_since_last_connection_change_) { |
| 173 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, | 203 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, |
| 174 peak_kbps_since_last_connection_change_, 0); | 204 peak_kbps_since_last_connection_change_, 0); |
| 175 } | 205 } |
| 176 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, | 206 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, |
| 177 peak_kbps_since_last_connection_change_, 0.1); | 207 peak_kbps_since_last_connection_change_, 0.1); |
| 178 } | 208 } |
| 179 | 209 |
| 210 std::string NetworkQualityEstimator::GetCurrentNetworkName() const { | |
| 211 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class | |
| 212 // that overrides this method on Android platform. | |
| 213 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 214 | |
| 215 switch (current_network_id_.type) { | |
| 216 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN: | |
| 217 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE: | |
| 218 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH: | |
| 219 return std::string(); | |
| 220 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET: | |
| 221 return std::string(); | |
| 222 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI: | |
| 223 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) | |
| 224 return GetWifiSSID(); | |
| 225 #endif // defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) | |
| 226 return std::string(); | |
| 227 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G: | |
| 228 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G: | |
| 229 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G: | |
| 230 #if defined(OS_ANDROID) | |
| 231 return android::GetTelephonyNetworkOperator(); | |
| 232 #endif // OS_ANDROID | |
| 233 return std::string(); | |
| 234 default: | |
| 235 NOTREACHED() << "Unexpected connection type = " | |
| 236 << current_network_id_.type; | |
| 237 return std::string(); | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() { | |
| 242 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 243 | |
| 244 CachedQualities::iterator it = | |
| 245 cached_network_quality_.find(current_network_id_); | |
| 246 if (it != cached_network_quality_.end()) { | |
| 247 // TOOD(tbansal): Populate these values back into the median computing | |
| 248 // algorithm. | |
| 249 // Add UMA to record how frequently match happens. | |
| 250 // int64 median_kbps = network_quality.median_kbps; | |
| 251 // int64 median_rtt_msec = network_quality.median_rtt_milliseconds; | |
| 252 // Ensure that the estimates read are non-zero before populating them into | |
| 253 // the median computing algorithm. | |
| 254 return true; | |
| 255 } | |
| 256 return false; | |
| 257 } | |
| 258 | |
| 259 void NetworkQualityEstimator::CacheNetworkQualityEstimate() { | |
| 260 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 261 DCHECK_LE(cached_network_quality_.size(), kMaximumNetworkQualityCacheSize); | |
| 262 | |
| 263 // TODO(tbansal): Following variables should be initialized using the median | |
| 264 /// values reported by NetworkQualityEstimator. | |
| 265 int median_kbps = 0; | |
| 266 base::TimeDelta median_rtt; | |
| 267 | |
| 268 // If this network is already in the cache, overwrite that entry. | |
| 269 CachedQualities::iterator it = | |
| 270 cached_network_quality_.find(current_network_id_); | |
| 271 if (it != cached_network_quality_.end()) { | |
| 272 (it->second)->UpdateNetworkQuality(median_kbps, median_rtt); | |
| 273 return; | |
| 274 } | |
| 275 | |
| 276 if (cached_network_quality_.size() == kMaximumNetworkQualityCacheSize) { | |
| 277 // Remove the oldest entry. | |
| 278 CachedQualities::iterator oldest_entry_iterator = | |
| 279 cached_network_quality_.begin(); | |
| 280 | |
| 281 for (CachedQualities::iterator iterator = cached_network_quality_.begin(); | |
| 282 iterator != cached_network_quality_.end(); ++iterator) { | |
| 283 if ((oldest_entry_iterator->second)->last_update_time() > | |
| 284 (iterator->second)->last_update_time()) { | |
| 285 oldest_entry_iterator = iterator; | |
| 286 } | |
| 287 } | |
| 288 cached_network_quality_.erase(oldest_entry_iterator); | |
| 289 } | |
| 290 | |
| 291 DCHECK_LT(cached_network_quality_.size(), kMaximumNetworkQualityCacheSize); | |
| 292 cached_network_quality_.insert( | |
| 293 std::make_pair(current_network_id_, | |
| 294 make_scoped_ptr(new CachedNetworkQuality( | |
| 295 NetworkQuality(median_rtt, 0.0, median_kbps, 0.0))))); | |
| 296 DCHECK_LE(cached_network_quality_.size(), kMaximumNetworkQualityCacheSize); | |
| 297 } | |
| 298 | |
| 299 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality( | |
| 300 const NetworkQuality& network_quality) | |
| 301 : last_update_time_(base::TimeTicks::Now()), | |
| 302 network_quality_(network_quality) { | |
| 303 } | |
| 304 | |
| 305 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() { | |
| 306 } | |
| 307 | |
| 308 void NetworkQualityEstimator::CachedNetworkQuality::UpdateNetworkQuality( | |
| 309 uint64_t median_kbps, | |
| 310 const base::TimeDelta& median_rtt) { | |
| 311 DCHECK_GE(median_kbps, 0U); | |
| 312 DCHECK_GE(median_rtt, base::TimeDelta()); | |
| 313 last_update_time_ = base::TimeTicks::Now(); | |
| 314 | |
| 315 network_quality_.fastest_rtt = median_rtt; | |
| 316 network_quality_.peak_throughput_kbps = median_kbps; | |
| 317 } | |
| 318 | |
| 180 } // namespace net | 319 } // namespace net |
| OLD | NEW |