• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/nqe/network_quality_estimator.h"
11 
12 #include <algorithm>
13 #include <cmath>
14 #include <limits>
15 #include <memory>
16 #include <utility>
17 
18 #include "base/check_op.h"
19 #include "base/functional/bind.h"
20 #include "base/functional/callback_helpers.h"
21 #include "base/location.h"
22 #include "base/metrics/field_trial_params.h"
23 #include "base/metrics/histogram.h"
24 #include "base/metrics/histogram_base.h"
25 #include "base/metrics/histogram_functions.h"
26 #include "base/metrics/histogram_macros.h"
27 #include "base/metrics/histogram_macros_local.h"
28 #include "base/notreached.h"
29 #include "base/observer_list.h"
30 #include "base/strings/string_number_conversions.h"
31 #include "base/task/lazy_thread_pool_task_runner.h"
32 #include "base/task/single_thread_task_runner.h"
33 #include "base/time/default_tick_clock.h"
34 #include "build/build_config.h"
35 #include "build/chromeos_buildflags.h"
36 #include "net/base/features.h"
37 #include "net/base/host_port_pair.h"
38 #include "net/base/load_flags.h"
39 #include "net/base/load_timing_info.h"
40 #include "net/base/network_interfaces.h"
41 #include "net/base/trace_constants.h"
42 #include "net/base/tracing.h"
43 #include "net/http/http_response_headers.h"
44 #include "net/http/http_response_info.h"
45 #include "net/http/http_status_code.h"
46 #include "net/nqe/network_quality_estimator_util.h"
47 #include "net/nqe/throughput_analyzer.h"
48 #include "net/nqe/weighted_observation.h"
49 #include "net/url_request/url_request.h"
50 #include "net/url_request/url_request_context.h"
51 #include "url/gurl.h"
52 
53 namespace net {
54 
55 namespace {
56 
57 #if BUILDFLAG(IS_CHROMEOS_ASH)
58 // SequencedTaskRunner to get the network id. A SequencedTaskRunner is used
59 // rather than parallel tasks to avoid having many threads getting the network
60 // id concurrently.
61 base::LazyThreadPoolSequencedTaskRunner g_get_network_id_task_runner =
62     LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
63         base::TaskTraits(base::MayBlock(),
64                          base::TaskPriority::BEST_EFFORT,
65                          base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
66 #endif
67 
ProtocolSourceToObservationSource(SocketPerformanceWatcherFactory::Protocol protocol)68 NetworkQualityObservationSource ProtocolSourceToObservationSource(
69     SocketPerformanceWatcherFactory::Protocol protocol) {
70   switch (protocol) {
71     case SocketPerformanceWatcherFactory::PROTOCOL_TCP:
72       return NETWORK_QUALITY_OBSERVATION_SOURCE_TCP;
73     case SocketPerformanceWatcherFactory::PROTOCOL_QUIC:
74       return NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC;
75   }
76   NOTREACHED();
77 }
78 
79 // Returns true if the scheme of the |request| is either HTTP or HTTPS.
RequestSchemeIsHTTPOrHTTPS(const URLRequest & request)80 bool RequestSchemeIsHTTPOrHTTPS(const URLRequest& request) {
81   return request.url().is_valid() && request.url().SchemeIsHTTPOrHTTPS();
82 }
83 
DoGetCurrentNetworkID(NetworkQualityEstimatorParams * params)84 nqe::internal::NetworkID DoGetCurrentNetworkID(
85     NetworkQualityEstimatorParams* params) {
86   nqe::internal::NetworkID network_id(
87       NetworkChangeNotifier::GetConnectionType(), std::string(), INT32_MIN);
88 
89   return network_id;
90 }
91 
CategoryToString(nqe::internal::ObservationCategory category)92 const char* CategoryToString(nqe::internal::ObservationCategory category) {
93   switch (category) {
94     case nqe::internal::OBSERVATION_CATEGORY_HTTP:
95       return "HTTP";
96     case nqe::internal::OBSERVATION_CATEGORY_TRANSPORT:
97       return "Transport";
98     case nqe::internal::OBSERVATION_CATEGORY_END_TO_END:
99       return "EndToEnd";
100     case nqe::internal::OBSERVATION_CATEGORY_COUNT:
101       NOTREACHED();
102   }
103 }
104 
GetStartTimeFromThreshold(int threshold)105 base::TimeTicks GetStartTimeFromThreshold(int threshold) {
106   if (threshold < 0) {
107     return base::TimeTicks();
108   }
109   return base::TimeTicks::Now() - base::Seconds(threshold);
110 }
111 
GetHTTPStartTime()112 base::TimeTicks GetHTTPStartTime() {
113   static const int threshold = features::kRecentHTTPThresholdInSeconds.Get();
114   return GetStartTimeFromThreshold(threshold);
115 }
116 
GetTransportStartTime()117 base::TimeTicks GetTransportStartTime() {
118   static const int threshold =
119       features::kRecentTransportThresholdInSeconds.Get();
120   return GetStartTimeFromThreshold(threshold);
121 }
122 
GetEndToEndStartTime()123 base::TimeTicks GetEndToEndStartTime() {
124   static const int threshold =
125       features::kRecentEndToEndThresholdInSeconds.Get();
126   return GetStartTimeFromThreshold(threshold);
127 }
128 
RecordFallbackSuccess(std::string_view category,bool fallback_success)129 void RecordFallbackSuccess(std::string_view category, bool fallback_success) {
130   base::UmaHistogramBoolean(
131       base::StrCat({"NQE.RTT.HittingThreshold.", category, ".FallbackSuccess"}),
132       fallback_success);
133 }
134 
135 }  // namespace
136 
NetworkQualityEstimator(std::unique_ptr<NetworkQualityEstimatorParams> params,NetLog * net_log)137 NetworkQualityEstimator::NetworkQualityEstimator(
138     std::unique_ptr<NetworkQualityEstimatorParams> params,
139     NetLog* net_log)
140     : params_(std::move(params)),
141       tick_clock_(base::DefaultTickClock::GetInstance()),
142       last_connection_change_(tick_clock_->NowTicks()),
143       current_network_id_(nqe::internal::NetworkID(
144           NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
145           std::string(),
146           INT32_MIN)),
147       http_downstream_throughput_kbps_observations_(
148           params_.get(),
149           tick_clock_,
150           params_->weight_multiplier_per_second(),
151           1.0 /*params_->weight_multiplier_per_signal_strength_level()*/),
152       rtt_ms_observations_{
153           ObservationBuffer(
154               params_.get(),
155               tick_clock_,
156               params_->weight_multiplier_per_second(),
157               1.0 /*params_->weight_multiplier_per_signal_strength_level()*/),
158           ObservationBuffer(
159               params_.get(),
160               tick_clock_,
161               params_->weight_multiplier_per_second(),
162               1.0 /*params_->weight_multiplier_per_signal_strength_level()*/),
163           ObservationBuffer(
164               params_.get(),
165               tick_clock_,
166               params_->weight_multiplier_per_second(),
167               1.0 /*params_->weight_multiplier_per_signal_strength_level()*/)},
168       effective_connection_type_recomputation_interval_(
169           features::kEffectiveConnectionTypeRecomputationInterval.Get()),
170       net_log_(NetLogWithSource::Make(
171           net_log,
172           net::NetLogSourceType::NETWORK_QUALITY_ESTIMATOR)),
173       event_creator_(net_log_) {
174   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
175             std::size(rtt_ms_observations_));
176 
177   network_quality_store_ =
178       std::make_unique<nqe::internal::NetworkQualityStore>();
179   NetworkChangeNotifier::AddConnectionTypeObserver(this);
180   throughput_analyzer_ = std::make_unique<nqe::internal::ThroughputAnalyzer>(
181       this, params_.get(), base::SingleThreadTaskRunner::GetCurrentDefault(),
182       base::BindRepeating(
183           &NetworkQualityEstimator::OnNewThroughputObservationAvailable,
184           weak_ptr_factory_.GetWeakPtr()),
185       tick_clock_, net_log_);
186 
187   watcher_factory_ = std::make_unique<nqe::internal::SocketWatcherFactory>(
188       base::SingleThreadTaskRunner::GetCurrentDefault(),
189       params_->min_socket_watcher_notification_interval(),
190       // OnUpdatedTransportRTTAvailable() may be called via PostTask() by
191       // socket watchers that live on a different thread than the current thread
192       // (i.e., base::SingleThreadTaskRunner::GetCurrentDefault()).
193       // Use WeakPtr() to avoid crashes where the socket watcher is destroyed
194       // after |this| is destroyed.
195       base::BindRepeating(
196           &NetworkQualityEstimator::OnUpdatedTransportRTTAvailable,
197           weak_ptr_factory_.GetWeakPtr()),
198       // ShouldSocketWatcherNotifyRTT() below is called by only the socket
199       // watchers that live on the same thread as the current thread
200       // (i.e., base::SingleThreadTaskRunner::GetCurrentDefault()). Also,
201       // network quality estimator is destroyed after network contexts and
202       // URLRequestContexts. It's safe to use base::Unretained() below since the
203       // socket watcher (owned by sockets) would be destroyed before |this|.
204       base::BindRepeating(
205           &NetworkQualityEstimator::ShouldSocketWatcherNotifyRTT,
206           base::Unretained(this)),
207       tick_clock_);
208 
209   GatherEstimatesForNextConnectionType();
210 }
211 
AddDefaultEstimates()212 void NetworkQualityEstimator::AddDefaultEstimates() {
213   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
214 
215   if (!params_->add_default_platform_observations())
216     return;
217 
218   if (params_->DefaultObservation(current_network_id_.type).http_rtt() !=
219       nqe::internal::InvalidRTT()) {
220     Observation rtt_observation(
221         params_->DefaultObservation(current_network_id_.type)
222             .http_rtt()
223             .InMilliseconds(),
224         tick_clock_->NowTicks(), INT32_MIN,
225         NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM);
226     AddAndNotifyObserversOfRTT(rtt_observation);
227   }
228 
229   if (params_->DefaultObservation(current_network_id_.type).transport_rtt() !=
230       nqe::internal::InvalidRTT()) {
231     Observation rtt_observation(
232         params_->DefaultObservation(current_network_id_.type)
233             .transport_rtt()
234             .InMilliseconds(),
235         tick_clock_->NowTicks(), INT32_MIN,
236         NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM);
237     AddAndNotifyObserversOfRTT(rtt_observation);
238   }
239 
240   if (params_->DefaultObservation(current_network_id_.type)
241           .downstream_throughput_kbps() !=
242       nqe::internal::INVALID_RTT_THROUGHPUT) {
243     Observation throughput_observation(
244         params_->DefaultObservation(current_network_id_.type)
245             .downstream_throughput_kbps(),
246         tick_clock_->NowTicks(), INT32_MIN,
247         NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM);
248     AddAndNotifyObserversOfThroughput(throughput_observation);
249   }
250 }
251 
~NetworkQualityEstimator()252 NetworkQualityEstimator::~NetworkQualityEstimator() {
253   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
254   NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
255 }
256 
NotifyStartTransaction(const URLRequest & request)257 void NetworkQualityEstimator::NotifyStartTransaction(
258     const URLRequest& request) {
259   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
260 
261   if (!RequestSchemeIsHTTPOrHTTPS(request))
262     return;
263 
264   // TODO(tbansal): Refactor this to a separate method.
265   if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) {
266     ComputeEffectiveConnectionType();
267   } else {
268     MaybeComputeEffectiveConnectionType();
269   }
270   throughput_analyzer_->NotifyStartTransaction(request);
271 }
272 
IsHangingRequest(base::TimeDelta observed_http_rtt) const273 bool NetworkQualityEstimator::IsHangingRequest(
274     base::TimeDelta observed_http_rtt) const {
275   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
276 
277   // If there are sufficient number of end to end RTT samples available, use
278   // the end to end RTT estimate to determine if the request is hanging.
279   // If |observed_http_rtt| is within a fixed multiplier of |end_to_end_rtt_|,
280   // then |observed_http_rtt| is determined to be not a hanging-request RTT.
281   if (params_->use_end_to_end_rtt() && end_to_end_rtt_.has_value() &&
282       end_to_end_rtt_observation_count_at_last_ect_computation_ >=
283           params_->http_rtt_transport_rtt_min_count() &&
284       params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() >
285           0 &&
286       observed_http_rtt <
287           params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() *
288               end_to_end_rtt_.value()) {
289     return false;
290   }
291 
292   DCHECK_LT(
293       0,
294       params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier());
295 
296   if (transport_rtt_observation_count_last_ect_computation_ >=
297           params_->http_rtt_transport_rtt_min_count() &&
298       (observed_http_rtt <
299        params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() *
300            GetTransportRTT().value_or(base::Seconds(10)))) {
301     // If there are sufficient number of transport RTT samples available, use
302     // the transport RTT estimate to determine if the request is hanging.
303     return false;
304   }
305 
306   DCHECK_LT(
307       0, params_->hanging_request_http_rtt_upper_bound_http_rtt_multiplier());
308 
309   if (observed_http_rtt <
310       params_->hanging_request_http_rtt_upper_bound_http_rtt_multiplier() *
311           GetHttpRTT().value_or(base::Seconds(10))) {
312     // Use the HTTP RTT estimate to determine if the request is hanging.
313     return false;
314   }
315 
316   if (observed_http_rtt <=
317       params_->hanging_request_upper_bound_min_http_rtt()) {
318     return false;
319   }
320   return true;
321 }
322 
NotifyHeadersReceived(const URLRequest & request,int64_t prefilter_total_bytes_read)323 void NetworkQualityEstimator::NotifyHeadersReceived(
324     const URLRequest& request,
325     int64_t prefilter_total_bytes_read) {
326   TRACE_EVENT0(NetTracingCategory(),
327                "NetworkQualityEstimator::NotifyHeadersReceived");
328   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
329 
330   if (!RequestSchemeIsHTTPOrHTTPS(request) ||
331       !RequestProvidesRTTObservation(request)) {
332     return;
333   }
334 
335   if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) {
336     ComputeEffectiveConnectionType();
337   }
338 
339   LoadTimingInfo load_timing_info;
340   request.GetLoadTimingInfo(&load_timing_info);
341 
342   // If the load timing info is unavailable, it probably means that the request
343   // did not go over the network.
344   if (load_timing_info.send_start.is_null() ||
345       load_timing_info.receive_headers_end.is_null()) {
346     return;
347   }
348   DCHECK(!request.response_info().was_cached);
349 
350   // Duration between when the resource was requested and when the response
351   // headers were received.
352   const base::TimeDelta observed_http_rtt =
353       load_timing_info.receive_headers_end - load_timing_info.send_start;
354   if (observed_http_rtt <= base::TimeDelta())
355     return;
356   DCHECK_GE(observed_http_rtt, base::TimeDelta());
357 
358   if (IsHangingRequest(observed_http_rtt))
359     return;
360 
361   // Metrics on estimation errors.
362   const auto& estimated_rtt = GetHttpRTT();
363   if (estimated_rtt) {
364     const base::TimeDelta estimation_error = observed_http_rtt - *estimated_rtt;
365     if (estimation_error.is_zero()) {
366       base::UmaHistogramBoolean("NQE.RTT.Error.IsZero", true);
367       base::UmaHistogramTimes("NQE.RTT.Error.Absolute", estimation_error);
368     } else {
369       base::UmaHistogramBoolean("NQE.RTT.Error.IsZero", false);
370       if (estimation_error.is_positive()) {
371         base::UmaHistogramTimes("NQE.RTT.Error.Positive", estimation_error);
372         base::UmaHistogramTimes("NQE.RTT.Error.Absolute", estimation_error);
373       } else {  // Negative.
374         base::UmaHistogramTimes("NQE.RTT.Error.Negative", -estimation_error);
375         base::UmaHistogramTimes("NQE.RTT.Error.Absolute", -estimation_error);
376       }
377     }
378   }
379 
380   Observation http_rtt_observation(observed_http_rtt.InMilliseconds(),
381                                    tick_clock_->NowTicks(),
382                                    current_network_id_.signal_strength,
383                                    NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP);
384   AddAndNotifyObserversOfRTT(http_rtt_observation);
385   throughput_analyzer_->NotifyBytesRead(request);
386   throughput_analyzer_->NotifyExpectedResponseContentSize(
387       request, request.GetExpectedContentSize());
388 }
389 
NotifyBytesRead(const URLRequest & request,int64_t prefilter_total_bytes_read)390 void NetworkQualityEstimator::NotifyBytesRead(
391     const URLRequest& request,
392     int64_t prefilter_total_bytes_read) {
393   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
394   throughput_analyzer_->NotifyBytesRead(request);
395 }
396 
NotifyRequestCompleted(const URLRequest & request)397 void NetworkQualityEstimator::NotifyRequestCompleted(
398     const URLRequest& request) {
399   TRACE_EVENT0(NetTracingCategory(),
400                "NetworkQualityEstimator::NotifyRequestCompleted");
401   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
402 
403   if (!RequestSchemeIsHTTPOrHTTPS(request))
404     return;
405 
406   throughput_analyzer_->NotifyRequestCompleted(request);
407 }
408 
NotifyURLRequestDestroyed(const URLRequest & request)409 void NetworkQualityEstimator::NotifyURLRequestDestroyed(
410     const URLRequest& request) {
411   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
412 
413   if (!RequestSchemeIsHTTPOrHTTPS(request))
414     return;
415 
416   throughput_analyzer_->NotifyRequestCompleted(request);
417 }
418 
AddRTTObserver(RTTObserver * rtt_observer)419 void NetworkQualityEstimator::AddRTTObserver(RTTObserver* rtt_observer) {
420   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
421   rtt_observer_list_.AddObserver(rtt_observer);
422 }
423 
RemoveRTTObserver(RTTObserver * rtt_observer)424 void NetworkQualityEstimator::RemoveRTTObserver(RTTObserver* rtt_observer) {
425   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
426   rtt_observer_list_.RemoveObserver(rtt_observer);
427 }
428 
AddThroughputObserver(ThroughputObserver * throughput_observer)429 void NetworkQualityEstimator::AddThroughputObserver(
430     ThroughputObserver* throughput_observer) {
431   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
432   throughput_observer_list_.AddObserver(throughput_observer);
433 }
434 
RemoveThroughputObserver(ThroughputObserver * throughput_observer)435 void NetworkQualityEstimator::RemoveThroughputObserver(
436     ThroughputObserver* throughput_observer) {
437   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
438   throughput_observer_list_.RemoveObserver(throughput_observer);
439 }
440 
441 SocketPerformanceWatcherFactory*
GetSocketPerformanceWatcherFactory()442 NetworkQualityEstimator::GetSocketPerformanceWatcherFactory() {
443   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
444 
445   return watcher_factory_.get();
446 }
447 
SetUseLocalHostRequestsForTesting(bool use_localhost_requests)448 void NetworkQualityEstimator::SetUseLocalHostRequestsForTesting(
449     bool use_localhost_requests) {
450   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
451   use_localhost_requests_ = use_localhost_requests;
452   watcher_factory_->SetUseLocalHostRequestsForTesting(use_localhost_requests_);
453   throughput_analyzer_->SetUseLocalHostRequestsForTesting(
454       use_localhost_requests_);
455 }
456 
SetUseSmallResponsesForTesting(bool use_small_responses)457 void NetworkQualityEstimator::SetUseSmallResponsesForTesting(
458     bool use_small_responses) {
459   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
460   params_->SetUseSmallResponsesForTesting(use_small_responses);
461 }
462 
DisableOfflineCheckForTesting(bool disable_offline_check)463 void NetworkQualityEstimator::DisableOfflineCheckForTesting(
464     bool disable_offline_check) {
465   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
466   disable_offline_check_ = disable_offline_check;
467 }
468 
ReportEffectiveConnectionTypeForTesting(EffectiveConnectionType effective_connection_type)469 void NetworkQualityEstimator::ReportEffectiveConnectionTypeForTesting(
470     EffectiveConnectionType effective_connection_type) {
471   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
472 
473   event_creator_.MaybeAddNetworkQualityChangedEventToNetLog(
474       effective_connection_type_,
475       params_->TypicalNetworkQuality(effective_connection_type));
476 
477   for (auto& observer : effective_connection_type_observer_list_)
478     observer.OnEffectiveConnectionTypeChanged(effective_connection_type);
479 
480   network_quality_store_->Add(current_network_id_,
481                               nqe::internal::CachedNetworkQuality(
482                                   tick_clock_->NowTicks(), network_quality_,
483                                   effective_connection_type));
484 }
485 
ReportRTTsAndThroughputForTesting(base::TimeDelta http_rtt,base::TimeDelta transport_rtt,int32_t downstream_throughput_kbps)486 void NetworkQualityEstimator::ReportRTTsAndThroughputForTesting(
487     base::TimeDelta http_rtt,
488     base::TimeDelta transport_rtt,
489     int32_t downstream_throughput_kbps) {
490   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
491 
492   for (auto& observer : rtt_and_throughput_estimates_observer_list_)
493     observer.OnRTTOrThroughputEstimatesComputed(http_rtt, transport_rtt,
494                                                 downstream_throughput_kbps);
495 }
496 
RequestProvidesRTTObservation(const URLRequest & request) const497 bool NetworkQualityEstimator::RequestProvidesRTTObservation(
498     const URLRequest& request) const {
499   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
500 
501   bool private_network_request =
502       nqe::internal::IsRequestForPrivateHost(request, net_log_);
503 
504   return (use_localhost_requests_ || !private_network_request) &&
505          // Verify that response headers are received, so it can be ensured that
506          // response is not cached.
507          !request.response_info().response_time.is_null() &&
508          !request.was_cached() &&
509          request.creation_time() >= last_connection_change_ &&
510          request.method() == "GET";
511 }
512 
OnConnectionTypeChanged(NetworkChangeNotifier::ConnectionType type)513 void NetworkQualityEstimator::OnConnectionTypeChanged(
514     NetworkChangeNotifier::ConnectionType type) {
515   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
516 
517   // It's possible that |type| has the same value as |current_network_id_.type|.
518   // This can happen if the device switches from one WiFi SSID to another.
519 
520   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
521             std::size(rtt_ms_observations_));
522 
523   // Write the estimates of the previous network to the cache.
524   network_quality_store_->Add(
525       current_network_id_, nqe::internal::CachedNetworkQuality(
526                                last_effective_connection_type_computation_,
527                                network_quality_, effective_connection_type_));
528 
529   // Clear the local state.
530   last_connection_change_ = tick_clock_->NowTicks();
531   http_downstream_throughput_kbps_observations_.Clear();
532   for (auto& rtt_ms_observation : rtt_ms_observations_)
533     rtt_ms_observation.Clear();
534 
535   current_network_id_.signal_strength = INT32_MIN;
536   network_quality_ = nqe::internal::NetworkQuality();
537   end_to_end_rtt_ = std::nullopt;
538   effective_connection_type_ = EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
539   rtt_observations_size_at_last_ect_computation_ = 0;
540   throughput_observations_size_at_last_ect_computation_ = 0;
541   new_rtt_observations_since_last_ect_computation_ = 0;
542   new_throughput_observations_since_last_ect_computation_ = 0;
543   transport_rtt_observation_count_last_ect_computation_ = 0;
544   end_to_end_rtt_observation_count_at_last_ect_computation_ = 0;
545   last_socket_watcher_rtt_notification_ = base::TimeTicks();
546   cached_estimate_applied_ = false;
547 
548   GatherEstimatesForNextConnectionType();
549   throughput_analyzer_->OnConnectionTypeChanged();
550 }
551 
GatherEstimatesForNextConnectionType()552 void NetworkQualityEstimator::GatherEstimatesForNextConnectionType() {
553   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
554 
555 #if BUILDFLAG(IS_CHROMEOS_ASH)
556   if (get_network_id_asynchronously_) {
557     // Doing PostTaskAndReplyWithResult by handle because it requires the result
558     // type have a default constructor and nqe::internal::NetworkID does not
559     // have that.
560     g_get_network_id_task_runner.Get()->PostTask(
561         FROM_HERE,
562         base::BindOnce(
563             [](scoped_refptr<base::TaskRunner> reply_task_runner,
564                base::OnceCallback<void(const nqe::internal::NetworkID&)>
565                    reply_callback) {
566               reply_task_runner->PostTask(
567                   FROM_HERE, base::BindOnce(std::move(reply_callback),
568                                             DoGetCurrentNetworkID(nullptr)));
569             },
570             base::SingleThreadTaskRunner::GetCurrentDefault(),
571             base::BindOnce(&NetworkQualityEstimator::
572                                ContinueGatherEstimatesForNextConnectionType,
573                            weak_ptr_factory_.GetWeakPtr())));
574     return;
575   }
576 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
577 
578   ContinueGatherEstimatesForNextConnectionType(GetCurrentNetworkID());
579 }
580 
ContinueGatherEstimatesForNextConnectionType(const nqe::internal::NetworkID & network_id)581 void NetworkQualityEstimator::ContinueGatherEstimatesForNextConnectionType(
582     const nqe::internal::NetworkID& network_id) {
583   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
584   // Update the local state as part of preparation for the new connection.
585   current_network_id_ = network_id;
586 
587   // Read any cached estimates for the new network. If cached estimates are
588   // unavailable, add the default estimates.
589   if (!ReadCachedNetworkQualityEstimate())
590     AddDefaultEstimates();
591 
592   ComputeEffectiveConnectionType();
593 }
594 
ComputeEffectiveConnectionType()595 void NetworkQualityEstimator::ComputeEffectiveConnectionType() {
596   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
597 
598   const base::TimeTicks now = tick_clock_->NowTicks();
599 
600   const EffectiveConnectionType past_type = effective_connection_type_;
601   last_effective_connection_type_computation_ = now;
602 
603   base::TimeDelta http_rtt = nqe::internal::InvalidRTT();
604   base::TimeDelta transport_rtt = nqe::internal::InvalidRTT();
605   base::TimeDelta end_to_end_rtt = nqe::internal::InvalidRTT();
606   int32_t downstream_throughput_kbps = nqe::internal::INVALID_RTT_THROUGHPUT;
607 
608   effective_connection_type_ = GetRecentEffectiveConnectionTypeUsingMetrics(
609       &http_rtt, &transport_rtt, &end_to_end_rtt, &downstream_throughput_kbps,
610       &transport_rtt_observation_count_last_ect_computation_,
611       &end_to_end_rtt_observation_count_at_last_ect_computation_);
612 
613   network_quality_ = nqe::internal::NetworkQuality(http_rtt, transport_rtt,
614                                                    downstream_throughput_kbps);
615   ClampKbpsBasedOnEct();
616   if (network_quality_.http_rtt() != nqe::internal::InvalidRTT()) {
617     UMA_HISTOGRAM_TIMES("NQE.RTT.OnECTComputation",
618                         network_quality_.http_rtt());
619   }
620   if (network_quality_.transport_rtt() != nqe::internal::InvalidRTT()) {
621     base::UmaHistogramTimes("NQE.TransportRTT.OnECTComputation",
622                             network_quality_.transport_rtt());
623   }
624 
625   end_to_end_rtt_ = std::nullopt;
626   if (end_to_end_rtt != nqe::internal::InvalidRTT()) {
627     end_to_end_rtt_ = end_to_end_rtt;
628   }
629 
630   NotifyObserversOfRTTOrThroughputComputed();
631 
632   if (past_type != effective_connection_type_)
633     NotifyObserversOfEffectiveConnectionTypeChanged();
634 
635   event_creator_.MaybeAddNetworkQualityChangedEventToNetLog(
636       effective_connection_type_, network_quality_);
637 
638   rtt_observations_size_at_last_ect_computation_ =
639       rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_HTTP].Size() +
640       rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT]
641           .Size();
642   throughput_observations_size_at_last_ect_computation_ =
643       http_downstream_throughput_kbps_observations_.Size();
644   new_rtt_observations_since_last_ect_computation_ = 0;
645   new_throughput_observations_since_last_ect_computation_ = 0;
646 }
647 
648 std::optional<net::EffectiveConnectionType>
GetOverrideECT() const649 NetworkQualityEstimator::GetOverrideECT() const {
650   return std::nullopt;
651 }
652 
ClampKbpsBasedOnEct()653 void NetworkQualityEstimator::ClampKbpsBasedOnEct() {
654   // No need to clamp when ECT is unknown or if the connection speed is fast.
655   if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
656       effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_OFFLINE ||
657       effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_4G) {
658     return;
659   }
660 
661   if (params_->upper_bound_typical_kbps_multiplier() <= 0.0)
662     return;
663 
664   DCHECK_LT(0, params_->TypicalNetworkQuality(effective_connection_type_)
665                    .downstream_throughput_kbps());
666   // For a given ECT, upper bound on Kbps can't be less than the typical Kbps
667   // for that ECT.
668   DCHECK_LE(1.0, params_->upper_bound_typical_kbps_multiplier());
669 
670   DCHECK(effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_SLOW_2G ||
671          effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_2G ||
672          effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_3G);
673 
674   // Put an upper bound on Kbps.
675   network_quality_.set_downstream_throughput_kbps(
676       std::min(network_quality_.downstream_throughput_kbps(),
677                static_cast<int>(
678                    params_->TypicalNetworkQuality(effective_connection_type_)
679                        .downstream_throughput_kbps() *
680                    params_->upper_bound_typical_kbps_multiplier())));
681 }
682 
AdjustHttpRttBasedOnRTTCounts(base::TimeDelta * http_rtt) const683 void NetworkQualityEstimator::AdjustHttpRttBasedOnRTTCounts(
684     base::TimeDelta* http_rtt) const {
685   if (!params_->adjust_rtt_based_on_rtt_counts())
686     return;
687 
688   // This is needed only when RTT from TCP sockets or
689   // QUIC/H2 connections is unavailable.
690   if (transport_rtt_observation_count_last_ect_computation_ >=
691           params_->http_rtt_transport_rtt_min_count() ||
692       end_to_end_rtt_observation_count_at_last_ect_computation_ >=
693           params_->http_rtt_transport_rtt_min_count()) {
694     return;
695   }
696 
697   // We prefer to use the cached value if it's available and the network change
698   // happened recently.
699   base::TimeDelta time_since_connection_change =
700       tick_clock_->NowTicks() - last_connection_change_;
701   if (cached_estimate_applied_ &&
702       time_since_connection_change <= base::Minutes(1)) {
703     return;
704   }
705 
706   // If there are not enough transport RTT samples, end-to-end RTT samples and
707   // the cached estimates are unavailble/too stale, then the computed value of
708   // HTTP RTT can't be trusted due to hanging GETs. In that case, return the
709   // typical HTTP RTT for a fast connection.
710   if (current_network_id_.type == net::NetworkChangeNotifier::CONNECTION_NONE) {
711     return;
712   }
713 
714   base::TimeDelta upper_bound_http_rtt =
715       params_->TypicalNetworkQuality(net::EFFECTIVE_CONNECTION_TYPE_4G)
716           .http_rtt();
717   if (upper_bound_http_rtt > *http_rtt) {
718     return;
719   }
720 
721   DCHECK_LE(upper_bound_http_rtt, *http_rtt);
722   *http_rtt = upper_bound_http_rtt;
723 }
724 
GetEffectiveConnectionType() const725 EffectiveConnectionType NetworkQualityEstimator::GetEffectiveConnectionType()
726     const {
727   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
728 
729   std::optional<net::EffectiveConnectionType> override_ect = GetOverrideECT();
730   if (override_ect) {
731     return override_ect.value();
732   }
733   return effective_connection_type_;
734 }
735 
UpdateHttpRttUsingAllRttValues(base::TimeDelta * http_rtt,const base::TimeDelta transport_rtt,const base::TimeDelta end_to_end_rtt) const736 void NetworkQualityEstimator::UpdateHttpRttUsingAllRttValues(
737     base::TimeDelta* http_rtt,
738     const base::TimeDelta transport_rtt,
739     const base::TimeDelta end_to_end_rtt) const {
740   DCHECK(http_rtt);
741 
742   // Use transport RTT to clamp the lower bound on HTTP RTT.
743   // To improve accuracy, the transport RTT estimate is used only when the
744   // transport RTT estimate was computed using at least
745   // |params_->http_rtt_transport_rtt_min_count()| observations.
746   if (*http_rtt != nqe::internal::InvalidRTT() &&
747       transport_rtt != nqe::internal::InvalidRTT() &&
748       transport_rtt_observation_count_last_ect_computation_ >=
749           params_->http_rtt_transport_rtt_min_count() &&
750       params_->lower_bound_http_rtt_transport_rtt_multiplier() > 0) {
751     *http_rtt =
752         std::max(*http_rtt,
753                  transport_rtt *
754                      params_->lower_bound_http_rtt_transport_rtt_multiplier());
755   }
756 
757   // Put lower bound on |http_rtt| using |end_to_end_rtt|.
758   if (*http_rtt != nqe::internal::InvalidRTT() &&
759       params_->use_end_to_end_rtt() &&
760       end_to_end_rtt != nqe::internal::InvalidRTT() &&
761       end_to_end_rtt_observation_count_at_last_ect_computation_ >=
762           params_->http_rtt_transport_rtt_min_count() &&
763       params_->lower_bound_http_rtt_transport_rtt_multiplier() > 0) {
764     *http_rtt =
765         std::max(*http_rtt,
766                  end_to_end_rtt *
767                      params_->lower_bound_http_rtt_transport_rtt_multiplier());
768   }
769 
770   // Put upper bound on |http_rtt| using |end_to_end_rtt|.
771   if (*http_rtt != nqe::internal::InvalidRTT() &&
772       params_->use_end_to_end_rtt() &&
773       end_to_end_rtt != nqe::internal::InvalidRTT() &&
774       end_to_end_rtt_observation_count_at_last_ect_computation_ >=
775           params_->http_rtt_transport_rtt_min_count() &&
776       params_->upper_bound_http_rtt_endtoend_rtt_multiplier() > 0) {
777     *http_rtt = std::min(
778         *http_rtt, end_to_end_rtt *
779                        params_->upper_bound_http_rtt_endtoend_rtt_multiplier());
780   }
781 
782   // Put upper bound on |http_rtt| if there is not enough HTTP RTT samples
783   // available.
784   AdjustHttpRttBasedOnRTTCounts(http_rtt);
785 }
786 
787 EffectiveConnectionType
GetRecentEffectiveConnectionTypeUsingMetrics(base::TimeDelta * http_rtt,base::TimeDelta * transport_rtt,base::TimeDelta * end_to_end_rtt,int32_t * downstream_throughput_kbps,size_t * transport_rtt_observation_count,size_t * end_to_end_rtt_observation_count) const788 NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics(
789     base::TimeDelta* http_rtt,
790     base::TimeDelta* transport_rtt,
791     base::TimeDelta* end_to_end_rtt,
792     int32_t* downstream_throughput_kbps,
793     size_t* transport_rtt_observation_count,
794     size_t* end_to_end_rtt_observation_count) const {
795   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
796 
797   *http_rtt = nqe::internal::InvalidRTT();
798   *transport_rtt = nqe::internal::InvalidRTT();
799   *end_to_end_rtt = nqe::internal::InvalidRTT();
800   *downstream_throughput_kbps = nqe::internal::INVALID_RTT_THROUGHPUT;
801 
802   auto forced_ect =
803       params_->GetForcedEffectiveConnectionType(current_network_id_.type);
804   if (forced_ect) {
805     *http_rtt = params_->TypicalNetworkQuality(forced_ect.value()).http_rtt();
806     *transport_rtt =
807         params_->TypicalNetworkQuality(forced_ect.value()).transport_rtt();
808     *downstream_throughput_kbps =
809         params_->TypicalNetworkQuality(forced_ect.value())
810             .downstream_throughput_kbps();
811     return forced_ect.value();
812   }
813 
814   // If the device is currently offline, then return
815   // EFFECTIVE_CONNECTION_TYPE_OFFLINE.
816   if (current_network_id_.type == NetworkChangeNotifier::CONNECTION_NONE &&
817       !disable_offline_check_) {
818     return EFFECTIVE_CONNECTION_TYPE_OFFLINE;
819   }
820 
821   if (force_report_wifi_as_slow_2g_for_testing_ &&
822       current_network_id_.type == NetworkChangeNotifier::CONNECTION_WIFI) {
823     return EFFECTIVE_CONNECTION_TYPE_SLOW_2G;
824   }
825 
826   if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP,
827                     GetHTTPStartTime(), http_rtt, nullptr)) {
828     bool fallback_success = true;
829     if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP,
830                       base::TimeTicks(), http_rtt, nullptr)) {
831       *http_rtt = nqe::internal::InvalidRTT();
832       fallback_success = false;
833     }
834     RecordFallbackSuccess("HTTP", fallback_success);
835   }
836 
837   if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_TRANSPORT,
838                     GetTransportStartTime(), transport_rtt,
839                     transport_rtt_observation_count)) {
840     bool fallback_success = true;
841     if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_TRANSPORT,
842                       base::TimeTicks(), transport_rtt,
843                       transport_rtt_observation_count)) {
844       *transport_rtt = nqe::internal::InvalidRTT();
845       fallback_success = false;
846     }
847     RecordFallbackSuccess("Transport", fallback_success);
848   }
849 
850   if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_END_TO_END,
851                     GetEndToEndStartTime(), end_to_end_rtt,
852                     end_to_end_rtt_observation_count)) {
853     bool fallback_success = true;
854     if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_END_TO_END,
855                       base::TimeTicks(), end_to_end_rtt,
856                       end_to_end_rtt_observation_count)) {
857       *end_to_end_rtt = nqe::internal::InvalidRTT();
858       fallback_success = false;
859     }
860     RecordFallbackSuccess("EndToEnd", fallback_success);
861   }
862 
863   UpdateHttpRttUsingAllRttValues(http_rtt, *transport_rtt, *end_to_end_rtt);
864 
865   if (!GetRecentDownlinkThroughputKbps(base::TimeTicks(),
866                                        downstream_throughput_kbps)) {
867     *downstream_throughput_kbps = nqe::internal::INVALID_RTT_THROUGHPUT;
868   }
869 
870   if (*http_rtt == nqe::internal::InvalidRTT()) {
871     return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
872   }
873 
874   if (*http_rtt == nqe::internal::InvalidRTT() &&
875       *transport_rtt == nqe::internal::InvalidRTT() &&
876       *downstream_throughput_kbps == nqe::internal::INVALID_RTT_THROUGHPUT) {
877     // None of the metrics are available.
878     return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
879   }
880 
881   // Search from the slowest connection type to the fastest to find the
882   // EffectiveConnectionType that best matches the current connection's
883   // performance. The match is done by comparing RTT and throughput.
884   for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
885     EffectiveConnectionType type = static_cast<EffectiveConnectionType>(i);
886     if (i == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
887       continue;
888 
889     const bool estimated_http_rtt_is_higher_than_threshold =
890         *http_rtt != nqe::internal::InvalidRTT() &&
891         params_->ConnectionThreshold(type).http_rtt() !=
892             nqe::internal::InvalidRTT() &&
893         *http_rtt >= params_->ConnectionThreshold(type).http_rtt();
894 
895     if (estimated_http_rtt_is_higher_than_threshold)
896       return type;
897   }
898   // Return the fastest connection type.
899   return static_cast<EffectiveConnectionType>(EFFECTIVE_CONNECTION_TYPE_LAST -
900                                               1);
901 }
902 
AddEffectiveConnectionTypeObserver(EffectiveConnectionTypeObserver * observer)903 void NetworkQualityEstimator::AddEffectiveConnectionTypeObserver(
904     EffectiveConnectionTypeObserver* observer) {
905   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
906   DCHECK(observer);
907   effective_connection_type_observer_list_.AddObserver(observer);
908 
909   // Notify the |observer| on the next message pump since |observer| may not
910   // be completely set up for receiving the callbacks.
911   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
912       FROM_HERE,
913       base::BindOnce(&NetworkQualityEstimator::
914                          NotifyEffectiveConnectionTypeObserverIfPresent,
915                      weak_ptr_factory_.GetWeakPtr(),
916                      // This is safe as `handle` is checked against a map to
917                      // verify it hasn't been removed before dereferencing.
918                      base::UnsafeDangling(observer)));
919 }
920 
RemoveEffectiveConnectionTypeObserver(EffectiveConnectionTypeObserver * observer)921 void NetworkQualityEstimator::RemoveEffectiveConnectionTypeObserver(
922     EffectiveConnectionTypeObserver* observer) {
923   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
924   effective_connection_type_observer_list_.RemoveObserver(observer);
925 }
926 
AddPeerToPeerConnectionsCountObserver(PeerToPeerConnectionsCountObserver * observer)927 void NetworkQualityEstimator::AddPeerToPeerConnectionsCountObserver(
928     PeerToPeerConnectionsCountObserver* observer) {
929   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
930   DCHECK(observer);
931   peer_to_peer_type_observer_list_.AddObserver(observer);
932 
933   // Notify the |observer| on the next message pump since |observer| may not
934   // be completely set up for receiving the callbacks.
935   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
936       FROM_HERE,
937       base::BindOnce(&NetworkQualityEstimator::
938                          NotifyPeerToPeerConnectionsCountObserverIfPresent,
939                      weak_ptr_factory_.GetWeakPtr(),
940                      // This is safe as `handle` is checked against a map to
941                      // verify it hasn't been removed before dereferencing.
942                      base::UnsafeDangling(observer)));
943 }
944 
RemovePeerToPeerConnectionsCountObserver(PeerToPeerConnectionsCountObserver * observer)945 void NetworkQualityEstimator::RemovePeerToPeerConnectionsCountObserver(
946     PeerToPeerConnectionsCountObserver* observer) {
947   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
948   peer_to_peer_type_observer_list_.RemoveObserver(observer);
949 }
950 
AddRTTAndThroughputEstimatesObserver(RTTAndThroughputEstimatesObserver * observer)951 void NetworkQualityEstimator::AddRTTAndThroughputEstimatesObserver(
952     RTTAndThroughputEstimatesObserver* observer) {
953   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
954   DCHECK(observer);
955   rtt_and_throughput_estimates_observer_list_.AddObserver(observer);
956 
957   // Notify the |observer| on the next message pump since |observer| may not
958   // be completely set up for receiving the callbacks.
959   base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
960       FROM_HERE,
961       base::BindOnce(&NetworkQualityEstimator::
962                          NotifyRTTAndThroughputEstimatesObserverIfPresent,
963                      weak_ptr_factory_.GetWeakPtr(), observer));
964 }
965 
RemoveRTTAndThroughputEstimatesObserver(RTTAndThroughputEstimatesObserver * observer)966 void NetworkQualityEstimator::RemoveRTTAndThroughputEstimatesObserver(
967     RTTAndThroughputEstimatesObserver* observer) {
968   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
969   rtt_and_throughput_estimates_observer_list_.RemoveObserver(observer);
970 }
971 
GetRecentRTT(nqe::internal::ObservationCategory observation_category,const base::TimeTicks & start_time,base::TimeDelta * rtt,size_t * observations_count) const972 bool NetworkQualityEstimator::GetRecentRTT(
973     nqe::internal::ObservationCategory observation_category,
974     const base::TimeTicks& start_time,
975     base::TimeDelta* rtt,
976     size_t* observations_count) const {
977   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
978   *rtt = GetRTTEstimateInternal(start_time, observation_category, 50,
979                                 observations_count);
980   return (*rtt != nqe::internal::InvalidRTT());
981 }
982 
GetRecentDownlinkThroughputKbps(const base::TimeTicks & start_time,int32_t * kbps) const983 bool NetworkQualityEstimator::GetRecentDownlinkThroughputKbps(
984     const base::TimeTicks& start_time,
985     int32_t* kbps) const {
986   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
987   *kbps = GetDownlinkThroughputKbpsEstimateInternal(start_time, 50);
988   return (*kbps != nqe::internal::INVALID_RTT_THROUGHPUT);
989 }
990 
GetRTTEstimateInternal(base::TimeTicks start_time,nqe::internal::ObservationCategory observation_category,int percentile,size_t * observations_count) const991 base::TimeDelta NetworkQualityEstimator::GetRTTEstimateInternal(
992     base::TimeTicks start_time,
993     nqe::internal::ObservationCategory observation_category,
994     int percentile,
995     size_t* observations_count) const {
996   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
997   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
998             std::size(rtt_ms_observations_));
999 
1000   // RTT observations are sorted by duration from shortest to longest, thus
1001   // a higher percentile RTT will have a longer RTT than a lower percentile.
1002   switch (observation_category) {
1003     case nqe::internal::OBSERVATION_CATEGORY_HTTP:
1004     case nqe::internal::OBSERVATION_CATEGORY_TRANSPORT:
1005     case nqe::internal::OBSERVATION_CATEGORY_END_TO_END:
1006       return base::Milliseconds(
1007           rtt_ms_observations_[observation_category]
1008               .GetPercentile(start_time, current_network_id_.signal_strength,
1009                              percentile, observations_count)
1010               .value_or(nqe::internal::INVALID_RTT_THROUGHPUT));
1011     case nqe::internal::OBSERVATION_CATEGORY_COUNT:
1012       NOTREACHED();
1013   }
1014 }
1015 
GetDownlinkThroughputKbpsEstimateInternal(const base::TimeTicks & start_time,int percentile) const1016 int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal(
1017     const base::TimeTicks& start_time,
1018     int percentile) const {
1019   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1020 
1021   // Throughput observations are sorted by kbps from slowest to fastest,
1022   // thus a higher percentile throughput will be faster than a lower one.
1023   return http_downstream_throughput_kbps_observations_
1024       .GetPercentile(start_time, current_network_id_.signal_strength,
1025                      100 - percentile, nullptr)
1026       .value_or(nqe::internal::INVALID_RTT_THROUGHPUT);
1027 }
1028 
GetCurrentNetworkID() const1029 nqe::internal::NetworkID NetworkQualityEstimator::GetCurrentNetworkID() const {
1030   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1031 
1032   // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class
1033   // that overrides this method on the Android platform.
1034 
1035   return DoGetCurrentNetworkID(params_.get());
1036 }
1037 
ReadCachedNetworkQualityEstimate()1038 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
1039   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1040 
1041   if (!params_->persistent_cache_reading_enabled())
1042     return false;
1043 
1044   nqe::internal::CachedNetworkQuality cached_network_quality;
1045 
1046   const bool cached_estimate_available = network_quality_store_->GetById(
1047       current_network_id_, &cached_network_quality);
1048 
1049   if (!cached_estimate_available) {
1050     return false;
1051   }
1052 
1053   EffectiveConnectionType effective_connection_type =
1054       cached_network_quality.effective_connection_type();
1055 
1056   if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
1057       effective_connection_type == EFFECTIVE_CONNECTION_TYPE_OFFLINE ||
1058       effective_connection_type == EFFECTIVE_CONNECTION_TYPE_LAST) {
1059     return false;
1060   }
1061 
1062   nqe::internal::NetworkQuality network_quality =
1063       cached_network_quality.network_quality();
1064 
1065   bool update_network_quality_store = false;
1066 
1067   // Populate |network_quality| with synthetic RTT and throughput observations
1068   // if they are missing.
1069   if (network_quality.http_rtt().InMilliseconds() ==
1070       nqe::internal::INVALID_RTT_THROUGHPUT) {
1071     network_quality.set_http_rtt(
1072         params_->TypicalNetworkQuality(effective_connection_type).http_rtt());
1073     update_network_quality_store = true;
1074   }
1075 
1076   if (network_quality.transport_rtt().InMilliseconds() ==
1077       nqe::internal::INVALID_RTT_THROUGHPUT) {
1078     network_quality.set_transport_rtt(
1079         params_->TypicalNetworkQuality(effective_connection_type)
1080             .transport_rtt());
1081     update_network_quality_store = true;
1082   }
1083 
1084   if (network_quality.downstream_throughput_kbps() ==
1085       nqe::internal::INVALID_RTT_THROUGHPUT) {
1086     network_quality.set_downstream_throughput_kbps(
1087         params_->TypicalNetworkQuality(effective_connection_type)
1088             .downstream_throughput_kbps());
1089     update_network_quality_store = true;
1090   }
1091 
1092   if (update_network_quality_store) {
1093     network_quality_store_->Add(current_network_id_,
1094                                 nqe::internal::CachedNetworkQuality(
1095                                     tick_clock_->NowTicks(), network_quality,
1096                                     effective_connection_type));
1097   }
1098 
1099   Observation http_rtt_observation(
1100       network_quality.http_rtt().InMilliseconds(), tick_clock_->NowTicks(),
1101       INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE);
1102   AddAndNotifyObserversOfRTT(http_rtt_observation);
1103 
1104   Observation transport_rtt_observation(
1105       network_quality.transport_rtt().InMilliseconds(), tick_clock_->NowTicks(),
1106       INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE);
1107   AddAndNotifyObserversOfRTT(transport_rtt_observation);
1108 
1109   Observation througphput_observation(
1110       network_quality.downstream_throughput_kbps(), tick_clock_->NowTicks(),
1111       INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE);
1112   AddAndNotifyObserversOfThroughput(througphput_observation);
1113 
1114   ComputeEffectiveConnectionType();
1115   return true;
1116 }
1117 
SetTickClockForTesting(const base::TickClock * tick_clock)1118 void NetworkQualityEstimator::SetTickClockForTesting(
1119     const base::TickClock* tick_clock) {
1120   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1121   tick_clock_ = tick_clock;
1122   for (auto& rtt_ms_observation : rtt_ms_observations_)
1123     rtt_ms_observation.SetTickClockForTesting(tick_clock_);  // IN-TEST
1124   http_downstream_throughput_kbps_observations_.SetTickClockForTesting(
1125       tick_clock_);
1126   throughput_analyzer_->SetTickClockForTesting(tick_clock_);
1127   watcher_factory_->SetTickClockForTesting(tick_clock_);
1128 }
1129 
OnUpdatedTransportRTTAvailable(SocketPerformanceWatcherFactory::Protocol protocol,const base::TimeDelta & rtt,const std::optional<nqe::internal::IPHash> & host)1130 void NetworkQualityEstimator::OnUpdatedTransportRTTAvailable(
1131     SocketPerformanceWatcherFactory::Protocol protocol,
1132     const base::TimeDelta& rtt,
1133     const std::optional<nqe::internal::IPHash>& host) {
1134   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1135   DCHECK_LT(nqe::internal::INVALID_RTT_THROUGHPUT, rtt.InMilliseconds());
1136   Observation observation(rtt.InMilliseconds(), tick_clock_->NowTicks(),
1137                           current_network_id_.signal_strength,
1138                           ProtocolSourceToObservationSource(protocol), host);
1139   AddAndNotifyObserversOfRTT(observation);
1140 }
1141 
AddAndNotifyObserversOfRTT(const Observation & observation)1142 void NetworkQualityEstimator::AddAndNotifyObserversOfRTT(
1143     const Observation& observation) {
1144   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1145   DCHECK_NE(nqe::internal::InvalidRTT(),
1146             base::Milliseconds(observation.value()));
1147   DCHECK_GT(NETWORK_QUALITY_OBSERVATION_SOURCE_MAX, observation.source());
1148 
1149   if (!ShouldAddObservation(observation))
1150     return;
1151 
1152   MaybeUpdateCachedEstimateApplied(
1153       observation,
1154       &rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_HTTP]);
1155   MaybeUpdateCachedEstimateApplied(
1156       observation,
1157       &rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT]);
1158   ++new_rtt_observations_since_last_ect_computation_;
1159 
1160   std::vector<nqe::internal::ObservationCategory> observation_categories =
1161       observation.GetObservationCategories();
1162   for (nqe::internal::ObservationCategory observation_category :
1163        observation_categories) {
1164     auto evicted =
1165         rtt_ms_observations_[observation_category].AddObservation(observation);
1166     if (evicted) {
1167       auto delta = base::TimeTicks::Now() - evicted->timestamp();
1168       base::UmaHistogramLongTimes100(
1169           base::StrCat({"NQE.RTT.ObservationBufferLifeTime2.",
1170                         CategoryToString(observation_category)}),
1171           delta);
1172       base::UmaHistogramLongTimes100("NQE.RTT.ObservationBufferLifeTime2.All",
1173                                      delta);
1174     }
1175   }
1176 
1177   if (observation.source() == NETWORK_QUALITY_OBSERVATION_SOURCE_TCP ||
1178       observation.source() == NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC) {
1179     last_socket_watcher_rtt_notification_ = tick_clock_->NowTicks();
1180   }
1181 
1182   UMA_HISTOGRAM_ENUMERATION("NQE.RTT.ObservationSource", observation.source(),
1183                             NETWORK_QUALITY_OBSERVATION_SOURCE_MAX);
1184 
1185   // Maybe recompute the effective connection type since a new RTT observation
1186   // is available.
1187   if (observation.source() !=
1188           NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE &&
1189       observation.source() !=
1190           NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE) {
1191     MaybeComputeEffectiveConnectionType();
1192   }
1193   for (auto& observer : rtt_observer_list_) {
1194     observer.OnRTTObservation(observation.value(), observation.timestamp(),
1195                               observation.source());
1196   }
1197 }
1198 
AddAndNotifyObserversOfThroughput(const Observation & observation)1199 void NetworkQualityEstimator::AddAndNotifyObserversOfThroughput(
1200     const Observation& observation) {
1201   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1202   DCHECK_NE(nqe::internal::INVALID_RTT_THROUGHPUT, observation.value());
1203   DCHECK_GT(NETWORK_QUALITY_OBSERVATION_SOURCE_MAX, observation.source());
1204   DCHECK_EQ(1u, observation.GetObservationCategories().size());
1205   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_HTTP,
1206             observation.GetObservationCategories().front());
1207 
1208   if (!ShouldAddObservation(observation))
1209     return;
1210 
1211   MaybeUpdateCachedEstimateApplied(
1212       observation, &http_downstream_throughput_kbps_observations_);
1213   ++new_throughput_observations_since_last_ect_computation_;
1214   http_downstream_throughput_kbps_observations_.AddObservation(observation);
1215 
1216   // Maybe recompute the effective connection type since a new throughput
1217   // observation is available.
1218   if (observation.source() !=
1219           NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE &&
1220       observation.source() !=
1221           NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE) {
1222     MaybeComputeEffectiveConnectionType();
1223   }
1224   for (auto& observer : throughput_observer_list_) {
1225     observer.OnThroughputObservation(
1226         observation.value(), observation.timestamp(), observation.source());
1227   }
1228 }
1229 
OnNewThroughputObservationAvailable(int32_t downstream_kbps)1230 void NetworkQualityEstimator::OnNewThroughputObservationAvailable(
1231     int32_t downstream_kbps) {
1232   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1233 
1234   if (downstream_kbps <= 0)
1235     return;
1236 
1237   DCHECK_NE(nqe::internal::INVALID_RTT_THROUGHPUT, downstream_kbps);
1238 
1239   Observation throughput_observation(downstream_kbps, tick_clock_->NowTicks(),
1240                                      current_network_id_.signal_strength,
1241                                      NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP);
1242   AddAndNotifyObserversOfThroughput(throughput_observation);
1243 }
1244 
ShouldComputeEffectiveConnectionType() const1245 bool NetworkQualityEstimator::ShouldComputeEffectiveConnectionType() const {
1246   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1247   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
1248             std::size(rtt_ms_observations_));
1249 
1250   const base::TimeTicks now = tick_clock_->NowTicks();
1251   // Recompute effective connection type only if
1252   // |effective_connection_type_recomputation_interval_| has passed since it was
1253   // last computed or a connection change event was observed since the last
1254   // computation. Strict inequalities are used to ensure that effective
1255   // connection type is recomputed on connection change events even if the clock
1256   // has not updated.
1257   if (now - last_effective_connection_type_computation_ >=
1258       effective_connection_type_recomputation_interval_) {
1259     return true;
1260   }
1261 
1262   if (last_connection_change_ >= last_effective_connection_type_computation_) {
1263     return true;
1264   }
1265 
1266   // Recompute the effective connection type if the previously computed
1267   // effective connection type was unknown.
1268   if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
1269     return true;
1270   }
1271 
1272   // Recompute the effective connection type if the number of samples
1273   // available now are 50% more than the number of samples that were
1274   // available when the effective connection type was last computed.
1275   if (rtt_observations_size_at_last_ect_computation_ * 1.5 <
1276       (rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_HTTP].Size() +
1277        rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT]
1278            .Size())) {
1279     return true;
1280   }
1281 
1282   if (throughput_observations_size_at_last_ect_computation_ * 1.5 <
1283       http_downstream_throughput_kbps_observations_.Size()) {
1284     return true;
1285   }
1286 
1287   if ((new_rtt_observations_since_last_ect_computation_ +
1288        new_throughput_observations_since_last_ect_computation_) >=
1289       params_->count_new_observations_received_compute_ect()) {
1290     return true;
1291   }
1292   return false;
1293 }
1294 
MaybeComputeEffectiveConnectionType()1295 void NetworkQualityEstimator::MaybeComputeEffectiveConnectionType() {
1296   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1297 
1298   if (!ShouldComputeEffectiveConnectionType())
1299     return;
1300   ComputeEffectiveConnectionType();
1301 }
1302 
1303 void NetworkQualityEstimator::
NotifyObserversOfEffectiveConnectionTypeChanged()1304     NotifyObserversOfEffectiveConnectionTypeChanged() {
1305   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1306   DCHECK_NE(EFFECTIVE_CONNECTION_TYPE_LAST, effective_connection_type_);
1307 
1308   std::optional<net::EffectiveConnectionType> override_ect = GetOverrideECT();
1309 
1310   // TODO(tbansal): Add hysteresis in the notification.
1311   for (auto& observer : effective_connection_type_observer_list_)
1312     observer.OnEffectiveConnectionTypeChanged(
1313         override_ect ? override_ect.value() : effective_connection_type_);
1314   // Add the estimates of the current network to the cache store.
1315   network_quality_store_->Add(current_network_id_,
1316                               nqe::internal::CachedNetworkQuality(
1317                                   tick_clock_->NowTicks(), network_quality_,
1318                                   effective_connection_type_));
1319 }
1320 
NotifyObserversOfRTTOrThroughputComputed() const1321 void NetworkQualityEstimator::NotifyObserversOfRTTOrThroughputComputed() const {
1322   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1323 
1324   // TODO(tbansal): Add hysteresis in the notification.
1325   for (auto& observer : rtt_and_throughput_estimates_observer_list_) {
1326     observer.OnRTTOrThroughputEstimatesComputed(
1327         network_quality_.http_rtt(), network_quality_.transport_rtt(),
1328         network_quality_.downstream_throughput_kbps());
1329   }
1330 }
1331 
NotifyEffectiveConnectionTypeObserverIfPresent(MayBeDangling<EffectiveConnectionTypeObserver> observer) const1332 void NetworkQualityEstimator::NotifyEffectiveConnectionTypeObserverIfPresent(
1333     MayBeDangling<EffectiveConnectionTypeObserver> observer) const {
1334   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1335 
1336   if (!effective_connection_type_observer_list_.HasObserver(observer))
1337     return;
1338 
1339   std::optional<net::EffectiveConnectionType> override_ect = GetOverrideECT();
1340   if (override_ect) {
1341     observer->OnEffectiveConnectionTypeChanged(override_ect.value());
1342     return;
1343   }
1344   if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
1345     return;
1346   observer->OnEffectiveConnectionTypeChanged(effective_connection_type_);
1347 }
1348 
NotifyPeerToPeerConnectionsCountObserverIfPresent(MayBeDangling<PeerToPeerConnectionsCountObserver> observer) const1349 void NetworkQualityEstimator::NotifyPeerToPeerConnectionsCountObserverIfPresent(
1350     MayBeDangling<PeerToPeerConnectionsCountObserver> observer) const {
1351   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1352 
1353   if (!peer_to_peer_type_observer_list_.HasObserver(observer))
1354     return;
1355   observer->OnPeerToPeerConnectionsCountChange(p2p_connections_count_);
1356 }
1357 
NotifyRTTAndThroughputEstimatesObserverIfPresent(RTTAndThroughputEstimatesObserver * observer) const1358 void NetworkQualityEstimator::NotifyRTTAndThroughputEstimatesObserverIfPresent(
1359     RTTAndThroughputEstimatesObserver* observer) const {
1360   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1361 
1362   if (!rtt_and_throughput_estimates_observer_list_.HasObserver(observer))
1363     return;
1364   observer->OnRTTOrThroughputEstimatesComputed(
1365       network_quality_.http_rtt(), network_quality_.transport_rtt(),
1366       network_quality_.downstream_throughput_kbps());
1367 }
1368 
AddNetworkQualitiesCacheObserver(nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver * observer)1369 void NetworkQualityEstimator::AddNetworkQualitiesCacheObserver(
1370     nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
1371         observer) {
1372   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1373   network_quality_store_->AddNetworkQualitiesCacheObserver(observer);
1374 }
1375 
RemoveNetworkQualitiesCacheObserver(nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver * observer)1376 void NetworkQualityEstimator::RemoveNetworkQualitiesCacheObserver(
1377     nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
1378         observer) {
1379   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1380   network_quality_store_->RemoveNetworkQualitiesCacheObserver(observer);
1381 }
1382 
OnPrefsRead(const std::map<nqe::internal::NetworkID,nqe::internal::CachedNetworkQuality> read_prefs)1383 void NetworkQualityEstimator::OnPrefsRead(
1384     const std::map<nqe::internal::NetworkID,
1385                    nqe::internal::CachedNetworkQuality> read_prefs) {
1386   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1387 
1388   for (auto& it : read_prefs) {
1389     EffectiveConnectionType effective_connection_type =
1390         it.second.effective_connection_type();
1391     if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
1392         effective_connection_type == EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
1393       continue;
1394     }
1395 
1396     // RTT and throughput values are not set in the prefs.
1397     DCHECK_EQ(nqe::internal::InvalidRTT(),
1398               it.second.network_quality().http_rtt());
1399     DCHECK_EQ(nqe::internal::InvalidRTT(),
1400               it.second.network_quality().transport_rtt());
1401     DCHECK_EQ(nqe::internal::INVALID_RTT_THROUGHPUT,
1402               it.second.network_quality().downstream_throughput_kbps());
1403 
1404     nqe::internal::CachedNetworkQuality cached_network_quality(
1405         tick_clock_->NowTicks(),
1406         params_->TypicalNetworkQuality(effective_connection_type),
1407         effective_connection_type);
1408 
1409     network_quality_store_->Add(it.first, cached_network_quality);
1410   }
1411   ReadCachedNetworkQualityEstimate();
1412 }
1413 
1414 #if BUILDFLAG(IS_CHROMEOS_ASH)
EnableGetNetworkIdAsynchronously()1415 void NetworkQualityEstimator::EnableGetNetworkIdAsynchronously() {
1416   get_network_id_asynchronously_ = true;
1417 }
1418 #endif  // BUILDFLAG(IS_CHROMEOS_ASH)
1419 
GetHttpRTT() const1420 std::optional<base::TimeDelta> NetworkQualityEstimator::GetHttpRTT() const {
1421   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1422 
1423   if (network_quality_.http_rtt() == nqe::internal::InvalidRTT())
1424     return std::optional<base::TimeDelta>();
1425   return network_quality_.http_rtt();
1426 }
1427 
GetTransportRTT() const1428 std::optional<base::TimeDelta> NetworkQualityEstimator::GetTransportRTT()
1429     const {
1430   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1431 
1432   if (network_quality_.transport_rtt() == nqe::internal::InvalidRTT())
1433     return std::optional<base::TimeDelta>();
1434   return network_quality_.transport_rtt();
1435 }
1436 
GetDownstreamThroughputKbps() const1437 std::optional<int32_t> NetworkQualityEstimator::GetDownstreamThroughputKbps()
1438     const {
1439   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1440 
1441   if (network_quality_.downstream_throughput_kbps() ==
1442       nqe::internal::INVALID_RTT_THROUGHPUT) {
1443     return std::optional<int32_t>();
1444   }
1445   return network_quality_.downstream_throughput_kbps();
1446 }
1447 
MaybeUpdateCachedEstimateApplied(const Observation & observation,ObservationBuffer * buffer)1448 void NetworkQualityEstimator::MaybeUpdateCachedEstimateApplied(
1449     const Observation& observation,
1450     ObservationBuffer* buffer) {
1451   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1452   if (observation.source() !=
1453           NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE &&
1454       observation.source() !=
1455           NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE) {
1456     return;
1457   }
1458 
1459   cached_estimate_applied_ = true;
1460   bool deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_MAX] = {
1461       false};
1462   deleted_observation_sources
1463       [NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM] = true;
1464   deleted_observation_sources
1465       [NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM] =
1466           true;
1467 
1468   buffer->RemoveObservationsWithSource(deleted_observation_sources);
1469 }
1470 
ShouldAddObservation(const Observation & observation) const1471 bool NetworkQualityEstimator::ShouldAddObservation(
1472     const Observation& observation) const {
1473   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1474 
1475   if (cached_estimate_applied_ &&
1476       (observation.source() ==
1477            NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM ||
1478        observation.source() ==
1479            NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM)) {
1480     return false;
1481   }
1482   return true;
1483 }
1484 
ShouldSocketWatcherNotifyRTT(base::TimeTicks now)1485 bool NetworkQualityEstimator::ShouldSocketWatcherNotifyRTT(
1486     base::TimeTicks now) {
1487   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1488   return (now - last_socket_watcher_rtt_notification_ >=
1489           params_->socket_watchers_min_notification_interval());
1490 }
1491 
SimulateNetworkQualityChangeForTesting(net::EffectiveConnectionType type)1492 void NetworkQualityEstimator::SimulateNetworkQualityChangeForTesting(
1493     net::EffectiveConnectionType type) {
1494   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1495   params_->SetForcedEffectiveConnectionTypeForTesting(type);
1496   ComputeEffectiveConnectionType();
1497 }
1498 
ForceReportWifiAsSlow2GForTesting()1499 void NetworkQualityEstimator::ForceReportWifiAsSlow2GForTesting() {
1500   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1501   force_report_wifi_as_slow_2g_for_testing_ = true;
1502 }
1503 
RecordSpdyPingLatency(const HostPortPair & host_port_pair,base::TimeDelta rtt)1504 void NetworkQualityEstimator::RecordSpdyPingLatency(
1505     const HostPortPair& host_port_pair,
1506     base::TimeDelta rtt) {
1507   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1508   DCHECK_LT(nqe::internal::INVALID_RTT_THROUGHPUT, rtt.InMilliseconds());
1509 
1510   Observation observation(rtt.InMilliseconds(), tick_clock_->NowTicks(),
1511                           current_network_id_.signal_strength,
1512                           NETWORK_QUALITY_OBSERVATION_SOURCE_H2_PINGS);
1513   AddAndNotifyObserversOfRTT(observation);
1514 }
1515 
OnPeerToPeerConnectionsCountChange(uint32_t count)1516 void NetworkQualityEstimator::OnPeerToPeerConnectionsCountChange(
1517     uint32_t count) {
1518   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1519 
1520   if (p2p_connections_count_ == count)
1521     return;
1522 
1523   p2p_connections_count_ = count;
1524 
1525   for (auto& observer : peer_to_peer_type_observer_list_) {
1526     observer.OnPeerToPeerConnectionsCountChange(p2p_connections_count_);
1527   }
1528 }
1529 
GetPeerToPeerConnectionsCountChange() const1530 uint32_t NetworkQualityEstimator::GetPeerToPeerConnectionsCountChange() const {
1531   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1532   return p2p_connections_count_;
1533 }
1534 
1535 }  // namespace net
1536