Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1593)

Unified Diff: net/base/network_quality_estimator.cc

Issue 1898603002: Move Network Quality Estimator files to //net/nqe (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased, removed //net/socket/OWNERS Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/base/network_quality_estimator.h ('k') | net/base/network_quality_estimator_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « net/base/network_quality_estimator.h ('k') | net/base/network_quality_estimator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698