text: // 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.
  
  #ifndef NET_NQE_NETWORK_QUALITY_ESTIMATOR_H_
  #define NET_NQE_NETWORK_QUALITY_ESTIMATOR_H_
  
  #include <stdint.h>
  
  #include <map>
  #include <memory>
  #include <string>
  #include <tuple>
  
  #include "base/compiler_specific.h"
  #include "base/gtest_prod_util.h"
  #include "base/macros.h"
  #include "base/memory/ref_counted.h"
  #include "base/memory/weak_ptr.h"
  #include "base/observer_list.h"
  #include "base/threading/thread_checker.h"
  #include "base/time/time.h"
  #include "net/base/net_export.h"
  #include "net/base/network_change_notifier.h"
  #include "net/nqe/cached_network_quality.h"
  #include "net/nqe/external_estimate_provider.h"
  #include "net/nqe/network_quality.h"
  #include "net/nqe/network_quality_observation.h"
  #include "net/nqe/network_quality_observation_source.h"
  #include "net/nqe/observation_buffer.h"
  #include "net/socket/socket_performance_watcher_factory.h"
  
  namespace base {
  class TickClock;
  }  // namespace base
  
  namespace net {
  
  namespace nqe {
  namespace internal {
  class ThroughputAnalyzer;
  }
  }
  
  class URLRequest;
  
  // NetworkQualityEstimator provides network quality estimates (quality of the
  // full paths to all origins that have been connected to).
  // The estimates are based on the observed organic traffic.
  // A NetworkQualityEstimator instance is attached to URLRequestContexts and
  // observes the traffic of URLRequests spawned from the URLRequestContexts.
  // A single instance of NQE can be attached to multiple URLRequestContexts,
  // thereby increasing the single NQE instance's accuracy by providing more
  // observed traffic characteristics.
  class NET_EXPORT_PRIVATE NetworkQualityEstimator
      : public NetworkChangeNotifier::ConnectionTypeObserver,
        public ExternalEstimateProvider::UpdatedEstimateDelegate {
   public:
    // EffectiveConnectionType is the connection type whose typical performance is
    // most similar to the measured performance of the network in use. In many
    // cases, the "effective" connection type and the actual type of connection in
    // use are the same, but often a network connection performs significantly
    // different, usually worse, from its expected capabilities.
    // EffectiveConnectionType of a network is independent of if the current
    // connection is metered or not. For example, an unmetered slow connection may
    // have EFFECTIVE_CONNECTION_TYPE_SLOW_2G as its effective connection type.
    enum EffectiveConnectionType {
      // The connection types should be in increasing order of quality.
      EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0,
      EFFECTIVE_CONNECTION_TYPE_OFFLINE,
      EFFECTIVE_CONNECTION_TYPE_SLOW_2G,
      EFFECTIVE_CONNECTION_TYPE_2G,
      EFFECTIVE_CONNECTION_TYPE_3G,
      EFFECTIVE_CONNECTION_TYPE_4G,
      EFFECTIVE_CONNECTION_TYPE_BROADBAND,
      EFFECTIVE_CONNECTION_TYPE_LAST,
    };
  
    // Observes changes in effective connection type.
    class NET_EXPORT_PRIVATE EffectiveConnectionTypeObserver {
     public:
      // Notifies the observer of a change in the effective connection type.
      // NetworkQualityEstimator computes the effective connection type once in
      // every interval of duration
      // |effective_connection_type_recomputation_interval_|. Additionally, when
      // there is a change in the connection type of the device, then the
      // effective connection type is immediately recomputed. The observer must
      // register and unregister itself on the IO thread. All the observers would
      // be notified on the IO thread.
      //
      // If the computed effective connection type is different from the
      // previously notified effective connection type, then all the registered
      // observers are notified of the new effective connection type.
      virtual void OnEffectiveConnectionTypeChanged(
          EffectiveConnectionType type) = 0;
  
     protected:
      EffectiveConnectionTypeObserver() {}
      virtual ~EffectiveConnectionTypeObserver() {}
  
     private:
      DISALLOW_COPY_AND_ASSIGN(EffectiveConnectionTypeObserver);
    };
  
    // Observes measurements of round trip time.
    class NET_EXPORT_PRIVATE RTTObserver {
     public:
      // Will be called when a new RTT observation is available. The round trip
      // time is specified in milliseconds. The time when the observation was
      // taken and the source of the observation are provided.
      virtual void OnRTTObservation(int32_t rtt_ms,
                                    const base::TimeTicks& timestamp,
                                    NetworkQualityObservationSource source) = 0;
  
     protected:
      RTTObserver() {}
      virtual ~RTTObserver() {}
  
     private:
      DISALLOW_COPY_AND_ASSIGN(RTTObserver);
    };
  
    // Observes measurements of throughput.
    class NET_EXPORT_PRIVATE ThroughputObserver {
     public:
      // Will be called when a new throughput observation is available.
      // Throughput is specified in kilobits per second.
      virtual void OnThroughputObservation(
          int32_t throughput_kbps,
          const base::TimeTicks& timestamp,
          NetworkQualityObservationSource source) = 0;
  
     protected:
      ThroughputObserver() {}
      virtual ~ThroughputObserver() {}
  
     private:
      DISALLOW_COPY_AND_ASSIGN(ThroughputObserver);
    };
  
    // Creates a new NetworkQualityEstimator.
    // |variation_params| is the map containing all field trial parameters
    // related to NetworkQualityEstimator field trial.
    // |external_estimates_provider| may be NULL.
    NetworkQualityEstimator(
        std::unique_ptr<ExternalEstimateProvider> external_estimates_provider,
        const std::map<std::string, std::string>& variation_params);
  
    // Construct a NetworkQualityEstimator instance allowing for test
    // configuration. Registers for network type change notifications so estimates
    // can be kept network specific.
    // |external_estimates_provider| may be NULL.
    // |variation_params| is the map containing all field trial parameters for the
    // network quality estimator field trial.
    // |use_local_host_requests_for_tests| should only be true when testing
    // against local HTTP server and allows the requests to local host to be
    // used for network quality estimation.
    // |use_smaller_responses_for_tests| should only be true when testing.
    // Allows the responses smaller than |kMinTransferSizeInBits| to be used for
    // network quality estimation.
    NetworkQualityEstimator(
        std::unique_ptr<ExternalEstimateProvider> external_estimates_provider,
        const std::map<std::string, std::string>& variation_params,
        bool use_local_host_requests_for_tests,
        bool use_smaller_responses_for_tests);
  
    ~NetworkQualityEstimator() override;
  
    // Returns the effective type of the current connection. Virtualized for
    // testing.
    virtual EffectiveConnectionType GetEffectiveConnectionType() const;
  
    // Returns the effective type of the current connection based on only the
    // samples observed after |start_time|. This should only be used for
    // recording the metrics. Virtualized for testing.
    virtual EffectiveConnectionType GetRecentEffectiveConnectionType(
        const base::TimeTicks& start_time) const;
  
    // Adds |observer| to the list of effective connection type observers. Must be
    // called on the IO thread.
    void AddEffectiveConnectionTypeObserver(
        EffectiveConnectionTypeObserver* observer);
  
    // Removes |observer| from the list of effective connection type observers.
    // Must be called on the IO thread.
    void RemoveEffectiveConnectionTypeObserver(
        EffectiveConnectionTypeObserver* observer);
  
    // Notifies NetworkQualityEstimator that the response header of |request| has
    // been received.
    void NotifyHeadersReceived(const URLRequest& request);
  
    // Notifies NetworkQualityEstimator that the headers of |request| are about to
    // be sent.
    void NotifyStartTransaction(const URLRequest& request);
  
    // Notifies NetworkQualityEstimator that the response body of |request| has
    // been received.
    void NotifyRequestCompleted(const URLRequest& request);
  
    // Notifies NetworkQualityEstimator that |request| will be destroyed.
    void NotifyURLRequestDestroyed(const URLRequest& request);
  
    // Adds |rtt_observer| to the list of round trip time observers. Must be
    // called on the IO thread.
    void AddRTTObserver(RTTObserver* rtt_observer);
  
    // Removes |rtt_observer| from the list of round trip time observers if it
    // is on the list of observers. Must be called on the IO thread.
    void RemoveRTTObserver(RTTObserver* rtt_observer);
  
    // Adds |throughput_observer| to the list of throughput observers. Must be
    // called on the IO thread.
    void AddThroughputObserver(ThroughputObserver* throughput_observer);
  
    // Removes |throughput_observer| from the list of throughput observers if it
    // is on the list of observers. Must be called on the IO thread.
    void RemoveThroughputObserver(ThroughputObserver* throughput_observer);
  
    SocketPerformanceWatcherFactory* GetSocketPerformanceWatcherFactory();
  
    // Returns a string equivalent to |type|.
    static const char* GetNameForEffectiveConnectionType(
        EffectiveConnectionType type);
  
    // Returns an EffectiveConnectionType equivalent to |connection_type_name|.
    static EffectiveConnectionType GetEffectiveConnectionTypeForName(
        const std::string& connection_type_name);
  
    // |use_localhost_requests| should only be true when testing against local
    // HTTP server and allows the requests to local host to be used for network
    // quality estimation.
    void SetUseLocalHostRequestsForTesting(bool use_localhost_requests);
  
    // |use_smaller_responses_for_tests| should only be true when testing.
    // Allows the responses smaller than |kMinTransferSizeInBits| to be used for
    // network quality estimation.
    void SetUseSmallResponsesForTesting(bool use_small_responses);
  
   protected:
    // NetworkID is used to uniquely identify a network.
    // For the purpose of network quality estimation and caching, a network is
    // uniquely identified by a combination of |type| and
    // |id|. This approach is unable to distinguish networks with
    // same name (e.g., different Wi-Fi networks with same SSID).
    // This is a protected member to expose it to tests.
    struct NET_EXPORT_PRIVATE NetworkID {
      NetworkID(NetworkChangeNotifier::ConnectionType type, const std::string& id)
          : type(type), id(id) {}
      NetworkID(const NetworkID& other) : type(other.type), id(other.id) {}
      ~NetworkID() {}
  
      NetworkID& operator=(const NetworkID& other) {
        type = other.type;
        id = other.id;
        return *this;
      }
  
      // Overloaded because NetworkID is used as key in a map.
      bool operator<(const NetworkID& other) const {
        return std::tie(type, id) < std::tie(other.type, other.id);
      }
  
      // Connection type of the network.
      NetworkChangeNotifier::ConnectionType type;
  
      // Name of this network. This is set to:
      // - Wi-Fi SSID if the device is connected to a Wi-Fi access point and the
      //   SSID name is available, or
      // - MCC/MNC code of the cellular carrier if the device is connected to a
      //   cellular network, or
      // - "Ethernet" in case the device is connected to ethernet.
      // - An empty string in all other cases or if the network name is not
      //   exposed by platform APIs.
      std::string id;
    };
  
    // Returns true if the cached network quality estimate was successfully read.
    bool ReadCachedNetworkQualityEstimate();
  
    // NetworkChangeNotifier::ConnectionTypeObserver implementation:
    void OnConnectionTypeChanged(
        NetworkChangeNotifier::ConnectionType type) override;
  
    // ExternalEstimateProvider::UpdatedEstimateObserver implementation.
    void OnUpdatedEstimateAvailable(const base::TimeDelta& rtt,
                                    int32_t downstream_throughput_kbps,
                                    int32_t upstream_throughput_kbps) override;
  
    // Returns true if the RTT is available and sets |rtt| to the RTT estimated at
    // the HTTP layer. Virtualized for testing. |rtt| should not be null. The RTT
    // at the HTTP layer measures the time from when the request was sent (this
    // happens after the connection is established) to the time when the response
    // headers were received.
    virtual bool GetHttpRTTEstimate(base::TimeDelta* rtt) const
        WARN_UNUSED_RESULT;
  
    // Returns true if the RTT is available and sets |rtt| to the RTT estimated at
    // the transport layer. |rtt| should not be null. Virtualized for testing.
    virtual bool GetTransportRTTEstimate(base::TimeDelta* rtt) const
        WARN_UNUSED_RESULT;
  
    // Returns true if downlink throughput is available and sets |kbps| to
    // estimated downlink throughput (in kilobits per second).
    // Virtualized for testing. |kbps| should not be null.
    virtual bool GetDownlinkThroughputKbpsEstimate(int32_t* kbps) const;
  
    // Returns true if median RTT at the HTTP layer is available and sets |rtt|
    // to the median of RTT observations since |start_time|.
    // Virtualized for testing. |rtt| should not be null. The RTT at the HTTP
    // layer measures the time from when the request was sent (this happens after
    // the connection is established) to the time when the response headers were
    // received.
    virtual bool GetRecentHttpRTTMedian(const base::TimeTicks& start_time,
                                        base::TimeDelta* rtt) const
        WARN_UNUSED_RESULT;
  
    // Returns true if the median RTT at the transport layer is available and sets
    // |rtt| to the median of transport layer RTT observations since
    // |start_time|. |rtt| should not be null. Virtualized for testing.
    virtual bool GetRecentTransportRTTMedian(const base::TimeTicks& start_time,
                                             base::TimeDelta* rtt) const
        WARN_UNUSED_RESULT;
  
    // Returns true if median downstream throughput is available and sets |kbps|
    // to the median of downstream throughput (in kilobits per second)
    // observations since |start_time|. Virtualized for testing. |kbps|
    // should not be null. Virtualized for testing.
    virtual bool GetRecentMedianDownlinkThroughputKbps(
        const base::TimeTicks& start_time,
        int32_t* kbps) const WARN_UNUSED_RESULT;
  
    // Returns the list of intervals at which the accuracy of network quality
    // prediction should be recorded. Virtualized for testing.
    virtual const std::vector<base::TimeDelta>& GetAccuracyRecordingIntervals()
        const;
  
    // Overrides the tick clock used by |this| for testing.
    void SetTickClockForTesting(std::unique_ptr<base::TickClock> tick_clock);
  
   private:
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, StoreObservations);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestAddObservation);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ObtainOperatingParams);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
                             ObtainAlgorithmToUseFromParams);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, HalfLifeParam);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, ComputedPercentiles);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestCaching);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
                             TestLRUCacheMaximumSize);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest, TestGetMetricsSince);
    FRIEND_TEST_ALL_PREFIXES(NetworkQualityEstimatorTest,
                             TestExternalEstimateProviderMergeEstimates);
  
    // Value of round trip time observations is in base::TimeDelta.
    typedef nqe::internal::Observation<base::TimeDelta> RttObservation;
    typedef nqe::internal::ObservationBuffer<base::TimeDelta>
        RttObservationBuffer;
  
    // Value of throughput observations is in kilobits per second.
    typedef nqe::internal::Observation<int32_t> ThroughputObservation;
    typedef nqe::internal::ObservationBuffer<int32_t> ThroughputObservationBuffer;
  
    // This does not use a unordered_map or hash_map for code simplicity (key just
    // implements operator<, rather than hash and equality) and because the map is
    // tiny.
    typedef std::map<NetworkID, nqe::internal::CachedNetworkQuality>
        CachedNetworkQualities;
  
    // Algorithms supported by network quality estimator for computing effective
    // connection type.
    enum class EffectiveConnectionTypeAlgorithm {
      HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT = 0,
      EFFECTIVE_CONNECTION_TYPE_ALGORITHM_LAST
    };
  
    // Map from algorithm names to EffectiveConnectionTypeAlgorithm.
    const std::map<std::string, EffectiveConnectionTypeAlgorithm>
        algorithm_name_to_enum_;
  
    // The default algorithm to be used if the algorithm value is not available
    // through field trial parameters.
    static const EffectiveConnectionTypeAlgorithm
        kDefaultEffectiveConnectionTypeAlgorithm =
            EffectiveConnectionTypeAlgorithm::HTTP_RTT_AND_DOWNSTREAM_THROUGHOUT;
  
    // Minimum valid value of the variation parameter that holds RTT (in
    // milliseconds) values.
    static const int kMinimumRTTVariationParameterMsec = 1;
  
    // Minimum valid value of the variation parameter that holds throughput (in
    // kilobits per second) values.
    static const int kMinimumThroughputVariationParameterKbps = 1;
  
    // Maximum size of the cache that holds network quality estimates.
    // Smaller size may reduce the cache hit rate due to frequent evictions.
    // Larger size may affect performance.
    static const size_t kMaximumNetworkQualityCacheSize = 10;
  
    // Returns the RTT value to be used when the valid RTT is unavailable. Readers
    // should discard RTT if it is set to the value returned by |InvalidRTT()|.
    static const base::TimeDelta InvalidRTT();
  
    // Records UMA when there is a change in connection type.
    void RecordMetricsOnConnectionTypeChanged() const;
  
    // Records UMA on main frame requests.
    void RecordMetricsOnMainFrameRequest() const;
  
    // Records a downstream throughput observation to the observation buffer if
    // a valid observation is available. |downstream_kbps| is the downstream
    // throughput in kilobits per second.
    void OnNewThroughputObservationAvailable(int32_t downstream_kbps);
  
    // Notifies |this| of a new transport layer RTT.
    void OnUpdatedRTTAvailable(SocketPerformanceWatcherFactory::Protocol protocol,
                               const base::TimeDelta& rtt);
  
    // Obtains operating parameters from the field trial parameters.
    void ObtainOperatingParams(
        const std::map<std::string, std::string>& variation_params);
  
    // Obtains the model parameters for different effective connection types from
    // the field trial parameters. For each effective connection type, a model
    // (currently composed of a RTT threshold and a downlink throughput threshold)
    // is provided by the field trial.
    void ObtainEffectiveConnectionTypeModelParams(
        const std::map<std::string, std::string>& variation_params);
  
    // Adds the default median RTT and downstream throughput estimate for the
    // current connection type to the observation buffer.
    void AddDefaultEstimates();
  
    // Returns an estimate of network quality at the specified |percentile|.
    // |disallowed_observation_sources| is the list of observation sources that
    // should be excluded when computing the percentile.
    // Only the observations later than |start_time| are taken into account.
    // |percentile| must be between 0 and 100 (both inclusive) with higher
    // percentiles indicating less performant networks. For example, if
    // |percentile| is 90, then the network is expected to be faster than the
    // returned estimate with 0.9 probability. Similarly, network is expected to
    // be slower than the returned estimate with 0.1 probability.
    base::TimeDelta GetRTTEstimateInternal(
        const std::vector<NetworkQualityObservationSource>&
            disallowed_observation_sources,
        const base::TimeTicks& start_time,
        int percentile) const;
    int32_t GetDownlinkThroughputKbpsEstimateInternal(
        const base::TimeTicks& start_time,
        int percentile) const;
  
    // Returns the current network ID checking by calling the platform APIs.
    // Virtualized for testing.
    virtual NetworkID GetCurrentNetworkID() const;
  
    // Writes the estimated quality of the current network to the cache.
    void CacheNetworkQualityEstimate();
  
    void NotifyObserversOfRTT(const RttObservation& observation);
  
    void NotifyObserversOfThroughput(const ThroughputObservation& observation);
  
    // Returns true only if the |request| can be used for RTT estimation.
    bool RequestProvidesRTTObservation(const URLRequest& request) const;
  
    // Recomputes effective connection type, if it was computed more than the
    // specified duration ago, or if there has been a connection change recently.
    void MaybeRecomputeEffectiveConnectionType();
  
    // Notify observers of a change in effective connection type.
    void NotifyObserversOfEffectiveConnectionTypeChanged();
  
    // Records NQE accuracy metrics. |measuring_duration| should belong to the
    // vector returned by AccuracyRecordingIntervals().
    // RecordAccuracyAfterMainFrame should be called |measuring_duration| after a
    // main frame request is observed.
    void RecordAccuracyAfterMainFrame(base::TimeDelta measuring_duration) const;
  
    // Returns the effective type of the current connection based on only the
    // samples observed after |start_time|. Uses HTTP RTT and downstream
    // throughput to compute the effective connection type, and requires both of
    // them to have a valid value.
    EffectiveConnectionType
    GetRecentEffectiveConnectionTypeHttpRTTAndDownstreamThroughput(
        const base::TimeTicks& start_time) const;
  
    // Values of external estimate provider status. This enum must remain
    // synchronized with the enum of the same name in
    // metrics/histograms/histograms.xml.
    enum NQEExternalEstimateProviderStatus {
      EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE,
      EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE,
      EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED,
      EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL,
      EXTERNAL_ESTIMATE_PROVIDER_STATUS_CALLBACK,
      EXTERNAL_ESTIMATE_PROVIDER_STATUS_RTT_AVAILABLE,
      EXTERNAL_ESTIMATE_PROVIDER_STATUS_DOWNLINK_BANDWIDTH_AVAILABLE,
      EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY
    };
  
    // Records the metrics related to external estimate provider.
    void RecordExternalEstimateProviderMetrics(
        NQEExternalEstimateProviderStatus status) const;
  
    // Determines if the requests to local host can be used in estimating the
    // network quality. Set to true only for tests.
    bool use_localhost_requests_;
  
    // Determines if the responses smaller than |kMinTransferSizeInBytes|
    // or shorter than |kMinTransferSizeInBytes| can be used in estimating the
    // network quality. Set to true only for tests.
    bool use_small_responses_;
  
    // The factor by which the weight of an observation reduces every second.
    const double weight_multiplier_per_second_;
  
    // Algorithm to use for computing effective connection type. The value is
    // obtained from field trial parameters. If the value from field trial
    // parameters is unavailable, it is set to
    // kDefaultEffectiveConnectionTypeAlgorithm.
    const EffectiveConnectionTypeAlgorithm effective_connection_type_algorithm_;
  
    // Tick clock used by the network quality estimator.
    std::unique_ptr<base::TickClock> tick_clock_;
  
    // Minimum duration between two consecutive computations of effective
    // connection type. Set to non-zero value as a performance optimization.
    const base::TimeDelta effective_connection_type_recomputation_interval_;
  
    // Time when the effective connection type was last computed.
    base::TimeTicks last_effective_connection_type_computation_;
  
    // Intervals after the main frame request arrives at which accuracy of network
    // quality prediction is recorded.
    std::vector<base::TimeDelta> accuracy_recording_intervals_;
  
    // Time when last connection change was observed.
    base::TimeTicks last_connection_change_;
  
    // ID of the current network.
    NetworkID current_network_id_;
  
    // Peak network quality (fastest round-trip-time (RTT) and highest
    // downstream throughput) measured since last connectivity change. RTT is
    // measured from time the request is sent until the first byte received.
    // The accuracy is decreased by ignoring these factors:
    // 1) Multiple URLRequests can occur concurrently.
    // 2) Includes server processing time.
    nqe::internal::NetworkQuality peak_network_quality_;
  
    // Cache that stores quality of previously seen networks.
    CachedNetworkQualities cached_network_qualities_;
  
    // Buffer that holds throughput observations (in kilobits per second) sorted
    // by timestamp.
    ThroughputObservationBuffer downstream_throughput_kbps_observations_;
  
    // Buffer that holds RTT observations sorted by timestamp.
    RttObservationBuffer rtt_observations_;
  
    // Default network quality observations obtained from the network quality
    // estimator field trial parameters. The observations are indexed by
    // ConnectionType.
    nqe::internal::NetworkQuality
        default_observations_[NetworkChangeNotifier::CONNECTION_LAST + 1];
  
    // Thresholds for different effective connection types obtained from field
    // trial variation params. These thresholds encode how different connection
    // types behave in general. In future, complex encodings (e.g., curve
    // fitting) may be used.
    nqe::internal::NetworkQuality
        connection_thresholds_[EFFECTIVE_CONNECTION_TYPE_LAST];
  
    // Latest time when the headers for a main frame request were received.
    base::TimeTicks last_main_frame_request_;
  
    // Estimated network quality when the response headers for the last mainframe
    // request were received.
    nqe::internal::NetworkQuality estimated_quality_at_last_main_frame_;
    EffectiveConnectionType effective_connection_type_at_last_main_frame_;
  
    // ExternalEstimateProvider that provides network quality using operating
    // system APIs. May be NULL.
    const std::unique_ptr<ExternalEstimateProvider> external_estimate_provider_;
  
    // Observer list for changes in effective connection type.
    base::ObserverList<EffectiveConnectionTypeObserver>
        effective_connection_type_observer_list_;
  
    // Observer lists for round trip times and throughput measurements.
    base::ObserverList<RTTObserver> rtt_observer_list_;
    base::ObserverList<ThroughputObserver> throughput_observer_list_;
  
    std::unique_ptr<SocketPerformanceWatcherFactory> watcher_factory_;
  
    // Takes throughput measurements, and passes them back to |this| through the
    // provided callback. |this| stores the throughput observations in
    // |downstream_throughput_kbps_observations_|, which are later used for
    // estimating the throughput.
    std::unique_ptr<nqe::internal::ThroughputAnalyzer> throughput_analyzer_;
  
    // Current effective connection type. It is updated on connection change
    // events. It is also updated every time there is network traffic (provided
    // the last computation was more than
    // |effective_connection_type_recomputation_interval_| ago).
    EffectiveConnectionType effective_connection_type_;
  
    base::ThreadChecker thread_checker_;
  
    base::WeakPtrFactory<NetworkQualityEstimator> weak_ptr_factory_;
  
    DISALLOW_COPY_AND_ASSIGN(NetworkQualityEstimator);
  };
  
  }  // namespace net
  
  #endif  // NET_NQE_NETWORK_QUALITY_ESTIMATOR_H_
  