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" |
| 10 #include "base/metrics/histogram.h" | 8 #include "base/metrics/histogram.h" |
| 9 #include "build/build_config.h" | |
| 11 #include "net/base/net_util.h" | 10 #include "net/base/net_util.h" |
| 12 #include "net/base/network_quality.h" | 11 #include "net/base/network_quality.h" |
| 13 #include "net/url_request/url_request.h" | 12 #include "net/url_request/url_request.h" |
| 14 #include "url/gurl.h" | 13 #include "url/gurl.h" |
| 15 | 14 |
| 15 #if defined(OS_ANDROID) | |
| 16 #include "net/android/network_library.h" | |
| 17 #endif // OS_ANDROID | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 21 // Maximum size of the cache that holds network quality estimates. | |
| 22 // Smaller size may reduce the cache hit rate due to frequent evictions. | |
| 23 // Larger size may affect performance. | |
| 24 const uint32_t kMaximumNetworkQualityCacheSize = 10; | |
| 25 | |
| 26 } // namespace | |
| 27 | |
| 16 namespace net { | 28 namespace net { |
| 17 | 29 |
| 18 NetworkQualityEstimator::NetworkQualityEstimator() | 30 NetworkQualityEstimator::NetworkQualityEstimator() |
| 19 : NetworkQualityEstimator(false) { | 31 : NetworkQualityEstimator(false) { |
| 20 } | 32 } |
| 21 | 33 |
| 22 NetworkQualityEstimator::NetworkQualityEstimator( | 34 NetworkQualityEstimator::NetworkQualityEstimator( |
| 23 bool allow_local_host_requests_for_tests) | 35 bool allow_local_host_requests_for_tests) |
| 24 : allow_localhost_requests_(allow_local_host_requests_for_tests), | 36 : allow_localhost_requests_(allow_local_host_requests_for_tests), |
| 25 last_connection_change_(base::TimeTicks::Now()), | 37 last_connection_change_(base::TimeTicks::Now()), |
| 26 current_connection_type_(NetworkChangeNotifier::GetConnectionType()), | 38 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) { |
| 29 static_assert(kMinRequestDurationMicroseconds > 0, | 41 static_assert(kMinRequestDurationMicroseconds > 0, |
| 30 "Minimum request duration must be > 0"); | 42 "Minimum request duration must be > 0"); |
| 43 static_assert(kMaximumNetworkQualityCacheSize > 0, | |
| 44 "Size of the network quality cache must be > 0"); | |
| 31 NetworkChangeNotifier::AddConnectionTypeObserver(this); | 45 NetworkChangeNotifier::AddConnectionTypeObserver(this); |
| 46 UpdateCurrentNetworkName(); | |
| 32 } | 47 } |
| 33 | 48 |
| 34 NetworkQualityEstimator::~NetworkQualityEstimator() { | 49 NetworkQualityEstimator::~NetworkQualityEstimator() { |
| 35 DCHECK(thread_checker_.CalledOnValidThread()); | 50 DCHECK(thread_checker_.CalledOnValidThread()); |
| 36 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | 51 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); |
| 37 } | 52 } |
| 38 | 53 |
| 39 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request, | 54 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest& request, |
| 40 int64_t prefilter_bytes_read) { | 55 int64_t prefilter_bytes_read) { |
| 41 DCHECK(thread_checker_.CalledOnValidThread()); | 56 DCHECK(thread_checker_.CalledOnValidThread()); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 104 break; | 119 break; |
| 105 case NetworkChangeNotifier::CONNECTION_NONE: | 120 case NetworkChangeNotifier::CONNECTION_NONE: |
| 106 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", | 121 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None", |
| 107 fastest_RTT_since_last_connection_change_); | 122 fastest_RTT_since_last_connection_change_); |
| 108 break; | 123 break; |
| 109 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | 124 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| 110 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", | 125 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth", |
| 111 fastest_RTT_since_last_connection_change_); | 126 fastest_RTT_since_last_connection_change_); |
| 112 break; | 127 break; |
| 113 default: | 128 default: |
| 114 NOTREACHED(); | 129 NOTREACHED() << "Unexpected connection type = " |
| 130 << current_connection_type_; | |
| 115 break; | 131 break; |
| 116 } | 132 } |
| 117 } | 133 } |
| 118 | 134 |
| 119 if (peak_kbps_since_last_connection_change_) { | 135 if (peak_kbps_since_last_connection_change_) { |
| 120 switch (current_connection_type_) { | 136 switch (current_connection_type_) { |
| 121 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | 137 case NetworkChangeNotifier::CONNECTION_UNKNOWN: |
| 122 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", | 138 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown", |
| 123 peak_kbps_since_last_connection_change_); | 139 peak_kbps_since_last_connection_change_); |
| 124 break; | 140 break; |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 144 break; | 160 break; |
| 145 case NetworkChangeNotifier::CONNECTION_NONE: | 161 case NetworkChangeNotifier::CONNECTION_NONE: |
| 146 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", | 162 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None", |
| 147 peak_kbps_since_last_connection_change_); | 163 peak_kbps_since_last_connection_change_); |
| 148 break; | 164 break; |
| 149 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | 165 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: |
| 150 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", | 166 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth", |
| 151 peak_kbps_since_last_connection_change_); | 167 peak_kbps_since_last_connection_change_); |
| 152 break; | 168 break; |
| 153 default: | 169 default: |
| 154 NOTREACHED(); | 170 NOTREACHED() << "Unexpected connection type = " |
| 171 << current_connection_type_; | |
| 155 break; | 172 break; |
| 156 } | 173 } |
| 157 } | 174 } |
| 158 | 175 |
| 176 // Write the estimates of the previous network to the cache. | |
| 177 CacheNetworkQualityEstimate(); | |
| 178 | |
| 159 last_connection_change_ = base::TimeTicks::Now(); | 179 last_connection_change_ = base::TimeTicks::Now(); |
| 160 bytes_read_since_last_connection_change_ = false; | 180 bytes_read_since_last_connection_change_ = false; |
| 161 peak_kbps_since_last_connection_change_ = 0; | 181 peak_kbps_since_last_connection_change_ = 0; |
| 162 current_connection_type_ = type; | 182 current_connection_type_ = type; |
| 183 UpdateCurrentNetworkName(); | |
| 184 | |
| 185 // Read any cached estimates for the new network. | |
| 186 ReadCachedNetworkQualityEstimate(); | |
| 187 } | |
| 188 | |
| 189 size_t NetworkQualityEstimator::GetCacheSizeForTests() const { | |
| 190 return cached_network_quality_.size(); | |
| 191 } | |
| 192 | |
| 193 void NetworkQualityEstimator::SetCurrentNetworkNameForTests( | |
| 194 const std::string& network_name) { | |
| 195 current_network_name_ = network_name; | |
| 163 } | 196 } |
| 164 | 197 |
| 165 NetworkQuality NetworkQualityEstimator::GetEstimate() const { | 198 NetworkQuality NetworkQualityEstimator::GetEstimate() const { |
| 166 DCHECK(thread_checker_.CalledOnValidThread()); | 199 DCHECK(thread_checker_.CalledOnValidThread()); |
| 167 | 200 |
| 168 if (!bytes_read_since_last_connection_change_) { | 201 if (!bytes_read_since_last_connection_change_) { |
| 169 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0, | 202 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0, |
| 170 peak_kbps_since_last_connection_change_, 0); | 203 peak_kbps_since_last_connection_change_, 0); |
| 171 } | 204 } |
| 172 if (!peak_kbps_since_last_connection_change_) { | 205 if (!peak_kbps_since_last_connection_change_) { |
| 173 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, | 206 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, |
| 174 peak_kbps_since_last_connection_change_, 0); | 207 peak_kbps_since_last_connection_change_, 0); |
| 175 } | 208 } |
| 176 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, | 209 return NetworkQuality(fastest_RTT_since_last_connection_change_, 0.1, |
| 177 peak_kbps_since_last_connection_change_, 0.1); | 210 peak_kbps_since_last_connection_change_, 0.1); |
| 178 } | 211 } |
| 179 | 212 |
| 213 void NetworkQualityEstimator::UpdateCurrentNetworkName() { | |
| 214 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 215 | |
| 216 current_network_name_ = std::string(); | |
| 217 switch (current_connection_type_) { | |
| 218 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN: | |
| 219 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE: | |
| 220 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH: | |
| 221 return; | |
| 222 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET: | |
| 223 current_network_name_ = "ethernet"; | |
| 224 return; | |
| 225 #if defined(OS_ANDROID) | |
|
bengr
2015/06/05 20:34:31
Could we have a NetworkQualityEstimatorAndroid tha
tbansal1
2015/06/06 01:03:14
Done. Added TODO
| |
| 226 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI: | |
|
mmenke
2015/06/05 20:37:21
Erm...WIFI only on Android?
tbansal1
2015/06/06 01:03:14
Added Linux and ChromeOS. GetWiFiSSID() is only im
| |
| 227 current_network_name_ = GetWifiSSID(); | |
| 228 return; | |
| 229 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G: | |
| 230 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G: | |
| 231 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G: | |
| 232 current_network_name_ = android::GetTelephonyNetworkOperator(); | |
| 233 return; | |
| 234 #endif // OS_ANDROID | |
|
mmenke
2015/06/05 20:37:20
Can't ChromeOS have cell connections? What about
tbansal1
2015/06/06 01:03:14
AFAIK, GetTelephonyNetworkOperator() would compile
mmenke
2015/06/08 20:34:19
There's not, but the old code defaulted to NOTREAC
| |
| 235 default: | |
| 236 #if defined(OS_ANDROID) | |
| 237 NOTREACHED() << "Unexpected connection type = " | |
| 238 << current_connection_type_; | |
| 239 #endif // OS_ANDROID | |
| 240 return; | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() { | |
| 245 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 246 | |
| 247 for (const auto& network_quality : cached_network_quality_) { | |
| 248 if (!network_quality->MatchesNetwork(current_connection_type_, | |
| 249 current_network_name_)) { | |
| 250 continue; | |
| 251 } | |
| 252 | |
| 253 // TOOD(tbansal): Populate these values back into the median computing | |
| 254 // algorithm. | |
| 255 // Add UMA to record how frequently match happens. | |
| 256 // int64 median_kbps = network_quality.median_kbps; | |
| 257 // int64 median_rtt_msec = network_quality.median_rtt_milliseconds; | |
| 258 // Ensure that the estimates read are non-zero before populating them into | |
| 259 // the median computing algorithm. | |
| 260 return true; | |
| 261 } | |
| 262 | |
| 263 return false; | |
| 264 } | |
| 265 | |
| 266 void NetworkQualityEstimator::CacheNetworkQualityEstimate() { | |
| 267 DCHECK(thread_checker_.CalledOnValidThread()); | |
| 268 | |
| 269 // TODO(tbansal): Following variables should be initialized using the median | |
| 270 /// values reported by NetworkQualityEstimator. | |
| 271 int median_kbps = 0; | |
| 272 base::TimeDelta median_rtt; | |
| 273 | |
| 274 // If this network is already in the cache, overwrite that entry. | |
| 275 for (auto& network_quality : cached_network_quality_) { | |
| 276 if (!network_quality->MatchesNetwork(current_connection_type_, | |
| 277 current_network_name_)) { | |
| 278 continue; | |
| 279 } | |
| 280 | |
| 281 network_quality->UpdateNetworkQuality(median_kbps, median_rtt); | |
| 282 return; | |
| 283 } | |
| 284 | |
| 285 if (cached_network_quality_.size() < kMaximumNetworkQualityCacheSize) { | |
| 286 cached_network_quality_.push_back(new CachedNetworkQuality( | |
| 287 current_connection_type_, current_network_name_, median_kbps, | |
| 288 median_rtt)); | |
| 289 return; | |
| 290 } | |
| 291 | |
| 292 DCHECK_EQ(kMaximumNetworkQualityCacheSize, cached_network_quality_.size()); | |
| 293 | |
| 294 // Overwrite the oldest entry. | |
| 295 ScopedVector<CachedNetworkQuality>::iterator oldest_entry_iterator = | |
| 296 cached_network_quality_.begin(); | |
| 297 | |
| 298 for (ScopedVector<CachedNetworkQuality>::iterator iterator = | |
| 299 cached_network_quality_.begin(); | |
| 300 iterator != cached_network_quality_.end(); ++iterator) { | |
| 301 if ((*oldest_entry_iterator)->GetLastUpdated() > | |
| 302 (*iterator)->GetLastUpdated()) { | |
| 303 oldest_entry_iterator = iterator; | |
| 304 } | |
| 305 } | |
| 306 | |
| 307 cached_network_quality_.erase(oldest_entry_iterator); | |
| 308 cached_network_quality_.push_back( | |
| 309 new CachedNetworkQuality(current_connection_type_, current_network_name_, | |
| 310 median_kbps, median_rtt)); | |
| 311 | |
| 312 DCHECK_EQ(kMaximumNetworkQualityCacheSize, cached_network_quality_.size()); | |
| 313 } | |
| 314 | |
| 315 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality( | |
| 316 NetworkChangeNotifier::ConnectionType connection_type, | |
| 317 const std::string& network_name, | |
| 318 uint64_t median_kbps, | |
| 319 const base::TimeDelta& median_rtt) | |
| 320 : median_kbps_(median_kbps), | |
| 321 median_rtt_(median_rtt), | |
| 322 last_updated_(base::TimeTicks::Now()), | |
| 323 connection_type_(connection_type), | |
| 324 network_name_(network_name) { | |
| 325 DCHECK_GE(median_kbps_, 0U); | |
| 326 DCHECK_GE(median_rtt_, base::TimeDelta()); | |
| 327 } | |
| 328 | |
| 329 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() { | |
| 330 } | |
| 331 | |
| 332 void NetworkQualityEstimator::CachedNetworkQuality::UpdateNetworkQuality( | |
| 333 uint64_t median_kbps, | |
| 334 const base::TimeDelta& median_rtt) { | |
| 335 median_kbps_ = median_kbps; | |
| 336 median_rtt_ = median_rtt; | |
| 337 last_updated_ = base::TimeTicks::Now(); | |
| 338 DCHECK_GE(median_kbps_, 0U); | |
| 339 DCHECK_GE(median_rtt_, base::TimeDelta()); | |
| 340 } | |
| 341 | |
| 342 bool NetworkQualityEstimator::CachedNetworkQuality::MatchesNetwork( | |
| 343 NetworkChangeNotifier::ConnectionType connection_type, | |
| 344 const std::string& network_name) const { | |
| 345 return connection_type == connection_type_ && network_name == network_name_; | |
| 346 } | |
| 347 | |
| 348 base::TimeTicks NetworkQualityEstimator::CachedNetworkQuality::GetLastUpdated() | |
|
bengr
2015/06/05 20:34:31
Can this be inlined in the .h and renamed last_upd
tbansal1
2015/06/06 01:03:14
Done.
| |
| 349 const { | |
| 350 return last_updated_; | |
| 351 } | |
| 352 | |
| 180 } // namespace net | 353 } // namespace net |
| OLD | NEW |