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