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