| 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 16 matching lines...) Expand all Loading... |
| 27 #include "base/trace_event/trace_event.h" | 27 #include "base/trace_event/trace_event.h" |
| 28 #include "build/build_config.h" | 28 #include "build/build_config.h" |
| 29 #include "net/base/load_flags.h" | 29 #include "net/base/load_flags.h" |
| 30 #include "net/base/load_timing_info.h" | 30 #include "net/base/load_timing_info.h" |
| 31 #include "net/base/network_interfaces.h" | 31 #include "net/base/network_interfaces.h" |
| 32 #include "net/base/trace_constants.h" | 32 #include "net/base/trace_constants.h" |
| 33 #include "net/base/url_util.h" | 33 #include "net/base/url_util.h" |
| 34 #include "net/http/http_response_headers.h" | 34 #include "net/http/http_response_headers.h" |
| 35 #include "net/http/http_response_info.h" | 35 #include "net/http/http_response_info.h" |
| 36 #include "net/http/http_status_code.h" | 36 #include "net/http/http_status_code.h" |
| 37 #include "net/nqe/network_quality_estimator_params.h" | |
| 38 #include "net/nqe/socket_watcher_factory.h" | 37 #include "net/nqe/socket_watcher_factory.h" |
| 39 #include "net/nqe/throughput_analyzer.h" | 38 #include "net/nqe/throughput_analyzer.h" |
| 40 #include "net/url_request/url_request.h" | 39 #include "net/url_request/url_request.h" |
| 41 #include "net/url_request/url_request_status.h" | 40 #include "net/url_request/url_request_status.h" |
| 42 #include "url/gurl.h" | 41 #include "url/gurl.h" |
| 43 | 42 |
| 44 #if defined(OS_ANDROID) | 43 #if defined(OS_ANDROID) |
| 45 #include "net/android/cellular_signal_strength.h" | 44 #include "net/android/cellular_signal_strength.h" |
| 46 #include "net/android/network_library.h" | 45 #include "net/android/network_library.h" |
| 47 #endif // OS_ANDROID | 46 #endif // OS_ANDROID |
| 48 | 47 |
| 49 namespace net { | 48 namespace net { |
| 50 | 49 |
| 51 namespace { | 50 namespace { |
| 52 | 51 |
| 53 // Returns the histogram that should be used to record the given statistic. | 52 // Returns the histogram that should be used to record the given statistic. |
| 54 // |max_limit| is the maximum value that can be stored in the histogram. | 53 // |max_limit| is the maximum value that can be stored in the histogram. |
| 55 base::HistogramBase* GetHistogram(const std::string& statistic_name, | 54 base::HistogramBase* GetHistogram(const std::string& statistic_name, |
| 56 NetworkChangeNotifier::ConnectionType type, | 55 NetworkChangeNotifier::ConnectionType type, |
| 57 int32_t max_limit) { | 56 int32_t max_limit) { |
| 58 const base::LinearHistogram::Sample kLowerLimit = 1; | 57 const base::LinearHistogram::Sample kLowerLimit = 1; |
| 59 DCHECK_GT(max_limit, kLowerLimit); | 58 DCHECK_GT(max_limit, kLowerLimit); |
| 60 const size_t kBucketCount = 50; | 59 const size_t kBucketCount = 50; |
| 61 | 60 |
| 62 return base::Histogram::FactoryGet( | 61 return base::Histogram::FactoryGet( |
| 63 "NQE." + statistic_name + nqe::internal::GetNameForConnectionType(type), | 62 "NQE." + statistic_name + |
| 63 nqe::internal::NetworkQualityEstimatorParams:: |
| 64 GetNameForConnectionType(type), |
| 64 kLowerLimit, max_limit, kBucketCount, | 65 kLowerLimit, max_limit, kBucketCount, |
| 65 base::HistogramBase::kUmaTargetedHistogramFlag); | 66 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 66 } | 67 } |
| 67 | 68 |
| 68 NetworkQualityObservationSource ProtocolSourceToObservationSource( | 69 NetworkQualityObservationSource ProtocolSourceToObservationSource( |
| 69 SocketPerformanceWatcherFactory::Protocol protocol) { | 70 SocketPerformanceWatcherFactory::Protocol protocol) { |
| 70 switch (protocol) { | 71 switch (protocol) { |
| 71 case SocketPerformanceWatcherFactory::PROTOCOL_TCP: | 72 case SocketPerformanceWatcherFactory::PROTOCOL_TCP: |
| 72 return NETWORK_QUALITY_OBSERVATION_SOURCE_TCP; | 73 return NETWORK_QUALITY_OBSERVATION_SOURCE_TCP; |
| 73 case SocketPerformanceWatcherFactory::PROTOCOL_QUIC: | 74 case SocketPerformanceWatcherFactory::PROTOCOL_QUIC: |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 bool use_local_host_requests_for_tests, | 241 bool use_local_host_requests_for_tests, |
| 241 bool use_smaller_responses_for_tests, | 242 bool use_smaller_responses_for_tests, |
| 242 bool add_default_platform_observations, | 243 bool add_default_platform_observations, |
| 243 const NetLogWithSource& net_log) | 244 const NetLogWithSource& net_log) |
| 244 : algorithm_name_to_enum_({{"HttpRTTAndDownstreamThroughput", | 245 : algorithm_name_to_enum_({{"HttpRTTAndDownstreamThroughput", |
| 245 EffectiveConnectionTypeAlgorithm:: | 246 EffectiveConnectionTypeAlgorithm:: |
| 246 HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT}, | 247 HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT}, |
| 247 {"TransportRTTOrDownstreamThroughput", | 248 {"TransportRTTOrDownstreamThroughput", |
| 248 EffectiveConnectionTypeAlgorithm:: | 249 EffectiveConnectionTypeAlgorithm:: |
| 249 TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT}}), | 250 TRANSPORT_RTT_OR_DOWNSTREAM_THROUGHOUT}}), |
| 251 params_(variation_params), |
| 250 use_localhost_requests_(use_local_host_requests_for_tests), | 252 use_localhost_requests_(use_local_host_requests_for_tests), |
| 251 use_small_responses_(use_smaller_responses_for_tests), | 253 use_small_responses_(use_smaller_responses_for_tests), |
| 252 disable_offline_check_(false), | 254 disable_offline_check_(false), |
| 253 add_default_platform_observations_(add_default_platform_observations), | 255 add_default_platform_observations_(add_default_platform_observations), |
| 254 weight_multiplier_per_second_( | 256 weight_multiplier_per_second_(params_.GetWeightMultiplierPerSecond()), |
| 255 nqe::internal::GetWeightMultiplierPerSecond(variation_params)), | 257 weight_multiplier_per_dbm_(params_.GetWeightMultiplierPerDbm()), |
| 256 weight_multiplier_per_dbm_( | |
| 257 nqe::internal::GetWeightMultiplierPerDbm(variation_params)), | |
| 258 effective_connection_type_algorithm_( | 258 effective_connection_type_algorithm_( |
| 259 algorithm_name_to_enum_.find( | 259 algorithm_name_to_enum_.find( |
| 260 nqe::internal::GetEffectiveConnectionTypeAlgorithm( | 260 params_.GetEffectiveConnectionTypeAlgorithm()) == |
| 261 variation_params)) == algorithm_name_to_enum_.end() | 261 algorithm_name_to_enum_.end() |
| 262 ? kDefaultEffectiveConnectionTypeAlgorithm | 262 ? kDefaultEffectiveConnectionTypeAlgorithm |
| 263 : algorithm_name_to_enum_ | 263 : algorithm_name_to_enum_ |
| 264 .find(nqe::internal::GetEffectiveConnectionTypeAlgorithm( | 264 .find(params_.GetEffectiveConnectionTypeAlgorithm()) |
| 265 variation_params)) | |
| 266 ->second), | 265 ->second), |
| 267 tick_clock_(new base::DefaultTickClock()), | 266 tick_clock_(new base::DefaultTickClock()), |
| 268 last_connection_change_(tick_clock_->NowTicks()), | 267 last_connection_change_(tick_clock_->NowTicks()), |
| 269 current_network_id_(nqe::internal::NetworkID( | 268 current_network_id_(nqe::internal::NetworkID( |
| 270 NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, | 269 NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN, |
| 271 std::string())), | 270 std::string())), |
| 272 downstream_throughput_kbps_observations_(weight_multiplier_per_second_, | 271 downstream_throughput_kbps_observations_(weight_multiplier_per_second_, |
| 273 weight_multiplier_per_dbm_), | 272 weight_multiplier_per_dbm_), |
| 274 rtt_observations_(weight_multiplier_per_second_, | 273 rtt_observations_(weight_multiplier_per_second_, |
| 275 weight_multiplier_per_dbm_), | 274 weight_multiplier_per_dbm_), |
| 276 effective_connection_type_at_last_main_frame_( | 275 effective_connection_type_at_last_main_frame_( |
| 277 EFFECTIVE_CONNECTION_TYPE_UNKNOWN), | 276 EFFECTIVE_CONNECTION_TYPE_UNKNOWN), |
| 278 external_estimate_provider_(std::move(external_estimates_provider)), | 277 external_estimate_provider_(std::move(external_estimates_provider)), |
| 279 effective_connection_type_recomputation_interval_( | 278 effective_connection_type_recomputation_interval_( |
| 280 base::TimeDelta::FromSeconds(10)), | 279 base::TimeDelta::FromSeconds(10)), |
| 281 rtt_observations_size_at_last_ect_computation_(0), | 280 rtt_observations_size_at_last_ect_computation_(0), |
| 282 throughput_observations_size_at_last_ect_computation_(0), | 281 throughput_observations_size_at_last_ect_computation_(0), |
| 283 effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN), | 282 effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN), |
| 284 signal_strength_dbm_(INT32_MIN), | 283 signal_strength_dbm_(INT32_MIN), |
| 285 min_signal_strength_since_connection_change_(INT32_MAX), | 284 min_signal_strength_since_connection_change_(INT32_MAX), |
| 286 max_signal_strength_since_connection_change_(INT32_MIN), | 285 max_signal_strength_since_connection_change_(INT32_MIN), |
| 287 correlation_uma_logging_probability_( | 286 correlation_uma_logging_probability_( |
| 288 nqe::internal::correlation_uma_logging_probability(variation_params)), | 287 params_.correlation_uma_logging_probability()), |
| 289 forced_effective_connection_type_set_( | 288 forced_effective_connection_type_set_( |
| 290 nqe::internal::forced_effective_connection_type_set( | 289 params_.forced_effective_connection_type_set()), |
| 291 variation_params)), | |
| 292 forced_effective_connection_type_( | 290 forced_effective_connection_type_( |
| 293 nqe::internal::forced_effective_connection_type(variation_params)), | 291 params_.forced_effective_connection_type()), |
| 294 persistent_cache_reading_enabled_( | 292 persistent_cache_reading_enabled_( |
| 295 nqe::internal::persistent_cache_reading_enabled(variation_params)), | 293 params_.persistent_cache_reading_enabled()), |
| 296 event_creator_(net_log), | 294 event_creator_(net_log), |
| 297 disallowed_observation_sources_for_http_( | 295 disallowed_observation_sources_for_http_( |
| 298 {NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, | 296 {NETWORK_QUALITY_OBSERVATION_SOURCE_TCP, |
| 299 NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC, | 297 NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC, |
| 300 NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, | 298 NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE, |
| 301 NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM}), | 299 NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM}), |
| 302 disallowed_observation_sources_for_transport_( | 300 disallowed_observation_sources_for_transport_( |
| 303 {NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, | 301 {NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP, |
| 304 NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_EXTERNAL_ESTIMATE, | 302 NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_EXTERNAL_ESTIMATE, |
| 305 NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE, | 303 NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE, |
| 306 NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM}), | 304 NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM}), |
| 307 weak_ptr_factory_(this) { | 305 weak_ptr_factory_(this) { |
| 308 // None of the algorithms can have an empty name. | 306 // None of the algorithms can have an empty name. |
| 309 DCHECK(algorithm_name_to_enum_.end() == | 307 DCHECK(algorithm_name_to_enum_.end() == |
| 310 algorithm_name_to_enum_.find(std::string())); | 308 algorithm_name_to_enum_.find(std::string())); |
| 311 | 309 |
| 312 DCHECK_EQ(algorithm_name_to_enum_.size(), | 310 DCHECK_EQ(algorithm_name_to_enum_.size(), |
| 313 static_cast<size_t>(EffectiveConnectionTypeAlgorithm:: | 311 static_cast<size_t>(EffectiveConnectionTypeAlgorithm:: |
| 314 EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST)); | 312 EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST)); |
| 315 DCHECK_NE(EffectiveConnectionTypeAlgorithm:: | 313 DCHECK_NE(EffectiveConnectionTypeAlgorithm:: |
| 316 EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST, | 314 EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST, |
| 317 effective_connection_type_algorithm_); | 315 effective_connection_type_algorithm_); |
| 318 | 316 |
| 319 network_quality_store_.reset(new nqe::internal::NetworkQualityStore()); | 317 network_quality_store_.reset(new nqe::internal::NetworkQualityStore()); |
| 320 ObtainOperatingParams(variation_params); | 318 ObtainOperatingParams(); |
| 321 NetworkChangeNotifier::AddConnectionTypeObserver(this); | 319 NetworkChangeNotifier::AddConnectionTypeObserver(this); |
| 322 if (external_estimate_provider_) { | 320 if (external_estimate_provider_) { |
| 323 RecordExternalEstimateProviderMetrics( | 321 RecordExternalEstimateProviderMetrics( |
| 324 EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE); | 322 EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE); |
| 325 external_estimate_provider_->SetUpdatedEstimateDelegate(this); | 323 external_estimate_provider_->SetUpdatedEstimateDelegate(this); |
| 326 } else { | 324 } else { |
| 327 RecordExternalEstimateProviderMetrics( | 325 RecordExternalEstimateProviderMetrics( |
| 328 EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE); | 326 EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE); |
| 329 } | 327 } |
| 330 current_network_id_ = GetCurrentNetworkID(); | 328 current_network_id_ = GetCurrentNetworkID(); |
| 331 AddDefaultEstimates(); | 329 AddDefaultEstimates(); |
| 332 | 330 |
| 333 throughput_analyzer_.reset(new nqe::internal::ThroughputAnalyzer( | 331 throughput_analyzer_.reset(new nqe::internal::ThroughputAnalyzer( |
| 334 base::ThreadTaskRunnerHandle::Get(), | 332 base::ThreadTaskRunnerHandle::Get(), |
| 335 base::Bind(&NetworkQualityEstimator::OnNewThroughputObservationAvailable, | 333 base::Bind(&NetworkQualityEstimator::OnNewThroughputObservationAvailable, |
| 336 base::Unretained(this)), | 334 base::Unretained(this)), |
| 337 use_localhost_requests_, use_smaller_responses_for_tests)); | 335 use_localhost_requests_, use_smaller_responses_for_tests)); |
| 338 | 336 |
| 339 watcher_factory_.reset(new nqe::internal::SocketWatcherFactory( | 337 watcher_factory_.reset(new nqe::internal::SocketWatcherFactory( |
| 340 base::ThreadTaskRunnerHandle::Get(), | 338 base::ThreadTaskRunnerHandle::Get(), |
| 341 nqe::internal::GetMinSocketWatcherNotificationInterval(variation_params), | 339 params_.GetMinSocketWatcherNotificationInterval(), |
| 342 base::Bind(&NetworkQualityEstimator::OnUpdatedRTTAvailable, | 340 base::Bind(&NetworkQualityEstimator::OnUpdatedRTTAvailable, |
| 343 base::Unretained(this)), | 341 base::Unretained(this)), |
| 344 tick_clock_.get())); | 342 tick_clock_.get())); |
| 345 | 343 |
| 346 // Record accuracy after a 15 second interval. The values used here must | 344 // Record accuracy after a 15 second interval. The values used here must |
| 347 // remain in sync with the suffixes specified in | 345 // remain in sync with the suffixes specified in |
| 348 // tools/metrics/histograms/histograms.xml. | 346 // tools/metrics/histograms/histograms.xml. |
| 349 accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(15)); | 347 accuracy_recording_intervals_.push_back(base::TimeDelta::FromSeconds(15)); |
| 350 | 348 |
| 351 for (int i = 0; i < STATISTIC_LAST; ++i) | 349 for (int i = 0; i < STATISTIC_LAST; ++i) |
| 352 http_rtt_at_last_main_frame_[i] = nqe::internal::InvalidRTT(); | 350 http_rtt_at_last_main_frame_[i] = nqe::internal::InvalidRTT(); |
| 353 } | 351 } |
| 354 | 352 |
| 355 void NetworkQualityEstimator::ObtainOperatingParams( | 353 void NetworkQualityEstimator::ObtainOperatingParams() { |
| 356 const std::map<std::string, std::string>& variation_params) { | |
| 357 DCHECK(thread_checker_.CalledOnValidThread()); | 354 DCHECK(thread_checker_.CalledOnValidThread()); |
| 358 nqe::internal::ObtainDefaultObservations(variation_params, | 355 params_.ObtainDefaultObservations(default_observations_); |
| 359 default_observations_); | 356 params_.ObtainEffectiveConnectionTypeModelParams(connection_thresholds_); |
| 360 nqe::internal::ObtainEffectiveConnectionTypeModelParams( | 357 params_.ObtainTypicalNetworkQuality(typical_network_quality_); |
| 361 variation_params, connection_thresholds_); | |
| 362 nqe::internal::ObtainTypicalNetworkQuality(typical_network_quality_); | |
| 363 } | 358 } |
| 364 | 359 |
| 365 void NetworkQualityEstimator::AddDefaultEstimates() { | 360 void NetworkQualityEstimator::AddDefaultEstimates() { |
| 366 DCHECK(thread_checker_.CalledOnValidThread()); | 361 DCHECK(thread_checker_.CalledOnValidThread()); |
| 367 | 362 |
| 368 if (!add_default_platform_observations_) | 363 if (!add_default_platform_observations_) |
| 369 return; | 364 return; |
| 370 | 365 |
| 371 if (default_observations_[current_network_id_.type].http_rtt() != | 366 if (default_observations_[current_network_id_.type].http_rtt() != |
| 372 nqe::internal::InvalidRTT()) { | 367 nqe::internal::InvalidRTT()) { |
| (...skipping 673 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1046 "NQE.EstimateAvailable.MainFrame.Kbps", | 1041 "NQE.EstimateAvailable.MainFrame.Kbps", |
| 1047 estimated_quality_at_last_main_frame_.downstream_throughput_kbps() != | 1042 estimated_quality_at_last_main_frame_.downstream_throughput_kbps() != |
| 1048 nqe::internal::kInvalidThroughput); | 1043 nqe::internal::kInvalidThroughput); |
| 1049 | 1044 |
| 1050 UMA_HISTOGRAM_ENUMERATION("NQE.MainFrame.EffectiveConnectionType", | 1045 UMA_HISTOGRAM_ENUMERATION("NQE.MainFrame.EffectiveConnectionType", |
| 1051 effective_connection_type_at_last_main_frame_, | 1046 effective_connection_type_at_last_main_frame_, |
| 1052 EFFECTIVE_CONNECTION_TYPE_LAST); | 1047 EFFECTIVE_CONNECTION_TYPE_LAST); |
| 1053 base::HistogramBase* effective_connection_type_histogram = | 1048 base::HistogramBase* effective_connection_type_histogram = |
| 1054 base::Histogram::FactoryGet( | 1049 base::Histogram::FactoryGet( |
| 1055 std::string("NQE.MainFrame.EffectiveConnectionType.") + | 1050 std::string("NQE.MainFrame.EffectiveConnectionType.") + |
| 1056 nqe::internal::GetNameForConnectionType(current_network_id_.type), | 1051 nqe::internal::NetworkQualityEstimatorParams:: |
| 1052 GetNameForConnectionType(current_network_id_.type), |
| 1057 0, EFFECTIVE_CONNECTION_TYPE_LAST, | 1053 0, EFFECTIVE_CONNECTION_TYPE_LAST, |
| 1058 EFFECTIVE_CONNECTION_TYPE_LAST /* Number of buckets */, | 1054 EFFECTIVE_CONNECTION_TYPE_LAST /* Number of buckets */, |
| 1059 base::HistogramBase::kUmaTargetedHistogramFlag); | 1055 base::HistogramBase::kUmaTargetedHistogramFlag); |
| 1060 | 1056 |
| 1061 effective_connection_type_histogram->Add( | 1057 effective_connection_type_histogram->Add( |
| 1062 effective_connection_type_at_last_main_frame_); | 1058 effective_connection_type_at_last_main_frame_); |
| 1063 | 1059 |
| 1064 // Record the HTTP RTT at the main frames for experimental statistics. | 1060 // Record the HTTP RTT at the main frames for experimental statistics. |
| 1065 for (int i = 0; i < STATISTIC_LAST; ++i) { | 1061 for (int i = 0; i < STATISTIC_LAST; ++i) { |
| 1066 if (http_rtt_at_last_main_frame_[i] != nqe::internal::InvalidRTT()) { | 1062 if (http_rtt_at_last_main_frame_[i] != nqe::internal::InvalidRTT()) { |
| (...skipping 777 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1844 return base::Optional<base::TimeDelta>(); | 1840 return base::Optional<base::TimeDelta>(); |
| 1845 } | 1841 } |
| 1846 | 1842 |
| 1847 base::Optional<int32_t> | 1843 base::Optional<int32_t> |
| 1848 NetworkQualityEstimator::NetworkQualityProvider::GetDownstreamThroughputKbps() | 1844 NetworkQualityEstimator::NetworkQualityProvider::GetDownstreamThroughputKbps() |
| 1849 const { | 1845 const { |
| 1850 return base::Optional<int32_t>(); | 1846 return base::Optional<int32_t>(); |
| 1851 } | 1847 } |
| 1852 | 1848 |
| 1853 } // namespace net | 1849 } // namespace net |
| OLD | NEW |