| 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 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 87 // parameter for Wi-Fi would be "WiFi.DefaultMedianKbps". | 87 // parameter for Wi-Fi would be "WiFi.DefaultMedianKbps". |
| 88 const char kDefaultKbpsObservationSuffix[] = ".DefaultMedianKbps"; | 88 const char kDefaultKbpsObservationSuffix[] = ".DefaultMedianKbps"; |
| 89 | 89 |
| 90 // Suffix of the name of the variation parameter that contains the threshold | 90 // Suffix of the name of the variation parameter that contains the threshold |
| 91 // HTTP RTTs (in milliseconds) for different effective connection types. | 91 // HTTP RTTs (in milliseconds) for different effective connection types. |
| 92 // Complete name of the variation parameter would be | 92 // Complete name of the variation parameter would be |
| 93 // |EffectiveConnectionType|.|kThresholdURLRTTMsecSuffix|. | 93 // |EffectiveConnectionType|.|kThresholdURLRTTMsecSuffix|. |
| 94 const char kThresholdURLRTTMsecSuffix[] = ".ThresholdMedianHttpRTTMsec"; | 94 const char kThresholdURLRTTMsecSuffix[] = ".ThresholdMedianHttpRTTMsec"; |
| 95 | 95 |
| 96 // Suffix of the name of the variation parameter that contains the threshold | 96 // Suffix of the name of the variation parameter that contains the threshold |
| 97 // transport RTTs (in milliseconds) for different effective connection types. |
| 98 // Complete name of the variation parameter would be |
| 99 // |EffectiveConnectionType|.|kThresholdTransportRTTMsecSuffix|. |
| 100 const char kThresholdTransportRTTMsecSuffix[] = |
| 101 ".ThresholdMedianTransportRTTMsec"; |
| 102 |
| 103 // Suffix of the name of the variation parameter that contains the threshold |
| 97 // downlink throughput (in kbps) for different effective connection types. | 104 // downlink throughput (in kbps) for different effective connection types. |
| 98 // Complete name of the variation parameter would be | 105 // Complete name of the variation parameter would be |
| 99 // |EffectiveConnectionType|.|kThresholdKbpsSuffix|. | 106 // |EffectiveConnectionType|.|kThresholdKbpsSuffix|. |
| 100 const char kThresholdKbpsSuffix[] = ".ThresholdMedianKbps"; | 107 const char kThresholdKbpsSuffix[] = ".ThresholdMedianKbps"; |
| 101 | 108 |
| 102 // Computes and returns the weight multiplier per second. | 109 // Computes and returns the weight multiplier per second. |
| 103 // |variation_params| is the map containing all field trial parameters | 110 // |variation_params| is the map containing all field trial parameters |
| 104 // related to NetworkQualityEstimator field trial. | 111 // related to NetworkQualityEstimator field trial. |
| 105 double GetWeightMultiplierPerSecond( | 112 double GetWeightMultiplierPerSecond( |
| 106 const std::map<std::string, std::string>& variation_params) { | 113 const std::map<std::string, std::string>& variation_params) { |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 221 false, | 228 false, |
| 222 false) {} | 229 false) {} |
| 223 | 230 |
| 224 NetworkQualityEstimator::NetworkQualityEstimator( | 231 NetworkQualityEstimator::NetworkQualityEstimator( |
| 225 std::unique_ptr<ExternalEstimateProvider> external_estimates_provider, | 232 std::unique_ptr<ExternalEstimateProvider> external_estimates_provider, |
| 226 const std::map<std::string, std::string>& variation_params, | 233 const std::map<std::string, std::string>& variation_params, |
| 227 bool use_local_host_requests_for_tests, | 234 bool use_local_host_requests_for_tests, |
| 228 bool use_smaller_responses_for_tests) | 235 bool use_smaller_responses_for_tests) |
| 229 : algorithm_name_to_enum_({{"HttpRTTAndDownstreamThroughput", | 236 : algorithm_name_to_enum_({{"HttpRTTAndDownstreamThroughput", |
| 230 EffectiveConnectionTypeAlgorithm:: | 237 EffectiveConnectionTypeAlgorithm:: |
| 231 HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT}}), | 238 HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT}, |
| 239 {"TransportRTTOrDownstreamThroughput", |
| 240 EffectiveConnectionTypeAlgorithm:: |
| 241 TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT}}), |
| 232 use_localhost_requests_(use_local_host_requests_for_tests), | 242 use_localhost_requests_(use_local_host_requests_for_tests), |
| 233 use_small_responses_(use_smaller_responses_for_tests), | 243 use_small_responses_(use_smaller_responses_for_tests), |
| 234 weight_multiplier_per_second_( | 244 weight_multiplier_per_second_( |
| 235 GetWeightMultiplierPerSecond(variation_params)), | 245 GetWeightMultiplierPerSecond(variation_params)), |
| 236 effective_connection_type_algorithm_( | 246 effective_connection_type_algorithm_( |
| 237 algorithm_name_to_enum_.find(GetEffectiveConnectionTypeAlgorithm( | 247 algorithm_name_to_enum_.find(GetEffectiveConnectionTypeAlgorithm( |
| 238 variation_params)) == algorithm_name_to_enum_.end() | 248 variation_params)) == algorithm_name_to_enum_.end() |
| 239 ? kDefaultEffectiveConnectionTypeAlgorithm | 249 ? kDefaultEffectiveConnectionTypeAlgorithm |
| 240 : algorithm_name_to_enum_ | 250 : algorithm_name_to_enum_ |
| 241 .find(GetEffectiveConnectionTypeAlgorithm(variation_params)) | 251 .find(GetEffectiveConnectionTypeAlgorithm(variation_params)) |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 369 continue; | 379 continue; |
| 370 | 380 |
| 371 std::string connection_type_name = std::string( | 381 std::string connection_type_name = std::string( |
| 372 GetNameForEffectiveConnectionType(effective_connection_type)); | 382 GetNameForEffectiveConnectionType(effective_connection_type)); |
| 373 | 383 |
| 374 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1; | 384 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1; |
| 375 if (GetValueForVariationParam( | 385 if (GetValueForVariationParam( |
| 376 variation_params, connection_type_name + kThresholdURLRTTMsecSuffix, | 386 variation_params, connection_type_name + kThresholdURLRTTMsecSuffix, |
| 377 &variations_value) && | 387 &variations_value) && |
| 378 variations_value >= kMinimumRTTVariationParameterMsec) { | 388 variations_value >= kMinimumRTTVariationParameterMsec) { |
| 379 base::TimeDelta rtt(base::TimeDelta::FromMilliseconds(variations_value)); | 389 connection_thresholds_[i].set_http_rtt( |
| 380 connection_thresholds_[i] = nqe::internal::NetworkQuality( | 390 base::TimeDelta(base::TimeDelta::FromMilliseconds(variations_value))); |
| 381 rtt, connection_thresholds_[i].transport_rtt(), | |
| 382 connection_thresholds_[i].downstream_throughput_kbps()); | |
| 383 | 391 |
| 384 // Verify that the RTT values are in decreasing order as the network | 392 // Verify that the RTT values are in decreasing order as the network |
| 385 // quality improves. | 393 // quality improves. |
| 386 DCHECK(i == 0 || | 394 DCHECK(i == 0 || |
| 387 connection_thresholds_[i - 1].http_rtt() == | 395 connection_thresholds_[i - 1].http_rtt() == |
| 388 nqe::internal::InvalidRTT() || | 396 nqe::internal::InvalidRTT() || |
| 389 rtt <= connection_thresholds_[i - 1].http_rtt()); | 397 connection_thresholds_[i].http_rtt() <= |
| 398 connection_thresholds_[i - 1].http_rtt()); |
| 399 } |
| 400 |
| 401 variations_value = kMinimumRTTVariationParameterMsec - 1; |
| 402 if (GetValueForVariationParam( |
| 403 variation_params, |
| 404 connection_type_name + kThresholdTransportRTTMsecSuffix, |
| 405 &variations_value) && |
| 406 variations_value >= kMinimumRTTVariationParameterMsec) { |
| 407 connection_thresholds_[i].set_transport_rtt( |
| 408 base::TimeDelta(base::TimeDelta::FromMilliseconds(variations_value))); |
| 409 |
| 410 // Verify that the transport RTT values are in decreasing order as the |
| 411 // network quality improves. |
| 412 DCHECK(i == 0 || |
| 413 connection_thresholds_[i - 1].transport_rtt() == |
| 414 nqe::internal::InvalidRTT() || |
| 415 connection_thresholds_[i].transport_rtt() <= |
| 416 connection_thresholds_[i - 1].transport_rtt()); |
| 390 } | 417 } |
| 391 | 418 |
| 392 variations_value = kMinimumThroughputVariationParameterKbps - 1; | 419 variations_value = kMinimumThroughputVariationParameterKbps - 1; |
| 393 if (GetValueForVariationParam(variation_params, | 420 if (GetValueForVariationParam(variation_params, |
| 394 connection_type_name + kThresholdKbpsSuffix, | 421 connection_type_name + kThresholdKbpsSuffix, |
| 395 &variations_value) && | 422 &variations_value) && |
| 396 variations_value >= kMinimumThroughputVariationParameterKbps) { | 423 variations_value >= kMinimumThroughputVariationParameterKbps) { |
| 397 int32_t throughput_kbps = variations_value; | 424 connection_thresholds_[i].set_downstream_throughput_kbps( |
| 398 connection_thresholds_[i] = nqe::internal::NetworkQuality( | 425 variations_value); |
| 399 connection_thresholds_[i].http_rtt(), | |
| 400 connection_thresholds_[i].transport_rtt(), throughput_kbps); | |
| 401 | 426 |
| 402 // Verify that the throughput values are in increasing order as the | 427 // Verify that the throughput values are in increasing order as the |
| 403 // network quality improves. | 428 // network quality improves. |
| 404 DCHECK(i == 0 || | 429 DCHECK(i == 0 || |
| 405 connection_thresholds_[i - 1].downstream_throughput_kbps() == | 430 connection_thresholds_[i - 1].downstream_throughput_kbps() == |
| 406 kMinimumThroughputVariationParameterKbps || | 431 kMinimumThroughputVariationParameterKbps || |
| 407 throughput_kbps >= | 432 connection_thresholds_[i].downstream_throughput_kbps() >= |
| 408 connection_thresholds_[i - 1].downstream_throughput_kbps()); | 433 connection_thresholds_[i - 1].downstream_throughput_kbps()); |
| 409 } | 434 } |
| 410 } | 435 } |
| 411 } | 436 } |
| 412 | 437 |
| 413 void NetworkQualityEstimator::AddDefaultEstimates() { | 438 void NetworkQualityEstimator::AddDefaultEstimates() { |
| 414 DCHECK(thread_checker_.CalledOnValidThread()); | 439 DCHECK(thread_checker_.CalledOnValidThread()); |
| 415 | 440 |
| 416 if (default_observations_[current_network_id_.type].http_rtt() != | 441 if (default_observations_[current_network_id_.type].http_rtt() != |
| 417 nqe::internal::InvalidRTT()) { | 442 nqe::internal::InvalidRTT()) { |
| (...skipping 495 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 913 return GetRecentEffectiveConnectionType(base::TimeTicks()); | 938 return GetRecentEffectiveConnectionType(base::TimeTicks()); |
| 914 } | 939 } |
| 915 | 940 |
| 916 NetworkQualityEstimator::EffectiveConnectionType | 941 NetworkQualityEstimator::EffectiveConnectionType |
| 917 NetworkQualityEstimator::GetRecentEffectiveConnectionType( | 942 NetworkQualityEstimator::GetRecentEffectiveConnectionType( |
| 918 const base::TimeTicks& start_time) const { | 943 const base::TimeTicks& start_time) const { |
| 919 DCHECK(thread_checker_.CalledOnValidThread()); | 944 DCHECK(thread_checker_.CalledOnValidThread()); |
| 920 | 945 |
| 921 if (effective_connection_type_algorithm_ == | 946 if (effective_connection_type_algorithm_ == |
| 922 EffectiveConnectionTypeAlgorithm::HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT) { | 947 EffectiveConnectionTypeAlgorithm::HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT) { |
| 923 return GetRecentEffectiveConnectionTypeHttpRTTAndDownstreamThroughput( | 948 return GetRecentEffectiveConnectionTypeUsingMetrics( |
| 924 start_time); | 949 start_time, NetworkQualityEstimator::MetricUsage:: |
| 950 MUST_BE_USED /* http_rtt_metric */, |
| 951 NetworkQualityEstimator::MetricUsage:: |
| 952 DO_NOT_USE /* transport_rtt_metric */, |
| 953 NetworkQualityEstimator::MetricUsage:: |
| 954 MUST_BE_USED /* downstream_throughput_kbps_metric */); |
| 955 } |
| 956 if (effective_connection_type_algorithm_ == |
| 957 EffectiveConnectionTypeAlgorithm:: |
| 958 TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT) { |
| 959 return GetRecentEffectiveConnectionTypeUsingMetrics( |
| 960 start_time, |
| 961 NetworkQualityEstimator::MetricUsage::DO_NOT_USE /* http_rtt_metric */, |
| 962 NetworkQualityEstimator::MetricUsage:: |
| 963 USE_IF_AVAILABLE /* transport_rtt_metric */, |
| 964 NetworkQualityEstimator::MetricUsage:: |
| 965 USE_IF_AVAILABLE /* downstream_throughput_kbps_metric */); |
| 925 } | 966 } |
| 926 // Add additional algorithms here. | 967 // Add additional algorithms here. |
| 927 NOTREACHED(); | 968 NOTREACHED(); |
| 928 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; | 969 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
| 929 } | 970 } |
| 930 | 971 |
| 931 NetworkQualityEstimator::EffectiveConnectionType NetworkQualityEstimator:: | 972 NetworkQualityEstimator::EffectiveConnectionType |
| 932 GetRecentEffectiveConnectionTypeHttpRTTAndDownstreamThroughput( | 973 NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics( |
| 933 const base::TimeTicks& start_time) const { | 974 const base::TimeTicks& start_time, |
| 975 NetworkQualityEstimator::MetricUsage http_rtt_metric, |
| 976 NetworkQualityEstimator::MetricUsage transport_rtt_metric, |
| 977 NetworkQualityEstimator::MetricUsage downstream_throughput_kbps_metric) |
| 978 const { |
| 934 DCHECK(thread_checker_.CalledOnValidThread()); | 979 DCHECK(thread_checker_.CalledOnValidThread()); |
| 935 | 980 |
| 936 // If the device is currently offline, then return | 981 // If the device is currently offline, then return |
| 937 // EFFECTIVE_CONNECTION_TYPE_OFFLINE. | 982 // EFFECTIVE_CONNECTION_TYPE_OFFLINE. |
| 938 if (GetCurrentNetworkID().type == NetworkChangeNotifier::CONNECTION_NONE) | 983 if (GetCurrentNetworkID().type == NetworkChangeNotifier::CONNECTION_NONE) |
| 939 return EFFECTIVE_CONNECTION_TYPE_OFFLINE; | 984 return EFFECTIVE_CONNECTION_TYPE_OFFLINE; |
| 940 | 985 |
| 941 base::TimeDelta http_rtt = nqe::internal::InvalidRTT(); | 986 base::TimeDelta http_rtt = nqe::internal::InvalidRTT(); |
| 942 if (!GetRecentHttpRTTMedian(start_time, &http_rtt)) | 987 if (http_rtt_metric != NetworkQualityEstimator::MetricUsage::DO_NOT_USE && |
| 988 !GetRecentHttpRTTMedian(start_time, &http_rtt)) { |
| 943 http_rtt = nqe::internal::InvalidRTT(); | 989 http_rtt = nqe::internal::InvalidRTT(); |
| 990 } |
| 991 |
| 992 base::TimeDelta transport_rtt = nqe::internal::InvalidRTT(); |
| 993 if (transport_rtt_metric != |
| 994 NetworkQualityEstimator::MetricUsage::DO_NOT_USE && |
| 995 !GetRecentTransportRTTMedian(start_time, &transport_rtt)) { |
| 996 transport_rtt = nqe::internal::InvalidRTT(); |
| 997 } |
| 944 | 998 |
| 945 int32_t kbps = nqe::internal::kInvalidThroughput; | 999 int32_t kbps = nqe::internal::kInvalidThroughput; |
| 946 if (!GetRecentMedianDownlinkThroughputKbps(start_time, &kbps)) | 1000 if (downstream_throughput_kbps_metric != |
| 1001 NetworkQualityEstimator::MetricUsage::DO_NOT_USE && |
| 1002 !GetRecentMedianDownlinkThroughputKbps(start_time, &kbps)) { |
| 947 kbps = nqe::internal::kInvalidThroughput; | 1003 kbps = nqe::internal::kInvalidThroughput; |
| 1004 } |
| 948 | 1005 |
| 949 if (http_rtt == nqe::internal::InvalidRTT() || | 1006 if (http_rtt == nqe::internal::InvalidRTT() && |
| 950 kbps == nqe::internal::kInvalidThroughput) { | 1007 http_rtt_metric == NetworkQualityEstimator::MetricUsage::MUST_BE_USED) { |
| 951 // Quality of the current network is unknown. | |
| 952 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; | 1008 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
| 953 } | 1009 } |
| 954 | 1010 |
| 1011 if (transport_rtt == nqe::internal::InvalidRTT() && |
| 1012 transport_rtt_metric == |
| 1013 NetworkQualityEstimator::MetricUsage::MUST_BE_USED) { |
| 1014 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
| 1015 } |
| 1016 |
| 1017 if (kbps == nqe::internal::kInvalidThroughput && |
| 1018 downstream_throughput_kbps_metric == |
| 1019 NetworkQualityEstimator::MetricUsage::MUST_BE_USED) { |
| 1020 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
| 1021 } |
| 1022 |
| 1023 if (http_rtt == nqe::internal::InvalidRTT() && |
| 1024 transport_rtt == nqe::internal::InvalidRTT() && |
| 1025 kbps == nqe::internal::kInvalidThroughput) { |
| 1026 // None of the metrics are available. |
| 1027 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN; |
| 1028 } |
| 1029 |
| 955 // Search from the slowest connection type to the fastest to find the | 1030 // Search from the slowest connection type to the fastest to find the |
| 956 // EffectiveConnectionType that best matches the current connection's | 1031 // EffectiveConnectionType that best matches the current connection's |
| 957 // performance. The match is done by comparing RTT and throughput. | 1032 // performance. The match is done by comparing RTT and throughput. |
| 958 for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) { | 1033 for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) { |
| 959 EffectiveConnectionType type = static_cast<EffectiveConnectionType>(i); | 1034 EffectiveConnectionType type = static_cast<EffectiveConnectionType>(i); |
| 960 if (i == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) | 1035 if (i == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) |
| 961 continue; | 1036 continue; |
| 962 bool estimated_http_rtt_is_higher_than_threshold = | 1037 |
| 1038 const bool estimated_http_rtt_is_higher_than_threshold = |
| 963 http_rtt != nqe::internal::InvalidRTT() && | 1039 http_rtt != nqe::internal::InvalidRTT() && |
| 964 connection_thresholds_[i].http_rtt() != nqe::internal::InvalidRTT() && | 1040 connection_thresholds_[i].http_rtt() != nqe::internal::InvalidRTT() && |
| 965 http_rtt >= connection_thresholds_[i].http_rtt(); | 1041 http_rtt >= connection_thresholds_[i].http_rtt(); |
| 966 bool estimated_throughput_is_lower_than_threshold = | 1042 |
| 1043 const bool estimated_transport_rtt_is_higher_than_threshold = |
| 1044 transport_rtt != nqe::internal::InvalidRTT() && |
| 1045 connection_thresholds_[i].transport_rtt() != |
| 1046 nqe::internal::InvalidRTT() && |
| 1047 transport_rtt >= connection_thresholds_[i].transport_rtt(); |
| 1048 |
| 1049 const bool estimated_throughput_is_lower_than_threshold = |
| 967 kbps != nqe::internal::kInvalidThroughput && | 1050 kbps != nqe::internal::kInvalidThroughput && |
| 968 connection_thresholds_[i].downstream_throughput_kbps() != | 1051 connection_thresholds_[i].downstream_throughput_kbps() != |
| 969 nqe::internal::kInvalidThroughput && | 1052 nqe::internal::kInvalidThroughput && |
| 970 kbps <= connection_thresholds_[i].downstream_throughput_kbps(); | 1053 kbps <= connection_thresholds_[i].downstream_throughput_kbps(); |
| 971 | 1054 |
| 972 // Return |type| as the effective connection type if the current network's | |
| 973 // RTT is worse than the threshold RTT for |type|, or if the current | |
| 974 // network's throughput is lower than the threshold throughput for |type|. | |
| 975 if (estimated_http_rtt_is_higher_than_threshold || | 1055 if (estimated_http_rtt_is_higher_than_threshold || |
| 1056 estimated_transport_rtt_is_higher_than_threshold || |
| 976 estimated_throughput_is_lower_than_threshold) { | 1057 estimated_throughput_is_lower_than_threshold) { |
| 977 return type; | 1058 return type; |
| 978 } | 1059 } |
| 979 } | 1060 } |
| 980 // Return the fastest connection type. | 1061 // Return the fastest connection type. |
| 981 return static_cast<EffectiveConnectionType>(EFFECTIVE_CONNECTION_TYPE_LAST - | 1062 return static_cast<EffectiveConnectionType>(EFFECTIVE_CONNECTION_TYPE_LAST - |
| 982 1); | 1063 1); |
| 983 } | 1064 } |
| 984 | 1065 |
| 985 void NetworkQualityEstimator::AddEffectiveConnectionTypeObserver( | 1066 void NetworkQualityEstimator::AddEffectiveConnectionTypeObserver( |
| (...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1391 NotifyObserversOfEffectiveConnectionTypeChanged() { | 1472 NotifyObserversOfEffectiveConnectionTypeChanged() { |
| 1392 DCHECK(thread_checker_.CalledOnValidThread()); | 1473 DCHECK(thread_checker_.CalledOnValidThread()); |
| 1393 | 1474 |
| 1394 // TODO(tbansal): Add hysteresis in the notification. | 1475 // TODO(tbansal): Add hysteresis in the notification. |
| 1395 FOR_EACH_OBSERVER( | 1476 FOR_EACH_OBSERVER( |
| 1396 EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, | 1477 EffectiveConnectionTypeObserver, effective_connection_type_observer_list_, |
| 1397 OnEffectiveConnectionTypeChanged(effective_connection_type_)); | 1478 OnEffectiveConnectionTypeChanged(effective_connection_type_)); |
| 1398 } | 1479 } |
| 1399 | 1480 |
| 1400 } // namespace net | 1481 } // namespace net |
| OLD | NEW |