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/nqe/network_quality_estimator.h" | 5 #include "net/nqe/network_quality_estimator.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <cmath> | 8 #include <cmath> |
9 #include <limits> | 9 #include <limits> |
10 #include <utility> | 10 #include <utility> |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
247 algorithm_name_to_enum_.find(GetEffectiveConnectionTypeAlgorithm( | 247 algorithm_name_to_enum_.find(GetEffectiveConnectionTypeAlgorithm( |
248 variation_params)) == algorithm_name_to_enum_.end() | 248 variation_params)) == algorithm_name_to_enum_.end() |
249 ? kDefaultEffectiveConnectionTypeAlgorithm | 249 ? kDefaultEffectiveConnectionTypeAlgorithm |
250 : algorithm_name_to_enum_ | 250 : algorithm_name_to_enum_ |
251 .find(GetEffectiveConnectionTypeAlgorithm(variation_params)) | 251 .find(GetEffectiveConnectionTypeAlgorithm(variation_params)) |
252 ->second), | 252 ->second), |
253 tick_clock_(new base::DefaultTickClock()), | 253 tick_clock_(new base::DefaultTickClock()), |
254 effective_connection_type_recomputation_interval_( | 254 effective_connection_type_recomputation_interval_( |
255 base::TimeDelta::FromSeconds(15)), | 255 base::TimeDelta::FromSeconds(15)), |
256 last_connection_change_(tick_clock_->NowTicks()), | 256 last_connection_change_(tick_clock_->NowTicks()), |
257 current_network_id_( | 257 current_network_id_(nqe::internal::NetworkID( |
258 NetworkID(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, | 258 NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, |
259 std::string())), | 259 std::string())), |
260 downstream_throughput_kbps_observations_(weight_multiplier_per_second_), | 260 downstream_throughput_kbps_observations_(weight_multiplier_per_second_), |
261 rtt_observations_(weight_multiplier_per_second_), | 261 rtt_observations_(weight_multiplier_per_second_), |
262 effective_connection_type_at_last_main_frame_( | 262 effective_connection_type_at_last_main_frame_( |
263 EFFECTIVE_CONNECTION_TYPE_UNKNOWN), | 263 EFFECTIVE_CONNECTION_TYPE_UNKNOWN), |
264 external_estimate_provider_(std::move(external_estimates_provider)), | 264 external_estimate_provider_(std::move(external_estimates_provider)), |
265 effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN), | 265 effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN), |
266 min_signal_strength_since_connection_change_(INT32_MAX), | 266 min_signal_strength_since_connection_change_(INT32_MAX), |
267 max_signal_strength_since_connection_change_(INT32_MIN), | 267 max_signal_strength_since_connection_change_(INT32_MIN), |
268 weak_ptr_factory_(this) { | 268 weak_ptr_factory_(this) { |
269 static_assert(kDefaultHalfLifeSeconds > 0, | 269 static_assert(kDefaultHalfLifeSeconds > 0, |
270 "Default half life duration must be > 0"); | 270 "Default half life duration must be > 0"); |
271 static_assert(kMaximumNetworkQualityCacheSize > 0, | |
272 "Size of the network quality cache must be > 0"); | |
273 // This limit should not be increased unless the logic for removing the | |
274 // oldest cache entry is rewritten to use a doubly-linked-list LRU queue. | |
275 static_assert(kMaximumNetworkQualityCacheSize <= 10, | |
276 "Size of the network quality cache must <= 10"); | |
277 // None of the algorithms can have an empty name. | 271 // None of the algorithms can have an empty name. |
278 DCHECK(algorithm_name_to_enum_.end() == | 272 DCHECK(algorithm_name_to_enum_.end() == |
279 algorithm_name_to_enum_.find(std::string())); | 273 algorithm_name_to_enum_.find(std::string())); |
280 | 274 |
281 DCHECK_EQ(algorithm_name_to_enum_.size(), | 275 DCHECK_EQ(algorithm_name_to_enum_.size(), |
282 static_cast<size_t>(EffectiveConnectionTypeAlgorithm:: | 276 static_cast<size_t>(EffectiveConnectionTypeAlgorithm:: |
283 EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST)); | 277 EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST)); |
284 DCHECK_NE(EffectiveConnectionTypeAlgorithm:: | 278 DCHECK_NE(EffectiveConnectionTypeAlgorithm:: |
285 EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST, | 279 EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST, |
286 effective_connection_type_algorithm_); | 280 effective_connection_type_algorithm_); |
(...skipping 468 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
755 EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY); | 749 EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY); |
756 } | 750 } |
757 | 751 |
758 void NetworkQualityEstimator::OnConnectionTypeChanged( | 752 void NetworkQualityEstimator::OnConnectionTypeChanged( |
759 NetworkChangeNotifier::ConnectionType type) { | 753 NetworkChangeNotifier::ConnectionType type) { |
760 DCHECK(thread_checker_.CalledOnValidThread()); | 754 DCHECK(thread_checker_.CalledOnValidThread()); |
761 | 755 |
762 RecordMetricsOnConnectionTypeChanged(); | 756 RecordMetricsOnConnectionTypeChanged(); |
763 | 757 |
764 // Write the estimates of the previous network to the cache. | 758 // Write the estimates of the previous network to the cache. |
765 CacheNetworkQualityEstimate(); | 759 network_qualities_manager_.CacheNetworkQualityEstimate( |
760 current_network_id_, nqe::internal::CachedNetworkQuality( | |
761 last_effective_connection_type_computation_, | |
762 estimated_quality_at_last_main_frame_)); | |
766 | 763 |
767 // Clear the local state. | 764 // Clear the local state. |
768 last_connection_change_ = tick_clock_->NowTicks(); | 765 last_connection_change_ = tick_clock_->NowTicks(); |
769 peak_network_quality_ = nqe::internal::NetworkQuality(); | 766 peak_network_quality_ = nqe::internal::NetworkQuality(); |
770 downstream_throughput_kbps_observations_.Clear(); | 767 downstream_throughput_kbps_observations_.Clear(); |
771 rtt_observations_.Clear(); | 768 rtt_observations_.Clear(); |
772 | 769 |
773 #if defined(OS_ANDROID) | 770 #if defined(OS_ANDROID) |
774 if (NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) { | 771 if (NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) { |
775 UMA_HISTOGRAM_BOOLEAN( | 772 UMA_HISTOGRAM_BOOLEAN( |
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
973 NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics( | 970 NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics( |
974 const base::TimeTicks& start_time, | 971 const base::TimeTicks& start_time, |
975 NetworkQualityEstimator::MetricUsage http_rtt_metric, | 972 NetworkQualityEstimator::MetricUsage http_rtt_metric, |
976 NetworkQualityEstimator::MetricUsage transport_rtt_metric, | 973 NetworkQualityEstimator::MetricUsage transport_rtt_metric, |
977 NetworkQualityEstimator::MetricUsage downstream_throughput_kbps_metric) | 974 NetworkQualityEstimator::MetricUsage downstream_throughput_kbps_metric) |
978 const { | 975 const { |
979 DCHECK(thread_checker_.CalledOnValidThread()); | 976 DCHECK(thread_checker_.CalledOnValidThread()); |
980 | 977 |
981 // If the device is currently offline, then return | 978 // If the device is currently offline, then return |
982 // EFFECTIVE_CONNECTION_TYPE_OFFLINE. | 979 // EFFECTIVE_CONNECTION_TYPE_OFFLINE. |
983 if (GetCurrentNetworkID().type == NetworkChangeNotifier::CONNECTION_NONE) | 980 if (current_network_id_.type == NetworkChangeNotifier::CONNECTION_NONE) |
984 return EFFECTIVE_CONNECTION_TYPE_OFFLINE; | 981 return EFFECTIVE_CONNECTION_TYPE_OFFLINE; |
985 | 982 |
986 base::TimeDelta http_rtt = nqe::internal::InvalidRTT(); | 983 base::TimeDelta http_rtt = nqe::internal::InvalidRTT(); |
987 if (http_rtt_metric != NetworkQualityEstimator::MetricUsage::DO_NOT_USE && | 984 if (http_rtt_metric != NetworkQualityEstimator::MetricUsage::DO_NOT_USE && |
988 !GetRecentHttpRTTMedian(start_time, &http_rtt)) { | 985 !GetRecentHttpRTTMedian(start_time, &http_rtt)) { |
989 http_rtt = nqe::internal::InvalidRTT(); | 986 http_rtt = nqe::internal::InvalidRTT(); |
990 } | 987 } |
991 | 988 |
992 base::TimeDelta transport_rtt = nqe::internal::InvalidRTT(); | 989 base::TimeDelta transport_rtt = nqe::internal::InvalidRTT(); |
993 if (transport_rtt_metric != | 990 if (transport_rtt_metric != |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1158 // thus a higher percentile throughput will be faster than a lower one. | 1155 // thus a higher percentile throughput will be faster than a lower one. |
1159 int32_t kbps = nqe::internal::kInvalidThroughput; | 1156 int32_t kbps = nqe::internal::kInvalidThroughput; |
1160 if (!downstream_throughput_kbps_observations_.GetPercentile( | 1157 if (!downstream_throughput_kbps_observations_.GetPercentile( |
1161 start_time, &kbps, 100 - percentile, | 1158 start_time, &kbps, 100 - percentile, |
1162 std::vector<NetworkQualityObservationSource>())) { | 1159 std::vector<NetworkQualityObservationSource>())) { |
1163 return nqe::internal::kInvalidThroughput; | 1160 return nqe::internal::kInvalidThroughput; |
1164 } | 1161 } |
1165 return kbps; | 1162 return kbps; |
1166 } | 1163 } |
1167 | 1164 |
1168 NetworkQualityEstimator::NetworkID | 1165 nqe::internal::NetworkID NetworkQualityEstimator::GetCurrentNetworkID() const { |
1169 NetworkQualityEstimator::GetCurrentNetworkID() const { | |
1170 DCHECK(thread_checker_.CalledOnValidThread()); | 1166 DCHECK(thread_checker_.CalledOnValidThread()); |
1171 | 1167 |
1172 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class | 1168 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class |
1173 // that overrides this method on the Android platform. | 1169 // that overrides this method on the Android platform. |
1174 | 1170 |
1175 // It is possible that the connection type changed between when | 1171 // It is possible that the connection type changed between when |
1176 // GetConnectionType() was called and when the API to determine the | 1172 // GetConnectionType() was called and when the API to determine the |
1177 // network name was called. Check if that happened and retry until the | 1173 // network name was called. Check if that happened and retry until the |
1178 // connection type stabilizes. This is an imperfect solution but should | 1174 // connection type stabilizes. This is an imperfect solution but should |
1179 // capture majority of cases, and should not significantly affect estimates | 1175 // capture majority of cases, and should not significantly affect estimates |
1180 // (that are approximate to begin with). | 1176 // (that are approximate to begin with). |
1181 while (true) { | 1177 while (true) { |
1182 NetworkQualityEstimator::NetworkID network_id( | 1178 nqe::internal::NetworkID network_id( |
1183 NetworkChangeNotifier::GetConnectionType(), std::string()); | 1179 NetworkChangeNotifier::GetConnectionType(), std::string()); |
1184 | 1180 |
1185 switch (network_id.type) { | 1181 switch (network_id.type) { |
1186 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN: | 1182 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN: |
1187 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE: | 1183 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE: |
1188 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH: | 1184 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH: |
1189 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET: | 1185 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET: |
1190 break; | 1186 break; |
1191 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI: | 1187 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI: |
1192 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \ | 1188 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \ |
(...skipping 15 matching lines...) Expand all Loading... | |
1208 | 1204 |
1209 if (network_id.type == NetworkChangeNotifier::GetConnectionType()) | 1205 if (network_id.type == NetworkChangeNotifier::GetConnectionType()) |
1210 return network_id; | 1206 return network_id; |
1211 } | 1207 } |
1212 NOTREACHED(); | 1208 NOTREACHED(); |
1213 } | 1209 } |
1214 | 1210 |
1215 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() { | 1211 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() { |
1216 DCHECK(thread_checker_.CalledOnValidThread()); | 1212 DCHECK(thread_checker_.CalledOnValidThread()); |
1217 | 1213 |
1218 // If the network name is unavailable, caching should not be performed. | 1214 nqe::internal::CachedNetworkQuality cached_network_quality; |
1219 if (current_network_id_.id.empty()) | 1215 |
1216 if (!network_qualities_manager_.GetCachedNetworkQualityEstimate( | |
1217 current_network_id_, &cached_network_quality)) { | |
1218 UMA_HISTOGRAM_BOOLEAN("NQE.CachedNetworkQualityAvailable", false); | |
RyanSturm
2016/07/12 18:45:38
Can you combine the two NQE.CacheNetworkQualityAva
tbansal1
2016/07/12 19:40:19
Done.
| |
1220 return false; | 1219 return false; |
1221 | 1220 } |
1222 CachedNetworkQualities::const_iterator it = | |
1223 cached_network_qualities_.find(current_network_id_); | |
1224 | |
1225 if (it == cached_network_qualities_.end()) | |
1226 return false; | |
1227 | |
1228 nqe::internal::NetworkQuality network_quality(it->second.network_quality()); | |
1229 | 1221 |
1230 const base::TimeTicks now = tick_clock_->NowTicks(); | 1222 const base::TimeTicks now = tick_clock_->NowTicks(); |
1231 bool read_cached_estimate = false; | |
1232 | 1223 |
1233 if (network_quality.downstream_throughput_kbps() != | 1224 if (cached_network_quality.network_quality().downstream_throughput_kbps() != |
1234 nqe::internal::kInvalidThroughput) { | 1225 nqe::internal::kInvalidThroughput) { |
1235 read_cached_estimate = true; | |
1236 ThroughputObservation througphput_observation( | 1226 ThroughputObservation througphput_observation( |
1237 network_quality.downstream_throughput_kbps(), now, | 1227 cached_network_quality.network_quality().downstream_throughput_kbps(), |
1238 NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE); | 1228 now, NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE); |
1239 downstream_throughput_kbps_observations_.AddObservation( | 1229 downstream_throughput_kbps_observations_.AddObservation( |
1240 througphput_observation); | 1230 througphput_observation); |
1241 NotifyObserversOfThroughput(througphput_observation); | 1231 NotifyObserversOfThroughput(througphput_observation); |
1242 } | 1232 } |
1243 | 1233 |
1244 if (network_quality.http_rtt() != nqe::internal::InvalidRTT()) { | 1234 if (cached_network_quality.network_quality().http_rtt() != |
1245 read_cached_estimate = true; | 1235 nqe::internal::InvalidRTT()) { |
1246 RttObservation rtt_observation( | 1236 RttObservation rtt_observation( |
1247 network_quality.http_rtt(), now, | 1237 cached_network_quality.network_quality().http_rtt(), now, |
1248 NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE); | 1238 NETWORK_QUALITY_OBSERVATION_SOURCE_CACHED_ESTIMATE); |
1249 rtt_observations_.AddObservation(rtt_observation); | 1239 rtt_observations_.AddObservation(rtt_observation); |
1250 NotifyObserversOfRTT(rtt_observation); | 1240 NotifyObserversOfRTT(rtt_observation); |
1251 } | 1241 } |
1252 | 1242 UMA_HISTOGRAM_BOOLEAN("NQE.CachedNetworkQualityAvailable", true); |
1253 return read_cached_estimate; | 1243 return true; |
1254 } | 1244 } |
1255 | 1245 |
1256 void NetworkQualityEstimator::OnUpdatedEstimateAvailable( | 1246 void NetworkQualityEstimator::OnUpdatedEstimateAvailable( |
1257 const base::TimeDelta& rtt, | 1247 const base::TimeDelta& rtt, |
1258 int32_t downstream_throughput_kbps, | 1248 int32_t downstream_throughput_kbps, |
1259 int32_t upstream_throughput_kbps) { | 1249 int32_t upstream_throughput_kbps) { |
1260 DCHECK(thread_checker_.CalledOnValidThread()); | 1250 DCHECK(thread_checker_.CalledOnValidThread()); |
1261 DCHECK(external_estimate_provider_); | 1251 DCHECK(external_estimate_provider_); |
1262 | 1252 |
1263 RecordExternalEstimateProviderMetrics( | 1253 RecordExternalEstimateProviderMetrics( |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1330 NOTREACHED(); | 1320 NOTREACHED(); |
1331 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; | 1321 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
1332 } | 1322 } |
1333 | 1323 |
1334 void NetworkQualityEstimator::SetTickClockForTesting( | 1324 void NetworkQualityEstimator::SetTickClockForTesting( |
1335 std::unique_ptr<base::TickClock> tick_clock) { | 1325 std::unique_ptr<base::TickClock> tick_clock) { |
1336 DCHECK(thread_checker_.CalledOnValidThread()); | 1326 DCHECK(thread_checker_.CalledOnValidThread()); |
1337 tick_clock_ = std::move(tick_clock); | 1327 tick_clock_ = std::move(tick_clock); |
1338 } | 1328 } |
1339 | 1329 |
1340 void NetworkQualityEstimator::CacheNetworkQualityEstimate() { | |
1341 DCHECK(thread_checker_.CalledOnValidThread()); | |
1342 DCHECK_LE(cached_network_qualities_.size(), | |
1343 static_cast<size_t>(kMaximumNetworkQualityCacheSize)); | |
1344 | |
1345 // If the network name is unavailable, caching should not be performed. | |
1346 if (current_network_id_.id.empty()) | |
1347 return; | |
1348 | |
1349 base::TimeDelta http_rtt = nqe::internal::InvalidRTT(); | |
1350 int32_t downlink_throughput_kbps = nqe::internal::kInvalidThroughput; | |
1351 | |
1352 if (!GetHttpRTTEstimate(&http_rtt) || | |
1353 !GetDownlinkThroughputKbpsEstimate(&downlink_throughput_kbps)) { | |
1354 return; | |
1355 } | |
1356 | |
1357 // |transport_rtt| is currently not cached. | |
1358 nqe::internal::NetworkQuality network_quality = nqe::internal::NetworkQuality( | |
1359 http_rtt, nqe::internal::InvalidRTT() /* transport_rtt */, | |
1360 downlink_throughput_kbps); | |
1361 | |
1362 if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) { | |
1363 // Remove the oldest entry. | |
1364 CachedNetworkQualities::iterator oldest_entry_iterator = | |
1365 cached_network_qualities_.begin(); | |
1366 | |
1367 for (CachedNetworkQualities::iterator it = | |
1368 cached_network_qualities_.begin(); | |
1369 it != cached_network_qualities_.end(); ++it) { | |
1370 if ((it->second).OlderThan(oldest_entry_iterator->second)) | |
1371 oldest_entry_iterator = it; | |
1372 } | |
1373 cached_network_qualities_.erase(oldest_entry_iterator); | |
1374 } | |
1375 DCHECK_LT(cached_network_qualities_.size(), | |
1376 static_cast<size_t>(kMaximumNetworkQualityCacheSize)); | |
1377 | |
1378 cached_network_qualities_.insert( | |
1379 std::make_pair(current_network_id_, | |
1380 nqe::internal::CachedNetworkQuality(network_quality))); | |
1381 DCHECK_LE(cached_network_qualities_.size(), | |
1382 static_cast<size_t>(kMaximumNetworkQualityCacheSize)); | |
1383 } | |
1384 | |
1385 void NetworkQualityEstimator::OnUpdatedRTTAvailable( | 1330 void NetworkQualityEstimator::OnUpdatedRTTAvailable( |
1386 SocketPerformanceWatcherFactory::Protocol protocol, | 1331 SocketPerformanceWatcherFactory::Protocol protocol, |
1387 const base::TimeDelta& rtt) { | 1332 const base::TimeDelta& rtt) { |
1388 DCHECK(thread_checker_.CalledOnValidThread()); | 1333 DCHECK(thread_checker_.CalledOnValidThread()); |
1389 DCHECK_NE(nqe::internal::InvalidRTT(), rtt); | 1334 DCHECK_NE(nqe::internal::InvalidRTT(), rtt); |
1390 | 1335 |
1391 RttObservation observation(rtt, tick_clock_->NowTicks(), | 1336 RttObservation observation(rtt, tick_clock_->NowTicks(), |
1392 ProtocolSourceToObservationSource(protocol)); | 1337 ProtocolSourceToObservationSource(protocol)); |
1393 NotifyObserversOfRTT(observation); | 1338 NotifyObserversOfRTT(observation); |
1394 rtt_observations_.AddObservation(observation); | 1339 rtt_observations_.AddObservation(observation); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1472 NotifyObserversOfEffectiveConnectionTypeChanged() { | 1417 NotifyObserversOfEffectiveConnectionTypeChanged() { |
1473 DCHECK(thread_checker_.CalledOnValidThread()); | 1418 DCHECK(thread_checker_.CalledOnValidThread()); |
1474 | 1419 |
1475 // TODO(tbansal): Add hysteresis in the notification. | 1420 // TODO(tbansal): Add hysteresis in the notification. |
1476 FOR_EACH_OBSERVER( | 1421 FOR_EACH_OBSERVER( |
1477 EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, | 1422 EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, |
1478 OnEffectiveConnectionTypeChanged(effective_connection_type_)); | 1423 OnEffectiveConnectionTypeChanged(effective_connection_type_)); |
1479 } | 1424 } |
1480 | 1425 |
1481 } // namespace net | 1426 } // namespace net |
OLD | NEW |