| Index: net/base/network_quality_estimator.cc
|
| diff --git a/net/base/network_quality_estimator.cc b/net/base/network_quality_estimator.cc
|
| deleted file mode 100644
|
| index a9ad1b91699c14769fe630419e746a42f89da024..0000000000000000000000000000000000000000
|
| --- a/net/base/network_quality_estimator.cc
|
| +++ /dev/null
|
| @@ -1,1163 +0,0 @@
|
| -// Copyright 2015 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "net/base/network_quality_estimator.h"
|
| -
|
| -#include <float.h>
|
| -#include <algorithm>
|
| -#include <cmath>
|
| -#include <limits>
|
| -#include <utility>
|
| -#include <vector>
|
| -
|
| -#include "base/logging.h"
|
| -#include "base/metrics/histogram.h"
|
| -#include "base/metrics/histogram_base.h"
|
| -#include "base/strings/string_number_conversions.h"
|
| -#include "base/thread_task_runner_handle.h"
|
| -#include "base/trace_event/trace_event.h"
|
| -#include "build/build_config.h"
|
| -#include "net/base/load_flags.h"
|
| -#include "net/base/load_timing_info.h"
|
| -#include "net/base/network_interfaces.h"
|
| -#include "net/base/socket_performance_watcher.h"
|
| -#include "net/base/url_util.h"
|
| -#include "net/url_request/url_request.h"
|
| -#include "url/gurl.h"
|
| -
|
| -#if defined(OS_ANDROID)
|
| -#include "net/android/network_library.h"
|
| -#endif // OS_ANDROID
|
| -
|
| -namespace {
|
| -
|
| -// Default value of the half life (in seconds) for computing time weighted
|
| -// percentiles. Every half life, the weight of all observations reduces by
|
| -// half. Lowering the half life would reduce the weight of older values faster.
|
| -const int kDefaultHalfLifeSeconds = 60;
|
| -
|
| -// Name of the variation parameter that holds the value of the half life (in
|
| -// seconds) of the observations.
|
| -const char kHalfLifeSecondsParamName[] = "HalfLifeSeconds";
|
| -
|
| -// Returns a descriptive name corresponding to |connection_type|.
|
| -const char* GetNameForConnectionType(
|
| - net::NetworkChangeNotifier::ConnectionType connection_type) {
|
| - switch (connection_type) {
|
| - case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
|
| - return "Unknown";
|
| - case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
|
| - return "Ethernet";
|
| - case net::NetworkChangeNotifier::CONNECTION_WIFI:
|
| - return "WiFi";
|
| - case net::NetworkChangeNotifier::CONNECTION_2G:
|
| - return "2G";
|
| - case net::NetworkChangeNotifier::CONNECTION_3G:
|
| - return "3G";
|
| - case net::NetworkChangeNotifier::CONNECTION_4G:
|
| - return "4G";
|
| - case net::NetworkChangeNotifier::CONNECTION_NONE:
|
| - return "None";
|
| - case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
|
| - return "Bluetooth";
|
| - default:
|
| - NOTREACHED();
|
| - break;
|
| - }
|
| - return "";
|
| -}
|
| -
|
| -// Suffix of the name of the variation parameter that contains the default RTT
|
| -// observation (in milliseconds). Complete name of the variation parameter
|
| -// would be |ConnectionType|.|kDefaultRTTMsecObservationSuffix| where
|
| -// |ConnectionType| is from |kConnectionTypeNames|. For example, variation
|
| -// parameter for Wi-Fi would be "WiFi.DefaultMedianRTTMsec".
|
| -const char kDefaultRTTMsecObservationSuffix[] = ".DefaultMedianRTTMsec";
|
| -
|
| -// Suffix of the name of the variation parameter that contains the default
|
| -// downstream throughput observation (in Kbps). Complete name of the variation
|
| -// parameter would be |ConnectionType|.|kDefaultKbpsObservationSuffix| where
|
| -// |ConnectionType| is from |kConnectionTypeNames|. For example, variation
|
| -// parameter for Wi-Fi would be "WiFi.DefaultMedianKbps".
|
| -const char kDefaultKbpsObservationSuffix[] = ".DefaultMedianKbps";
|
| -
|
| -// Suffix of the name of the variation parameter that contains the threshold
|
| -// RTTs (in milliseconds) for different effective connection types. Complete
|
| -// name of the variation parameter would be
|
| -// |EffectiveConnectionType|.|kThresholdURLRTTMsecSuffix|.
|
| -const char kThresholdURLRTTMsecSuffix[] = ".ThresholdMedianURLRTTMsec";
|
| -
|
| -// Suffix of the name of the variation parameter that contains the threshold
|
| -// downlink throughput (in kbps) for different effective connection types.
|
| -// Complete name of the variation parameter would be
|
| -// |EffectiveConnectionType|.|kThresholdKbpsSuffix|.
|
| -const char kThresholdKbpsSuffix[] = ".ThresholdMedianKbps";
|
| -
|
| -// Computes and returns the weight multiplier per second.
|
| -// |variation_params| is the map containing all field trial parameters
|
| -// related to NetworkQualityEstimator field trial.
|
| -double GetWeightMultiplierPerSecond(
|
| - const std::map<std::string, std::string>& variation_params) {
|
| - int half_life_seconds = kDefaultHalfLifeSeconds;
|
| - int32_t variations_value = 0;
|
| - auto it = variation_params.find(kHalfLifeSecondsParamName);
|
| - if (it != variation_params.end() &&
|
| - base::StringToInt(it->second, &variations_value) &&
|
| - variations_value >= 1) {
|
| - half_life_seconds = variations_value;
|
| - }
|
| - DCHECK_GT(half_life_seconds, 0);
|
| - return exp(log(0.5) / half_life_seconds);
|
| -}
|
| -
|
| -// Returns the histogram that should be used to record the given statistic.
|
| -// |max_limit| is the maximum value that can be stored in the histogram.
|
| -base::HistogramBase* GetHistogram(
|
| - const std::string& statistic_name,
|
| - net::NetworkChangeNotifier::ConnectionType type,
|
| - int32_t max_limit) {
|
| - const base::LinearHistogram::Sample kLowerLimit = 1;
|
| - DCHECK_GT(max_limit, kLowerLimit);
|
| - const size_t kBucketCount = 50;
|
| -
|
| - // Prefix of network quality estimator histograms.
|
| - const char prefix[] = "NQE.";
|
| - return base::Histogram::FactoryGet(
|
| - prefix + statistic_name + GetNameForConnectionType(type), kLowerLimit,
|
| - max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag);
|
| -}
|
| -
|
| -bool GetValueForVariationParam(
|
| - const std::map<std::string, std::string>& variation_params,
|
| - const std::string& parameter_name,
|
| - int32_t* variations_value) {
|
| - auto it = variation_params.find(parameter_name);
|
| - return it != variation_params.end() &&
|
| - base::StringToInt(it->second, variations_value);
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -namespace net {
|
| -
|
| -// SocketWatcher implements SocketPerformanceWatcher, and notifies
|
| -// NetworkQualityEstimator of various socket performance events. SocketWatcher
|
| -// is not thread-safe.
|
| -class NetworkQualityEstimator::SocketWatcher : public SocketPerformanceWatcher {
|
| - public:
|
| - SocketWatcher(
|
| - SocketPerformanceWatcherFactory::Protocol protocol,
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
| - const base::WeakPtr<NetworkQualityEstimator>& network_quality_estimator)
|
| - : protocol_(protocol),
|
| - task_runner_(std::move(task_runner)),
|
| - network_quality_estimator_(network_quality_estimator) {}
|
| -
|
| - ~SocketWatcher() override {}
|
| -
|
| - // SocketPerformanceWatcher implementation:
|
| - bool ShouldNotifyUpdatedRTT() const override {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - return true;
|
| - }
|
| -
|
| - void OnUpdatedRTTAvailable(const base::TimeDelta& rtt) override {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - task_runner_->PostTask(
|
| - FROM_HERE, base::Bind(&NetworkQualityEstimator::OnUpdatedRTTAvailable,
|
| - network_quality_estimator_, protocol_, rtt));
|
| - }
|
| -
|
| - void OnConnectionChanged() override {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - }
|
| -
|
| - private:
|
| - // Transport layer protocol used by the socket that |this| is watching.
|
| - const SocketPerformanceWatcherFactory::Protocol protocol_;
|
| -
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
| -
|
| - base::WeakPtr<NetworkQualityEstimator> network_quality_estimator_;
|
| -
|
| - base::ThreadChecker thread_checker_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(SocketWatcher);
|
| -};
|
| -
|
| -// SocketWatcherFactory implements SocketPerformanceWatcherFactory, and is
|
| -// owned by NetworkQualityEstimator. SocketWatcherFactory is thread safe.
|
| -class NetworkQualityEstimator::SocketWatcherFactory
|
| - : public SocketPerformanceWatcherFactory {
|
| - public:
|
| - SocketWatcherFactory(
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
| - const base::WeakPtr<NetworkQualityEstimator>& network_quality_estimator)
|
| - : task_runner_(std::move(task_runner)),
|
| - network_quality_estimator_(network_quality_estimator) {}
|
| -
|
| - ~SocketWatcherFactory() override {}
|
| -
|
| - // SocketPerformanceWatcherFactory implementation:
|
| - std::unique_ptr<SocketPerformanceWatcher> CreateSocketPerformanceWatcher(
|
| - const Protocol protocol) override {
|
| - return std::unique_ptr<SocketPerformanceWatcher>(
|
| - new SocketWatcher(protocol, task_runner_, network_quality_estimator_));
|
| - }
|
| -
|
| - private:
|
| - scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
|
| -
|
| - base::WeakPtr<NetworkQualityEstimator> network_quality_estimator_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(SocketWatcherFactory);
|
| -};
|
| -
|
| -const int32_t NetworkQualityEstimator::kInvalidThroughput = 0;
|
| -
|
| -NetworkQualityEstimator::NetworkQualityEstimator(
|
| - std::unique_ptr<ExternalEstimateProvider> external_estimates_provider,
|
| - const std::map<std::string, std::string>& variation_params)
|
| - : NetworkQualityEstimator(std::move(external_estimates_provider),
|
| - variation_params,
|
| - false,
|
| - false) {}
|
| -
|
| -NetworkQualityEstimator::NetworkQualityEstimator(
|
| - std::unique_ptr<ExternalEstimateProvider> external_estimates_provider,
|
| - const std::map<std::string, std::string>& variation_params,
|
| - bool allow_local_host_requests_for_tests,
|
| - bool allow_smaller_responses_for_tests)
|
| - : allow_localhost_requests_(allow_local_host_requests_for_tests),
|
| - allow_small_responses_(allow_smaller_responses_for_tests),
|
| - weight_multiplier_per_second_(
|
| - GetWeightMultiplierPerSecond(variation_params)),
|
| - last_connection_change_(base::TimeTicks::Now()),
|
| - current_network_id_(
|
| - NetworkID(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
|
| - std::string())),
|
| - downstream_throughput_kbps_observations_(weight_multiplier_per_second_),
|
| - rtt_observations_(weight_multiplier_per_second_),
|
| - external_estimate_provider_(std::move(external_estimates_provider)),
|
| - weak_ptr_factory_(this) {
|
| - static_assert(kMinRequestDurationMicroseconds > 0,
|
| - "Minimum request duration must be > 0");
|
| - static_assert(kDefaultHalfLifeSeconds > 0,
|
| - "Default half life duration must be > 0");
|
| - static_assert(kMaximumNetworkQualityCacheSize > 0,
|
| - "Size of the network quality cache must be > 0");
|
| - // This limit should not be increased unless the logic for removing the
|
| - // oldest cache entry is rewritten to use a doubly-linked-list LRU queue.
|
| - static_assert(kMaximumNetworkQualityCacheSize <= 10,
|
| - "Size of the network quality cache must <= 10");
|
| -
|
| - ObtainOperatingParams(variation_params);
|
| - ObtainEffectiveConnectionTypeModelParams(variation_params);
|
| - NetworkChangeNotifier::AddConnectionTypeObserver(this);
|
| - if (external_estimate_provider_) {
|
| - RecordExternalEstimateProviderMetrics(
|
| - EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE);
|
| - external_estimate_provider_->SetUpdatedEstimateDelegate(this);
|
| - QueryExternalEstimateProvider();
|
| - } else {
|
| - RecordExternalEstimateProviderMetrics(
|
| - EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE);
|
| - }
|
| - current_network_id_ = GetCurrentNetworkID();
|
| - AddDefaultEstimates();
|
| -
|
| - watcher_factory_.reset(new SocketWatcherFactory(
|
| - base::ThreadTaskRunnerHandle::Get(), weak_ptr_factory_.GetWeakPtr()));
|
| -}
|
| -
|
| -// static
|
| -const base::TimeDelta NetworkQualityEstimator::InvalidRTT() {
|
| - return base::TimeDelta::Max();
|
| -}
|
| -
|
| -void NetworkQualityEstimator::ObtainOperatingParams(
|
| - const std::map<std::string, std::string>& variation_params) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) {
|
| - NetworkChangeNotifier::ConnectionType type =
|
| - static_cast<NetworkChangeNotifier::ConnectionType>(i);
|
| - DCHECK_EQ(InvalidRTT(), default_observations_[i].rtt());
|
| - DCHECK_EQ(kInvalidThroughput,
|
| - default_observations_[i].downstream_throughput_kbps());
|
| - int32_t variations_value = kMinimumRTTVariationParameterMsec - 1;
|
| - // Name of the parameter that holds the RTT value for this connection type.
|
| - std::string rtt_parameter_name =
|
| - std::string(GetNameForConnectionType(type))
|
| - .append(kDefaultRTTMsecObservationSuffix);
|
| - auto it = variation_params.find(rtt_parameter_name);
|
| - if (it != variation_params.end() &&
|
| - base::StringToInt(it->second, &variations_value) &&
|
| - variations_value >= kMinimumRTTVariationParameterMsec) {
|
| - default_observations_[i] =
|
| - NetworkQuality(base::TimeDelta::FromMilliseconds(variations_value),
|
| - default_observations_[i].downstream_throughput_kbps());
|
| - }
|
| -
|
| - variations_value = kMinimumThroughputVariationParameterKbps - 1;
|
| - // Name of the parameter that holds the Kbps value for this connection
|
| - // type.
|
| - std::string kbps_parameter_name =
|
| - std::string(GetNameForConnectionType(type))
|
| - .append(kDefaultKbpsObservationSuffix);
|
| - it = variation_params.find(kbps_parameter_name);
|
| - if (it != variation_params.end() &&
|
| - base::StringToInt(it->second, &variations_value) &&
|
| - variations_value >= kMinimumThroughputVariationParameterKbps) {
|
| - default_observations_[i] =
|
| - NetworkQuality(default_observations_[i].rtt(), variations_value);
|
| - }
|
| - }
|
| -}
|
| -
|
| -void NetworkQualityEstimator::ObtainEffectiveConnectionTypeModelParams(
|
| - const std::map<std::string, std::string>& variation_params) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
|
| - EffectiveConnectionType effective_connection_type =
|
| - static_cast<EffectiveConnectionType>(i);
|
| - DCHECK_EQ(InvalidRTT(), connection_thresholds_[i].rtt());
|
| - DCHECK_EQ(kInvalidThroughput,
|
| - connection_thresholds_[i].downstream_throughput_kbps());
|
| - if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
|
| - continue;
|
| -
|
| - std::string connection_type_name = std::string(
|
| - GetNameForEffectiveConnectionType(effective_connection_type));
|
| -
|
| - int32_t variations_value = kMinimumRTTVariationParameterMsec - 1;
|
| - if (GetValueForVariationParam(
|
| - variation_params, connection_type_name + kThresholdURLRTTMsecSuffix,
|
| - &variations_value) &&
|
| - variations_value >= kMinimumRTTVariationParameterMsec) {
|
| - base::TimeDelta rtt(base::TimeDelta::FromMilliseconds(variations_value));
|
| - connection_thresholds_[i] = NetworkQuality(
|
| - rtt, connection_thresholds_[i].downstream_throughput_kbps());
|
| -
|
| - // Verify that the RTT values are in decreasing order as the network
|
| - // quality improves.
|
| - DCHECK(i == 0 || connection_thresholds_[i - 1].rtt() == InvalidRTT() ||
|
| - rtt <= connection_thresholds_[i - 1].rtt());
|
| - }
|
| -
|
| - variations_value = kMinimumThroughputVariationParameterKbps - 1;
|
| - if (GetValueForVariationParam(variation_params,
|
| - connection_type_name + kThresholdKbpsSuffix,
|
| - &variations_value) &&
|
| - variations_value >= kMinimumThroughputVariationParameterKbps) {
|
| - int32_t throughput_kbps = variations_value;
|
| - connection_thresholds_[i] =
|
| - NetworkQuality(connection_thresholds_[i].rtt(), throughput_kbps);
|
| -
|
| - // Verify that the throughput values are in increasing order as the
|
| - // network quality improves.
|
| - DCHECK(i == 0 ||
|
| - connection_thresholds_[i - 1].downstream_throughput_kbps() ==
|
| - kMinimumThroughputVariationParameterKbps ||
|
| - throughput_kbps >=
|
| - connection_thresholds_[i - 1].downstream_throughput_kbps());
|
| - }
|
| - }
|
| -}
|
| -
|
| -void NetworkQualityEstimator::AddDefaultEstimates() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (default_observations_[current_network_id_.type].rtt() != InvalidRTT()) {
|
| - RttObservation rtt_observation(
|
| - default_observations_[current_network_id_.type].rtt(),
|
| - base::TimeTicks::Now(), DEFAULT_FROM_PLATFORM);
|
| - rtt_observations_.AddObservation(rtt_observation);
|
| - NotifyObserversOfRTT(rtt_observation);
|
| - }
|
| - if (default_observations_[current_network_id_.type]
|
| - .downstream_throughput_kbps() != kInvalidThroughput) {
|
| - ThroughputObservation throughput_observation(
|
| - default_observations_[current_network_id_.type]
|
| - .downstream_throughput_kbps(),
|
| - base::TimeTicks::Now(), DEFAULT_FROM_PLATFORM);
|
| - downstream_throughput_kbps_observations_.AddObservation(
|
| - throughput_observation);
|
| - NotifyObserversOfThroughput(throughput_observation);
|
| - }
|
| -}
|
| -
|
| -NetworkQualityEstimator::~NetworkQualityEstimator() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
|
| -}
|
| -
|
| -void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) {
|
| - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("net"),
|
| - "NetworkQualityEstimator::NotifyHeadersReceived");
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - if (!RequestProvidesUsefulObservations(request))
|
| - return;
|
| -
|
| - // Update |estimated_median_network_quality_| if this is a main frame request.
|
| - if (request.load_flags() & LOAD_MAIN_FRAME) {
|
| - base::TimeDelta rtt;
|
| - if (!GetURLRequestRTTEstimate(&rtt))
|
| - rtt = InvalidRTT();
|
| -
|
| - int32_t downstream_throughput_kbps;
|
| - if (!GetDownlinkThroughputKbpsEstimate(&downstream_throughput_kbps))
|
| - downstream_throughput_kbps = kInvalidThroughput;
|
| -
|
| - estimated_median_network_quality_ =
|
| - NetworkQuality(rtt, downstream_throughput_kbps);
|
| - }
|
| -
|
| - base::TimeTicks now = base::TimeTicks::Now();
|
| - LoadTimingInfo load_timing_info;
|
| - request.GetLoadTimingInfo(&load_timing_info);
|
| -
|
| - // If the load timing info is unavailable, it probably means that the request
|
| - // did not go over the network.
|
| - if (load_timing_info.send_start.is_null() ||
|
| - load_timing_info.receive_headers_end.is_null()) {
|
| - return;
|
| - }
|
| -
|
| - // Time when the resource was requested.
|
| - base::TimeTicks request_start_time = load_timing_info.send_start;
|
| -
|
| - // Time when the headers were received.
|
| - base::TimeTicks headers_received_time = load_timing_info.receive_headers_end;
|
| -
|
| - // Duration between when the resource was requested and when response
|
| - // headers were received.
|
| - base::TimeDelta observed_rtt = headers_received_time - request_start_time;
|
| - DCHECK_GE(observed_rtt, base::TimeDelta());
|
| - if (observed_rtt < peak_network_quality_.rtt()) {
|
| - peak_network_quality_ = NetworkQuality(
|
| - observed_rtt, peak_network_quality_.downstream_throughput_kbps());
|
| - }
|
| -
|
| - RttObservation rtt_observation(observed_rtt, now, URL_REQUEST);
|
| - rtt_observations_.AddObservation(rtt_observation);
|
| - NotifyObserversOfRTT(rtt_observation);
|
| -
|
| - // Compare the RTT observation with the estimated value and record it.
|
| - if (estimated_median_network_quality_.rtt() != InvalidRTT()) {
|
| - RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(),
|
| - observed_rtt.InMilliseconds());
|
| - }
|
| -}
|
| -
|
| -void NetworkQualityEstimator::NotifyRequestCompleted(
|
| - const URLRequest& request) {
|
| - TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("net"),
|
| - "NetworkQualityEstimator::NotifyRequestCompleted");
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - if (!RequestProvidesUsefulObservations(request))
|
| - return;
|
| -
|
| - base::TimeTicks now = base::TimeTicks::Now();
|
| - LoadTimingInfo load_timing_info;
|
| - request.GetLoadTimingInfo(&load_timing_info);
|
| -
|
| - // If the load timing info is unavailable, it probably means that the request
|
| - // did not go over the network.
|
| - if (load_timing_info.send_start.is_null() ||
|
| - load_timing_info.receive_headers_end.is_null()) {
|
| - return;
|
| - }
|
| -
|
| - // Time since the resource was requested.
|
| - // TODO(tbansal): Change the start time to receive_headers_end, once we use
|
| - // NetworkActivityMonitor.
|
| - base::TimeDelta request_start_to_completed =
|
| - now - load_timing_info.send_start;
|
| - DCHECK_GE(request_start_to_completed, base::TimeDelta());
|
| -
|
| - // Ignore tiny transfers which will not produce accurate rates.
|
| - // Ignore short duration transfers.
|
| - // Skip the checks if |allow_small_responses_| is true.
|
| - if (!allow_small_responses_ &&
|
| - (request.GetTotalReceivedBytes() < kMinTransferSizeInBytes ||
|
| - request_start_to_completed < base::TimeDelta::FromMicroseconds(
|
| - kMinRequestDurationMicroseconds))) {
|
| - return;
|
| - }
|
| -
|
| - double downstream_kbps = request.GetTotalReceivedBytes() * 8.0 / 1000.0 /
|
| - request_start_to_completed.InSecondsF();
|
| - DCHECK_GE(downstream_kbps, 0.0);
|
| -
|
| - // Check overflow errors. This may happen if the downstream_kbps is more than
|
| - // 2 * 10^9 (= 2000 Gbps).
|
| - if (downstream_kbps >= std::numeric_limits<int32_t>::max())
|
| - downstream_kbps = std::numeric_limits<int32_t>::max();
|
| -
|
| - int32_t downstream_kbps_as_integer = static_cast<int32_t>(downstream_kbps);
|
| -
|
| - // Round up |downstream_kbps_as_integer|. If the |downstream_kbps_as_integer|
|
| - // is less than 1, it is set to 1 to differentiate from case when there is no
|
| - // connection.
|
| - if (downstream_kbps - downstream_kbps_as_integer > 0)
|
| - downstream_kbps_as_integer++;
|
| -
|
| - DCHECK_GT(downstream_kbps_as_integer, 0.0);
|
| - if (downstream_kbps_as_integer >
|
| - peak_network_quality_.downstream_throughput_kbps())
|
| - peak_network_quality_ =
|
| - NetworkQuality(peak_network_quality_.rtt(), downstream_kbps_as_integer);
|
| -
|
| - ThroughputObservation throughput_observation(downstream_kbps_as_integer, now,
|
| - URL_REQUEST);
|
| - downstream_throughput_kbps_observations_.AddObservation(
|
| - throughput_observation);
|
| - NotifyObserversOfThroughput(throughput_observation);
|
| -}
|
| -
|
| -void NetworkQualityEstimator::AddRTTObserver(RTTObserver* rtt_observer) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - rtt_observer_list_.AddObserver(rtt_observer);
|
| -}
|
| -
|
| -void NetworkQualityEstimator::RemoveRTTObserver(RTTObserver* rtt_observer) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - rtt_observer_list_.RemoveObserver(rtt_observer);
|
| -}
|
| -
|
| -void NetworkQualityEstimator::AddThroughputObserver(
|
| - ThroughputObserver* throughput_observer) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - throughput_observer_list_.AddObserver(throughput_observer);
|
| -}
|
| -
|
| -void NetworkQualityEstimator::RemoveThroughputObserver(
|
| - ThroughputObserver* throughput_observer) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - throughput_observer_list_.RemoveObserver(throughput_observer);
|
| -}
|
| -
|
| -SocketPerformanceWatcherFactory*
|
| -NetworkQualityEstimator::GetSocketPerformanceWatcherFactory() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - return watcher_factory_.get();
|
| -}
|
| -
|
| -void NetworkQualityEstimator::RecordRTTUMA(int32_t estimated_value_msec,
|
| - int32_t actual_value_msec) const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // Record the difference between the actual and the estimated value.
|
| - if (estimated_value_msec >= actual_value_msec) {
|
| - base::HistogramBase* difference_rtt =
|
| - GetHistogram("DifferenceRTTEstimatedAndActual.",
|
| - current_network_id_.type, 10 * 1000); // 10 seconds
|
| - difference_rtt->Add(estimated_value_msec - actual_value_msec);
|
| - } else {
|
| - base::HistogramBase* difference_rtt =
|
| - GetHistogram("DifferenceRTTActualAndEstimated.",
|
| - current_network_id_.type, 10 * 1000); // 10 seconds
|
| - difference_rtt->Add(actual_value_msec - estimated_value_msec);
|
| - }
|
| -
|
| - // Record all the RTT observations.
|
| - base::HistogramBase* rtt_observations =
|
| - GetHistogram("RTTObservations.", current_network_id_.type,
|
| - 10 * 1000); // 10 seconds upper bound
|
| - rtt_observations->Add(actual_value_msec);
|
| -
|
| - if (actual_value_msec == 0)
|
| - return;
|
| -
|
| - int32_t ratio = (estimated_value_msec * 100) / actual_value_msec;
|
| -
|
| - // Record the accuracy of estimation by recording the ratio of estimated
|
| - // value to the actual value.
|
| - base::HistogramBase* ratio_median_rtt = GetHistogram(
|
| - "RatioEstimatedToActualRTT.", current_network_id_.type, 1000);
|
| - ratio_median_rtt->Add(ratio);
|
| -}
|
| -
|
| -bool NetworkQualityEstimator::RequestProvidesUsefulObservations(
|
| - const URLRequest& request) const {
|
| - return request.url().is_valid() &&
|
| - (allow_localhost_requests_ || !IsLocalhost(request.url().host())) &&
|
| - request.url().SchemeIsHTTPOrHTTPS() &&
|
| - // Verify that response headers are received, so it can be ensured that
|
| - // response is not cached.
|
| - !request.response_info().response_time.is_null() &&
|
| - !request.was_cached() &&
|
| - request.creation_time() >= last_connection_change_;
|
| -}
|
| -
|
| -void NetworkQualityEstimator::RecordExternalEstimateProviderMetrics(
|
| - NQEExternalEstimateProviderStatus status) const {
|
| - UMA_HISTOGRAM_ENUMERATION("NQE.ExternalEstimateProviderStatus", status,
|
| - EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY);
|
| -}
|
| -
|
| -void NetworkQualityEstimator::OnConnectionTypeChanged(
|
| - NetworkChangeNotifier::ConnectionType type) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - if (peak_network_quality_.rtt() != InvalidRTT()) {
|
| - base::HistogramBase* rtt_histogram =
|
| - GetHistogram("FastestRTT.", current_network_id_.type, 10 * 1000);
|
| - rtt_histogram->Add(peak_network_quality_.rtt().InMilliseconds());
|
| - }
|
| -
|
| - if (peak_network_quality_.downstream_throughput_kbps() !=
|
| - kInvalidThroughput) {
|
| - base::HistogramBase* downstream_throughput_histogram =
|
| - GetHistogram("PeakKbps.", current_network_id_.type, 1000 * 1000);
|
| - downstream_throughput_histogram->Add(
|
| - peak_network_quality_.downstream_throughput_kbps());
|
| - }
|
| -
|
| - base::TimeDelta rtt;
|
| - if (GetURLRequestRTTEstimate(&rtt)) {
|
| - // Add the 50th percentile value.
|
| - base::HistogramBase* rtt_percentile =
|
| - GetHistogram("RTT.Percentile50.", current_network_id_.type, 10 * 1000);
|
| - rtt_percentile->Add(rtt.InMilliseconds());
|
| -
|
| - // Add the remaining percentile values.
|
| - static const int kPercentiles[] = {0, 10, 90, 100};
|
| - std::vector<ObservationSource> disallowed_observation_sources;
|
| - disallowed_observation_sources.push_back(TCP);
|
| - disallowed_observation_sources.push_back(QUIC);
|
| - for (size_t i = 0; i < arraysize(kPercentiles); ++i) {
|
| - rtt = GetRTTEstimateInternal(disallowed_observation_sources,
|
| - base::TimeTicks(), kPercentiles[i]);
|
| -
|
| - rtt_percentile = GetHistogram(
|
| - "RTT.Percentile" + base::IntToString(kPercentiles[i]) + ".",
|
| - current_network_id_.type, 10 * 1000); // 10 seconds
|
| - rtt_percentile->Add(rtt.InMilliseconds());
|
| - }
|
| - }
|
| -
|
| - // Write the estimates of the previous network to the cache.
|
| - CacheNetworkQualityEstimate();
|
| -
|
| - // Clear the local state.
|
| - last_connection_change_ = base::TimeTicks::Now();
|
| - peak_network_quality_ = NetworkQuality();
|
| - downstream_throughput_kbps_observations_.Clear();
|
| - rtt_observations_.Clear();
|
| - current_network_id_ = GetCurrentNetworkID();
|
| -
|
| - QueryExternalEstimateProvider();
|
| -
|
| - // Read any cached estimates for the new network. If cached estimates are
|
| - // unavailable, add the default estimates.
|
| - if (!ReadCachedNetworkQualityEstimate())
|
| - AddDefaultEstimates();
|
| - estimated_median_network_quality_ = NetworkQuality();
|
| -}
|
| -
|
| -NetworkQualityEstimator::EffectiveConnectionType
|
| -NetworkQualityEstimator::GetEffectiveConnectionType() const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - base::TimeDelta url_request_rtt = InvalidRTT();
|
| - if (!GetURLRequestRTTEstimate(&url_request_rtt))
|
| - url_request_rtt = InvalidRTT();
|
| -
|
| - int32_t kbps = kInvalidThroughput;
|
| - if (!GetDownlinkThroughputKbpsEstimate(&kbps))
|
| - kbps = kInvalidThroughput;
|
| -
|
| - if (url_request_rtt == InvalidRTT() && kbps == kInvalidThroughput) {
|
| - // Quality of the current network is unknown.
|
| - return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
|
| - }
|
| -
|
| - // Search from the slowest connection type to the fastest to find the
|
| - // EffectiveConnectionType that best matches the current connection's
|
| - // performance. The match is done by comparing RTT and throughput.
|
| - for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
|
| - EffectiveConnectionType type = static_cast<EffectiveConnectionType>(i);
|
| - if (i == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
|
| - continue;
|
| - bool estimated_rtt_is_higher_than_threshold =
|
| - url_request_rtt != InvalidRTT() &&
|
| - connection_thresholds_[i].rtt() != InvalidRTT() &&
|
| - url_request_rtt >= connection_thresholds_[i].rtt();
|
| - bool estimated_throughput_is_lower_than_threshold =
|
| - kbps != kInvalidThroughput &&
|
| - connection_thresholds_[i].downstream_throughput_kbps() !=
|
| - kInvalidThroughput &&
|
| - kbps <= connection_thresholds_[i].downstream_throughput_kbps();
|
| - // Return |type| as the effective connection type if the current network's
|
| - // RTT is worse than the threshold RTT for |type|, or if the current
|
| - // network's throughput is lower than the threshold throughput for |type|.
|
| - if (estimated_rtt_is_higher_than_threshold ||
|
| - estimated_throughput_is_lower_than_threshold) {
|
| - return type;
|
| - }
|
| - }
|
| - // Return the fastest connection type.
|
| - return static_cast<EffectiveConnectionType>(EFFECTIVE_CONNECTION_TYPE_LAST -
|
| - 1);
|
| -}
|
| -
|
| -bool NetworkQualityEstimator::GetURLRequestRTTEstimate(
|
| - base::TimeDelta* rtt) const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - std::vector<ObservationSource> disallowed_observation_sources;
|
| - disallowed_observation_sources.push_back(TCP);
|
| - disallowed_observation_sources.push_back(QUIC);
|
| - *rtt = GetRTTEstimateInternal(disallowed_observation_sources,
|
| - base::TimeTicks(), 50);
|
| - return (*rtt != InvalidRTT());
|
| -}
|
| -
|
| -bool NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(
|
| - int32_t* kbps) const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - *kbps = GetDownlinkThroughputKbpsEstimateInternal(base::TimeTicks(), 50);
|
| - return (*kbps != kInvalidThroughput);
|
| -}
|
| -
|
| -bool NetworkQualityEstimator::GetRecentURLRequestRTTMedian(
|
| - const base::TimeTicks& begin_timestamp,
|
| - base::TimeDelta* rtt) const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - std::vector<ObservationSource> disallowed_observation_sources;
|
| - disallowed_observation_sources.push_back(TCP);
|
| - disallowed_observation_sources.push_back(QUIC);
|
| - *rtt = GetRTTEstimateInternal(disallowed_observation_sources, begin_timestamp,
|
| - 50);
|
| - return (*rtt != InvalidRTT());
|
| -}
|
| -
|
| -bool NetworkQualityEstimator::GetRecentMedianDownlinkThroughputKbps(
|
| - const base::TimeTicks& begin_timestamp,
|
| - int32_t* kbps) const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - *kbps = GetDownlinkThroughputKbpsEstimateInternal(begin_timestamp, 50);
|
| - return (*kbps != kInvalidThroughput);
|
| -}
|
| -
|
| -template <typename ValueType>
|
| -NetworkQualityEstimator::ObservationBuffer<ValueType>::ObservationBuffer(
|
| - double weight_multiplier_per_second)
|
| - : weight_multiplier_per_second_(weight_multiplier_per_second) {
|
| - static_assert(kMaximumObservationsBufferSize > 0U,
|
| - "Minimum size of observation buffer must be > 0");
|
| - DCHECK_GE(weight_multiplier_per_second_, 0.0);
|
| - DCHECK_LE(weight_multiplier_per_second_, 1.0);
|
| -}
|
| -
|
| -template <typename ValueType>
|
| -NetworkQualityEstimator::ObservationBuffer<ValueType>::~ObservationBuffer() {}
|
| -
|
| -base::TimeDelta NetworkQualityEstimator::GetRTTEstimateInternal(
|
| - const std::vector<ObservationSource>& disallowed_observation_sources,
|
| - const base::TimeTicks& begin_timestamp,
|
| - int percentile) const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // RTT observations are sorted by duration from shortest to longest, thus
|
| - // a higher percentile RTT will have a longer RTT than a lower percentile.
|
| - base::TimeDelta rtt = InvalidRTT();
|
| - if (!rtt_observations_.GetPercentile(begin_timestamp, &rtt, percentile,
|
| - disallowed_observation_sources)) {
|
| - return InvalidRTT();
|
| - }
|
| - return rtt;
|
| -}
|
| -
|
| -int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal(
|
| - const base::TimeTicks& begin_timestamp,
|
| - int percentile) const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // Throughput observations are sorted by kbps from slowest to fastest,
|
| - // thus a higher percentile throughput will be faster than a lower one.
|
| - int32_t kbps = kInvalidThroughput;
|
| - if (!downstream_throughput_kbps_observations_.GetPercentile(
|
| - begin_timestamp, &kbps, 100 - percentile,
|
| - std::vector<ObservationSource>())) {
|
| - return kInvalidThroughput;
|
| - }
|
| - return kbps;
|
| -}
|
| -
|
| -template <typename ValueType>
|
| -void NetworkQualityEstimator::ObservationBuffer<ValueType>::
|
| - ComputeWeightedObservations(
|
| - const base::TimeTicks& begin_timestamp,
|
| - std::vector<WeightedObservation<ValueType>>& weighted_observations,
|
| - double* total_weight,
|
| - const std::vector<ObservationSource>& disallowed_observation_sources)
|
| - const {
|
| - weighted_observations.clear();
|
| - double total_weight_observations = 0.0;
|
| - base::TimeTicks now = base::TimeTicks::Now();
|
| -
|
| - for (const auto& observation : observations_) {
|
| - if (observation.timestamp < begin_timestamp)
|
| - continue;
|
| - bool disallowed = false;
|
| - for (const auto& disallowed_source : disallowed_observation_sources) {
|
| - if (disallowed_source == observation.source)
|
| - disallowed = true;
|
| - }
|
| - if (disallowed)
|
| - continue;
|
| - base::TimeDelta time_since_sample_taken = now - observation.timestamp;
|
| - double weight =
|
| - pow(weight_multiplier_per_second_, time_since_sample_taken.InSeconds());
|
| - weight = std::max(DBL_MIN, std::min(1.0, weight));
|
| -
|
| - weighted_observations.push_back(
|
| - WeightedObservation<ValueType>(observation.value, weight));
|
| - total_weight_observations += weight;
|
| - }
|
| -
|
| - // Sort the samples by value in ascending order.
|
| - std::sort(weighted_observations.begin(), weighted_observations.end());
|
| - *total_weight = total_weight_observations;
|
| -}
|
| -
|
| -template <typename ValueType>
|
| -bool NetworkQualityEstimator::ObservationBuffer<ValueType>::GetPercentile(
|
| - const base::TimeTicks& begin_timestamp,
|
| - ValueType* result,
|
| - int percentile,
|
| - const std::vector<ObservationSource>& disallowed_observation_sources)
|
| - const {
|
| - DCHECK(result);
|
| - DCHECK_GE(percentile, 0);
|
| - DCHECK_LE(percentile, 100);
|
| -
|
| - // Stores WeightedObservation in increasing order of value.
|
| - std::vector<WeightedObservation<ValueType>> weighted_observations;
|
| -
|
| - // Total weight of all observations in |weighted_observations|.
|
| - double total_weight = 0.0;
|
| -
|
| - ComputeWeightedObservations(begin_timestamp, weighted_observations,
|
| - &total_weight, disallowed_observation_sources);
|
| - if (weighted_observations.empty())
|
| - return false;
|
| -
|
| - DCHECK(!weighted_observations.empty());
|
| - DCHECK_GT(total_weight, 0.0);
|
| -
|
| - // weighted_observations may have a smaller size than observations_ since the
|
| - // former contains only the observations later than begin_timestamp.
|
| - DCHECK_GE(observations_.size(), weighted_observations.size());
|
| -
|
| - double desired_weight = percentile / 100.0 * total_weight;
|
| -
|
| - double cumulative_weight_seen_so_far = 0.0;
|
| - for (const auto& weighted_observation : weighted_observations) {
|
| - cumulative_weight_seen_so_far += weighted_observation.weight;
|
| -
|
| - if (cumulative_weight_seen_so_far >= desired_weight) {
|
| - *result = weighted_observation.value;
|
| - return true;
|
| - }
|
| - }
|
| -
|
| - // Computation may reach here due to floating point errors. This may happen
|
| - // if |percentile| was 100 (or close to 100), and |desired_weight| was
|
| - // slightly larger than |total_weight| (due to floating point errors).
|
| - // In this case, we return the highest |value| among all observations.
|
| - // This is same as value of the last observation in the sorted vector.
|
| - *result = weighted_observations.at(weighted_observations.size() - 1).value;
|
| - return true;
|
| -}
|
| -
|
| -NetworkQualityEstimator::NetworkID
|
| -NetworkQualityEstimator::GetCurrentNetworkID() const {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class
|
| - // that overrides this method on the Android platform.
|
| -
|
| - // It is possible that the connection type changed between when
|
| - // GetConnectionType() was called and when the API to determine the
|
| - // network name was called. Check if that happened and retry until the
|
| - // connection type stabilizes. This is an imperfect solution but should
|
| - // capture majority of cases, and should not significantly affect estimates
|
| - // (that are approximate to begin with).
|
| - while (true) {
|
| - NetworkQualityEstimator::NetworkID network_id(
|
| - NetworkChangeNotifier::GetConnectionType(), std::string());
|
| -
|
| - switch (network_id.type) {
|
| - case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
|
| - case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
|
| - case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
|
| - case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
|
| - break;
|
| - case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
|
| -#if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
|
| - defined(OS_WIN)
|
| - network_id.id = GetWifiSSID();
|
| -#endif
|
| - break;
|
| - case NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
|
| - case NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
|
| - case NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
|
| -#if defined(OS_ANDROID)
|
| - network_id.id = android::GetTelephonyNetworkOperator();
|
| -#endif
|
| - break;
|
| - default:
|
| - NOTREACHED() << "Unexpected connection type = " << network_id.type;
|
| - break;
|
| - }
|
| -
|
| - if (network_id.type == NetworkChangeNotifier::GetConnectionType())
|
| - return network_id;
|
| - }
|
| - NOTREACHED();
|
| -}
|
| -
|
| -bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - // If the network name is unavailable, caching should not be performed.
|
| - if (current_network_id_.id.empty())
|
| - return false;
|
| -
|
| - CachedNetworkQualities::const_iterator it =
|
| - cached_network_qualities_.find(current_network_id_);
|
| -
|
| - if (it == cached_network_qualities_.end())
|
| - return false;
|
| -
|
| - NetworkQuality network_quality(it->second.network_quality());
|
| -
|
| - DCHECK_NE(InvalidRTT(), network_quality.rtt());
|
| - DCHECK_NE(kInvalidThroughput, network_quality.downstream_throughput_kbps());
|
| -
|
| - ThroughputObservation througphput_observation(
|
| - network_quality.downstream_throughput_kbps(), base::TimeTicks::Now(),
|
| - CACHED_ESTIMATE);
|
| - downstream_throughput_kbps_observations_.AddObservation(
|
| - througphput_observation);
|
| - NotifyObserversOfThroughput(througphput_observation);
|
| -
|
| - RttObservation rtt_observation(network_quality.rtt(), base::TimeTicks::Now(),
|
| - CACHED_ESTIMATE);
|
| - rtt_observations_.AddObservation(rtt_observation);
|
| - NotifyObserversOfRTT(rtt_observation);
|
| -
|
| - return true;
|
| -}
|
| -
|
| -void NetworkQualityEstimator::OnUpdatedEstimateAvailable() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK(external_estimate_provider_);
|
| -
|
| - RecordExternalEstimateProviderMetrics(
|
| - EXTERNAL_ESTIMATE_PROVIDER_STATUS_CALLBACK);
|
| - QueryExternalEstimateProvider();
|
| -}
|
| -
|
| -const char* NetworkQualityEstimator::GetNameForEffectiveConnectionType(
|
| - EffectiveConnectionType type) const {
|
| - switch (type) {
|
| - case EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
|
| - return "Unknown";
|
| - case EFFECTIVE_CONNECTION_TYPE_OFFLINE:
|
| - return "Offline";
|
| - case EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
|
| - return "Slow2G";
|
| - case EFFECTIVE_CONNECTION_TYPE_2G:
|
| - return "2G";
|
| - case EFFECTIVE_CONNECTION_TYPE_3G:
|
| - return "3G";
|
| - case EFFECTIVE_CONNECTION_TYPE_4G:
|
| - return "4G";
|
| - case EFFECTIVE_CONNECTION_TYPE_BROADBAND:
|
| - return "Broadband";
|
| - default:
|
| - NOTREACHED();
|
| - break;
|
| - }
|
| - return "";
|
| -}
|
| -
|
| -void NetworkQualityEstimator::QueryExternalEstimateProvider() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - if (!external_estimate_provider_)
|
| - return;
|
| - RecordExternalEstimateProviderMetrics(
|
| - EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED);
|
| -
|
| - base::TimeDelta time_since_last_update;
|
| -
|
| - // Request a new estimate if estimate is not available, or if the available
|
| - // estimate is not fresh.
|
| - if (!external_estimate_provider_->GetTimeSinceLastUpdate(
|
| - &time_since_last_update) ||
|
| - time_since_last_update >
|
| - base::TimeDelta::FromMilliseconds(
|
| - kExternalEstimateProviderFreshnessDurationMsec)) {
|
| - // Request the external estimate provider for updated estimates. When the
|
| - // updates estimates are available, OnUpdatedEstimateAvailable() will be
|
| - // called.
|
| - external_estimate_provider_->Update();
|
| - return;
|
| - }
|
| -
|
| - RecordExternalEstimateProviderMetrics(
|
| - EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL);
|
| - base::TimeDelta rtt;
|
| - if (external_estimate_provider_->GetRTT(&rtt)) {
|
| - RecordExternalEstimateProviderMetrics(
|
| - EXTERNAL_ESTIMATE_PROVIDER_STATUS_RTT_AVAILABLE);
|
| - UMA_HISTOGRAM_TIMES("NQE.ExternalEstimateProvider.RTT", rtt);
|
| - rtt_observations_.AddObservation(
|
| - RttObservation(rtt, base::TimeTicks::Now(), EXTERNAL_ESTIMATE));
|
| - }
|
| -
|
| - int32_t downstream_throughput_kbps;
|
| - if (external_estimate_provider_->GetDownstreamThroughputKbps(
|
| - &downstream_throughput_kbps)) {
|
| - RecordExternalEstimateProviderMetrics(
|
| - EXTERNAL_ESTIMATE_PROVIDER_STATUS_DOWNLINK_BANDWIDTH_AVAILABLE);
|
| - UMA_HISTOGRAM_COUNTS("NQE.ExternalEstimateProvider.DownlinkBandwidth",
|
| - downstream_throughput_kbps);
|
| - downstream_throughput_kbps_observations_.AddObservation(
|
| - ThroughputObservation(downstream_throughput_kbps,
|
| - base::TimeTicks::Now(), EXTERNAL_ESTIMATE));
|
| - }
|
| -}
|
| -
|
| -void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| - DCHECK_LE(cached_network_qualities_.size(),
|
| - static_cast<size_t>(kMaximumNetworkQualityCacheSize));
|
| -
|
| - // If the network name is unavailable, caching should not be performed.
|
| - if (current_network_id_.id.empty())
|
| - return;
|
| -
|
| - base::TimeDelta rtt = InvalidRTT();
|
| - int32_t downlink_throughput_kbps = kInvalidThroughput;
|
| -
|
| - if (!GetURLRequestRTTEstimate(&rtt) ||
|
| - !GetDownlinkThroughputKbpsEstimate(&downlink_throughput_kbps)) {
|
| - return;
|
| - }
|
| -
|
| - NetworkQuality network_quality =
|
| - NetworkQuality(rtt, downlink_throughput_kbps);
|
| -
|
| - if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) {
|
| - // Remove the oldest entry.
|
| - CachedNetworkQualities::iterator oldest_entry_iterator =
|
| - cached_network_qualities_.begin();
|
| -
|
| - for (CachedNetworkQualities::iterator it =
|
| - cached_network_qualities_.begin();
|
| - it != cached_network_qualities_.end(); ++it) {
|
| - if ((it->second).OlderThan(oldest_entry_iterator->second))
|
| - oldest_entry_iterator = it;
|
| - }
|
| - cached_network_qualities_.erase(oldest_entry_iterator);
|
| - }
|
| - DCHECK_LT(cached_network_qualities_.size(),
|
| - static_cast<size_t>(kMaximumNetworkQualityCacheSize));
|
| -
|
| - cached_network_qualities_.insert(std::make_pair(
|
| - current_network_id_, CachedNetworkQuality(network_quality)));
|
| - DCHECK_LE(cached_network_qualities_.size(),
|
| - static_cast<size_t>(kMaximumNetworkQualityCacheSize));
|
| -}
|
| -
|
| -void NetworkQualityEstimator::OnUpdatedRTTAvailable(
|
| - SocketPerformanceWatcherFactory::Protocol protocol,
|
| - const base::TimeDelta& rtt) {
|
| - DCHECK(thread_checker_.CalledOnValidThread());
|
| -
|
| - switch (protocol) {
|
| - case SocketPerformanceWatcherFactory::PROTOCOL_TCP:
|
| - NotifyObserversOfRTT(RttObservation(rtt, base::TimeTicks::Now(), TCP));
|
| - return;
|
| - case SocketPerformanceWatcherFactory::PROTOCOL_QUIC:
|
| - NotifyObserversOfRTT(RttObservation(rtt, base::TimeTicks::Now(), QUIC));
|
| - return;
|
| - default:
|
| - NOTREACHED();
|
| - }
|
| -}
|
| -
|
| -void NetworkQualityEstimator::NotifyObserversOfRTT(
|
| - const RttObservation& observation) {
|
| - FOR_EACH_OBSERVER(
|
| - RTTObserver, rtt_observer_list_,
|
| - OnRTTObservation(observation.value.InMilliseconds(),
|
| - observation.timestamp, observation.source));
|
| -}
|
| -
|
| -void NetworkQualityEstimator::NotifyObserversOfThroughput(
|
| - const ThroughputObservation& observation) {
|
| - FOR_EACH_OBSERVER(
|
| - ThroughputObserver, throughput_observer_list_,
|
| - OnThroughputObservation(observation.value, observation.timestamp,
|
| - observation.source));
|
| -}
|
| -
|
| -NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
|
| - const NetworkQuality& network_quality)
|
| - : last_update_time_(base::TimeTicks::Now()),
|
| - network_quality_(network_quality) {
|
| -}
|
| -
|
| -NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
|
| - const CachedNetworkQuality& other)
|
| - : last_update_time_(other.last_update_time_),
|
| - network_quality_(other.network_quality_) {
|
| -}
|
| -
|
| -NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() {
|
| -}
|
| -
|
| -bool NetworkQualityEstimator::CachedNetworkQuality::OlderThan(
|
| - const CachedNetworkQuality& cached_network_quality) const {
|
| - return last_update_time_ < cached_network_quality.last_update_time_;
|
| -}
|
| -
|
| -NetworkQualityEstimator::NetworkQuality::NetworkQuality()
|
| - : NetworkQuality(NetworkQualityEstimator::InvalidRTT(),
|
| - NetworkQualityEstimator::kInvalidThroughput) {}
|
| -
|
| -NetworkQualityEstimator::NetworkQuality::NetworkQuality(
|
| - const base::TimeDelta& rtt,
|
| - int32_t downstream_throughput_kbps)
|
| - : rtt_(rtt), downstream_throughput_kbps_(downstream_throughput_kbps) {
|
| - DCHECK_GE(rtt_, base::TimeDelta());
|
| - DCHECK_GE(downstream_throughput_kbps_, 0);
|
| -}
|
| -
|
| -NetworkQualityEstimator::NetworkQuality::NetworkQuality(
|
| - const NetworkQuality& other)
|
| - : NetworkQuality(other.rtt_, other.downstream_throughput_kbps_) {}
|
| -
|
| -NetworkQualityEstimator::NetworkQuality::~NetworkQuality() {}
|
| -
|
| -NetworkQualityEstimator::NetworkQuality&
|
| - NetworkQualityEstimator::NetworkQuality::
|
| - operator=(const NetworkQuality& other) {
|
| - rtt_ = other.rtt_;
|
| - downstream_throughput_kbps_ = other.downstream_throughput_kbps_;
|
| - return *this;
|
| -}
|
| -
|
| -} // namespace net
|
|
|