1 // Copyright 2015 The Chromium Authors. All rights reserved.
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 <utility>
11 
12 #include "base/bind.h"
13 #include "base/callback_helpers.h"
14 #include "base/check_op.h"
15 #include "base/location.h"
16 #include "base/metrics/field_trial_params.h"
17 #include "base/metrics/histogram.h"
18 #include "base/metrics/histogram_base.h"
19 #include "base/metrics/histogram_functions.h"
20 #include "base/metrics/histogram_macros.h"
21 #include "base/metrics/histogram_macros_local.h"
22 #include "base/notreached.h"
23 #include "base/single_thread_task_runner.h"
24 #include "base/stl_util.h"
25 #include "base/strings/string_number_conversions.h"
26 #include "base/strings/string_piece.h"
27 #include "base/strings/stringprintf.h"
28 #include "base/task/lazy_thread_pool_task_runner.h"
29 #include "base/threading/thread_task_runner_handle.h"
30 #include "base/time/default_tick_clock.h"
31 #include "base/trace_event/trace_event.h"
32 #include "build/build_config.h"
33 #include "net/base/features.h"
34 #include "net/base/host_port_pair.h"
35 #include "net/base/load_flags.h"
36 #include "net/base/load_timing_info.h"
37 #include "net/base/network_interfaces.h"
38 #include "net/base/trace_constants.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/connectivity_monitor.h"
43 #include "net/nqe/network_quality_estimator_util.h"
44 #include "net/nqe/throughput_analyzer.h"
45 #include "net/nqe/weighted_observation.h"
46 #include "net/url_request/url_request.h"
47 #include "net/url_request/url_request_context.h"
48 #include "url/gurl.h"
49 
50 #if defined(OS_ANDROID)
51 #include "net/android/cellular_signal_strength.h"
52 #include "net/android/network_library.h"
53 #endif  // OS_ANDROID
54 
55 namespace net {
56 
57 class HostResolver;
58 
59 namespace {
60 
61 #if defined(OS_CHROMEOS)
62 // SequencedTaskRunner to get the network id. A SequencedTaskRunner is used
63 // rather than parallel tasks to avoid having many threads getting the network
64 // id concurrently.
65 base::LazyThreadPoolSequencedTaskRunner g_get_network_id_task_runner =
66     LAZY_THREAD_POOL_SEQUENCED_TASK_RUNNER_INITIALIZER(
67         base::TaskTraits(base::MayBlock(),
68                          base::TaskPriority::BEST_EFFORT,
69                          base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN));
70 #endif
71 
ProtocolSourceToObservationSource(SocketPerformanceWatcherFactory::Protocol protocol)72 NetworkQualityObservationSource ProtocolSourceToObservationSource(
73     SocketPerformanceWatcherFactory::Protocol protocol) {
74   switch (protocol) {
75     case SocketPerformanceWatcherFactory::PROTOCOL_TCP:
76       return NETWORK_QUALITY_OBSERVATION_SOURCE_TCP;
77     case SocketPerformanceWatcherFactory::PROTOCOL_QUIC:
78       return NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC;
79   }
80   NOTREACHED();
81   return NETWORK_QUALITY_OBSERVATION_SOURCE_TCP;
82 }
83 
84 // Returns true if the scheme of the |request| is either HTTP or HTTPS.
RequestSchemeIsHTTPOrHTTPS(const URLRequest & request)85 bool RequestSchemeIsHTTPOrHTTPS(const URLRequest& request) {
86   return request.url().is_valid() && request.url().SchemeIsHTTPOrHTTPS();
87 }
88 
DoGetCurrentNetworkID(NetworkQualityEstimatorParams * params)89 nqe::internal::NetworkID DoGetCurrentNetworkID(
90     NetworkQualityEstimatorParams* params) {
91   // It is possible that the connection type changed between when
92   // GetConnectionType() was called and when the API to determine the
93   // network name was called. Check if that happened and retry until the
94   // connection type stabilizes. This is an imperfect solution but should
95   // capture majority of cases, and should not significantly affect estimates
96   // (that are approximate to begin with).
97   while (true) {
98     nqe::internal::NetworkID network_id(
99         NetworkChangeNotifier::GetConnectionType(), std::string(), INT32_MIN);
100 
101     if (!params || !params->get_signal_strength_and_detailed_network_id())
102       return network_id;
103 
104     switch (network_id.type) {
105       case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
106       case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
107       case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
108       case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
109         break;
110       case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
111 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) || defined(OS_BSD) || \
112     defined(OS_WIN)
113         network_id.id = GetWifiSSID();
114 #endif
115         break;
116       case NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
117       case NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
118       case NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
119       case NetworkChangeNotifier::ConnectionType::CONNECTION_5G:
120 #if defined(OS_ANDROID)
121         network_id.id = android::GetTelephonyNetworkOperator();
122 #endif
123         break;
124       default:
125         NOTREACHED() << "Unexpected connection type = " << network_id.type;
126         break;
127     }
128 
129     if (network_id.type == NetworkChangeNotifier::GetConnectionType())
130       return network_id;
131   }
132   NOTREACHED();
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       end_to_end_rtt_observation_count_at_last_ect_computation_(0),
142       use_localhost_requests_(false),
143       disable_offline_check_(false),
144       tick_clock_(base::DefaultTickClock::GetInstance()),
145       last_connection_change_(tick_clock_->NowTicks()),
146       current_network_id_(nqe::internal::NetworkID(
147           NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
148           std::string(),
149           INT32_MIN)),
150       http_downstream_throughput_kbps_observations_(
151           params_.get(),
152           tick_clock_,
153           params_->weight_multiplier_per_second(),
154           params_->weight_multiplier_per_signal_strength_level()),
155       rtt_ms_observations_{
156           ObservationBuffer(
157               params_.get(),
158               tick_clock_,
159               params_->weight_multiplier_per_second(),
160               params_->weight_multiplier_per_signal_strength_level()),
161           ObservationBuffer(
162               params_.get(),
163               tick_clock_,
164               params_->weight_multiplier_per_second(),
165               params_->weight_multiplier_per_signal_strength_level()),
166           ObservationBuffer(
167               params_.get(),
168               tick_clock_,
169               params_->weight_multiplier_per_second(),
170               params_->weight_multiplier_per_signal_strength_level())},
171       effective_connection_type_at_last_main_frame_(
172           EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
173       queueing_delay_update_interval_(base::TimeDelta::FromMilliseconds(2000)),
174       effective_connection_type_recomputation_interval_(
175           base::TimeDelta::FromSeconds(10)),
176       rtt_observations_size_at_last_ect_computation_(0),
177       throughput_observations_size_at_last_ect_computation_(0),
178       transport_rtt_observation_count_last_ect_computation_(0),
179       new_rtt_observations_since_last_ect_computation_(0),
180       new_throughput_observations_since_last_ect_computation_(0),
181       network_congestion_analyzer_(this, tick_clock_),
182       effective_connection_type_(EFFECTIVE_CONNECTION_TYPE_UNKNOWN),
183       cached_estimate_applied_(false),
184       net_log_(NetLogWithSource::Make(
185           net_log,
186           net::NetLogSourceType::NETWORK_QUALITY_ESTIMATOR)),
187       event_creator_(net_log_),
188       connectivity_monitor_(std::make_unique<ConnectivityMonitor>()) {
189   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
190             base::size(rtt_ms_observations_));
191 
192   AddEffectiveConnectionTypeObserver(&network_congestion_analyzer_);
193   network_quality_store_.reset(new nqe::internal::NetworkQualityStore());
194   NetworkChangeNotifier::AddConnectionTypeObserver(this);
195   throughput_analyzer_.reset(new nqe::internal::ThroughputAnalyzer(
196       this, params_.get(), base::ThreadTaskRunnerHandle::Get(),
197       base::BindRepeating(
198           &NetworkQualityEstimator::OnNewThroughputObservationAvailable,
199           weak_ptr_factory_.GetWeakPtr()),
200       tick_clock_, net_log_));
201 
202   watcher_factory_.reset(new nqe::internal::SocketWatcherFactory(
203       base::ThreadTaskRunnerHandle::Get(),
204       params_->min_socket_watcher_notification_interval(),
205       // OnUpdatedTransportRTTAvailable() may be called via PostTask() by
206       // socket watchers that live on a different thread than the current thread
207       // (i.e., base::ThreadTaskRunnerHandle::Get()).
208       // Use WeakPtr() to avoid crashes where the socket watcher is destroyed
209       // after |this| is destroyed.
210       base::BindRepeating(
211           &NetworkQualityEstimator::OnUpdatedTransportRTTAvailable,
212           weak_ptr_factory_.GetWeakPtr()),
213       // ShouldSocketWatcherNotifyRTT() below is called by only the socket
214       // watchers that live on the same thread as the current thread
215       // (i.e., base::ThreadTaskRunnerHandle::Get()). Also, network quality
216       // estimator is destroyed after network contexts and URLRequestContexts.
217       // It's safe to use base::Unretained() below since the socket watcher
218       // (owned by sockets) would be destroyed before |this|.
219       base::BindRepeating(
220           &NetworkQualityEstimator::ShouldSocketWatcherNotifyRTT,
221           base::Unretained(this)),
222       tick_clock_));
223 
224   GatherEstimatesForNextConnectionType();
225 }
226 
AddDefaultEstimates()227 void NetworkQualityEstimator::AddDefaultEstimates() {
228   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
229 
230   if (!params_->add_default_platform_observations())
231     return;
232 
233   if (params_->DefaultObservation(current_network_id_.type).http_rtt() !=
234       nqe::internal::InvalidRTT()) {
235     Observation rtt_observation(
236         params_->DefaultObservation(current_network_id_.type)
237             .http_rtt()
238             .InMilliseconds(),
239         tick_clock_->NowTicks(), INT32_MIN,
240         NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM);
241     AddAndNotifyObserversOfRTT(rtt_observation);
242   }
243 
244   if (params_->DefaultObservation(current_network_id_.type).transport_rtt() !=
245       nqe::internal::InvalidRTT()) {
246     Observation rtt_observation(
247         params_->DefaultObservation(current_network_id_.type)
248             .transport_rtt()
249             .InMilliseconds(),
250         tick_clock_->NowTicks(), INT32_MIN,
251         NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM);
252     AddAndNotifyObserversOfRTT(rtt_observation);
253   }
254 
255   if (params_->DefaultObservation(current_network_id_.type)
256           .downstream_throughput_kbps() !=
257       nqe::internal::INVALID_RTT_THROUGHPUT) {
258     Observation throughput_observation(
259         params_->DefaultObservation(current_network_id_.type)
260             .downstream_throughput_kbps(),
261         tick_clock_->NowTicks(), INT32_MIN,
262         NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM);
263     AddAndNotifyObserversOfThroughput(throughput_observation);
264   }
265 }
266 
~NetworkQualityEstimator()267 NetworkQualityEstimator::~NetworkQualityEstimator() {
268   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
269   NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
270   RemoveEffectiveConnectionTypeObserver(&network_congestion_analyzer_);
271 }
272 
NotifyStartTransaction(const URLRequest & request)273 void NetworkQualityEstimator::NotifyStartTransaction(
274     const URLRequest& request) {
275   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
276 
277   if (!RequestSchemeIsHTTPOrHTTPS(request))
278     return;
279 
280   // Update |estimated_quality_at_last_main_frame_| if this is a main frame
281   // request.
282   // TODO(tbansal): Refactor this to a separate method.
283   if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) {
284     base::TimeTicks now = tick_clock_->NowTicks();
285     last_main_frame_request_ = now;
286 
287     ComputeEffectiveConnectionType();
288     effective_connection_type_at_last_main_frame_ = effective_connection_type_;
289     estimated_quality_at_last_main_frame_ = network_quality_;
290   } else {
291     MaybeComputeEffectiveConnectionType();
292   }
293   throughput_analyzer_->NotifyStartTransaction(request);
294   network_congestion_analyzer_.NotifyStartTransaction(request);
295   connectivity_monitor_->TrackNewRequest(request);
296 }
297 
IsHangingRequest(base::TimeDelta observed_http_rtt) const298 bool NetworkQualityEstimator::IsHangingRequest(
299     base::TimeDelta observed_http_rtt) const {
300   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
301 
302   // If there are sufficient number of end to end RTT samples available, use
303   // the end to end RTT estimate to determine if the request is hanging.
304   // If |observed_http_rtt| is within a fixed multiplier of |end_to_end_rtt_|,
305   // then |observed_http_rtt| is determined to be not a hanging-request RTT.
306   if (params_->use_end_to_end_rtt() && end_to_end_rtt_.has_value() &&
307       end_to_end_rtt_observation_count_at_last_ect_computation_ >=
308           params_->http_rtt_transport_rtt_min_count() &&
309       params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() >
310           0 &&
311       observed_http_rtt <
312           params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() *
313               end_to_end_rtt_.value()) {
314     return false;
315   }
316 
317   DCHECK_LT(
318       0,
319       params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier());
320 
321   if (transport_rtt_observation_count_last_ect_computation_ >=
322           params_->http_rtt_transport_rtt_min_count() &&
323       (observed_http_rtt <
324        params_->hanging_request_http_rtt_upper_bound_transport_rtt_multiplier() *
325            GetTransportRTT().value_or(base::TimeDelta::FromSeconds(10)))) {
326     // If there are sufficient number of transport RTT samples available, use
327     // the transport RTT estimate to determine if the request is hanging.
328     return false;
329   }
330 
331   DCHECK_LT(
332       0, params_->hanging_request_http_rtt_upper_bound_http_rtt_multiplier());
333 
334   if (observed_http_rtt <
335       params_->hanging_request_http_rtt_upper_bound_http_rtt_multiplier() *
336           GetHttpRTT().value_or(base::TimeDelta::FromSeconds(10))) {
337     // Use the HTTP RTT estimate to determine if the request is hanging.
338     return false;
339   }
340 
341   if (observed_http_rtt <=
342       params_->hanging_request_upper_bound_min_http_rtt()) {
343     return false;
344   }
345   return true;
346 }
347 
NotifyHeadersReceived(const URLRequest & request,int64_t prefilter_total_bytes_read)348 void NetworkQualityEstimator::NotifyHeadersReceived(
349     const URLRequest& request,
350     int64_t prefilter_total_bytes_read) {
351   TRACE_EVENT0(NetTracingCategory(),
352                "NetworkQualityEstimator::NotifyHeadersReceived");
353   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
354 
355   if (!RequestSchemeIsHTTPOrHTTPS(request) ||
356       !RequestProvidesRTTObservation(request)) {
357     return;
358   }
359 
360   if (request.load_flags() & LOAD_MAIN_FRAME_DEPRECATED) {
361     ComputeEffectiveConnectionType();
362     RecordMetricsOnMainFrameRequest();
363   }
364 
365   LoadTimingInfo load_timing_info;
366   request.GetLoadTimingInfo(&load_timing_info);
367 
368   // If the load timing info is unavailable, it probably means that the request
369   // did not go over the network.
370   if (load_timing_info.send_start.is_null() ||
371       load_timing_info.receive_headers_end.is_null()) {
372     return;
373   }
374   DCHECK(!request.response_info().was_cached);
375 
376   // Duration between when the resource was requested and when the response
377   // headers were received.
378   const base::TimeDelta observed_http_rtt =
379       load_timing_info.receive_headers_end - load_timing_info.send_start;
380   if (observed_http_rtt <= base::TimeDelta())
381     return;
382   DCHECK_GE(observed_http_rtt, base::TimeDelta());
383 
384   if (IsHangingRequest(observed_http_rtt))
385     return;
386 
387   Observation http_rtt_observation(observed_http_rtt.InMilliseconds(),
388                                    tick_clock_->NowTicks(),
389                                    current_network_id_.signal_strength,
390                                    NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP);
391   AddAndNotifyObserversOfRTT(http_rtt_observation);
392   throughput_analyzer_->NotifyBytesRead(request);
393   throughput_analyzer_->NotifyExpectedResponseContentSize(
394       request, request.GetExpectedContentSize());
395   connectivity_monitor_->NotifyRequestProgress(request);
396 }
397 
NotifyBytesRead(const URLRequest & request,int64_t prefilter_total_bytes_read)398 void NetworkQualityEstimator::NotifyBytesRead(
399     const URLRequest& request,
400     int64_t prefilter_total_bytes_read) {
401   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
402   throughput_analyzer_->NotifyBytesRead(request);
403   connectivity_monitor_->NotifyRequestProgress(request);
404 }
405 
NotifyRequestCompleted(const URLRequest & request)406 void NetworkQualityEstimator::NotifyRequestCompleted(
407     const URLRequest& request) {
408   TRACE_EVENT0(NetTracingCategory(),
409                "NetworkQualityEstimator::NotifyRequestCompleted");
410   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
411 
412   if (!RequestSchemeIsHTTPOrHTTPS(request))
413     return;
414 
415   throughput_analyzer_->NotifyRequestCompleted(request);
416   network_congestion_analyzer_.NotifyRequestCompleted(request);
417   connectivity_monitor_->NotifyRequestCompleted(request);
418 }
419 
NotifyURLRequestDestroyed(const URLRequest & request)420 void NetworkQualityEstimator::NotifyURLRequestDestroyed(
421     const URLRequest& request) {
422   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
423 
424   if (!RequestSchemeIsHTTPOrHTTPS(request))
425     return;
426 
427   throughput_analyzer_->NotifyRequestCompleted(request);
428   connectivity_monitor_->NotifyRequestCompleted(request);
429 }
430 
AddRTTObserver(RTTObserver * rtt_observer)431 void NetworkQualityEstimator::AddRTTObserver(RTTObserver* rtt_observer) {
432   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
433   rtt_observer_list_.AddObserver(rtt_observer);
434 }
435 
RemoveRTTObserver(RTTObserver * rtt_observer)436 void NetworkQualityEstimator::RemoveRTTObserver(RTTObserver* rtt_observer) {
437   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
438   rtt_observer_list_.RemoveObserver(rtt_observer);
439 }
440 
AddThroughputObserver(ThroughputObserver * throughput_observer)441 void NetworkQualityEstimator::AddThroughputObserver(
442     ThroughputObserver* throughput_observer) {
443   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
444   throughput_observer_list_.AddObserver(throughput_observer);
445 }
446 
RemoveThroughputObserver(ThroughputObserver * throughput_observer)447 void NetworkQualityEstimator::RemoveThroughputObserver(
448     ThroughputObserver* throughput_observer) {
449   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
450   throughput_observer_list_.RemoveObserver(throughput_observer);
451 }
452 
453 SocketPerformanceWatcherFactory*
GetSocketPerformanceWatcherFactory()454 NetworkQualityEstimator::GetSocketPerformanceWatcherFactory() {
455   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
456 
457   return watcher_factory_.get();
458 }
459 
SetUseLocalHostRequestsForTesting(bool use_localhost_requests)460 void NetworkQualityEstimator::SetUseLocalHostRequestsForTesting(
461     bool use_localhost_requests) {
462   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
463   use_localhost_requests_ = use_localhost_requests;
464   watcher_factory_->SetUseLocalHostRequestsForTesting(use_localhost_requests_);
465   throughput_analyzer_->SetUseLocalHostRequestsForTesting(
466       use_localhost_requests_);
467 }
468 
SetUseSmallResponsesForTesting(bool use_small_responses)469 void NetworkQualityEstimator::SetUseSmallResponsesForTesting(
470     bool use_small_responses) {
471   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
472   params_->SetUseSmallResponsesForTesting(use_small_responses);
473 }
474 
DisableOfflineCheckForTesting(bool disable_offline_check)475 void NetworkQualityEstimator::DisableOfflineCheckForTesting(
476     bool disable_offline_check) {
477   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
478   disable_offline_check_ = disable_offline_check;
479 }
480 
ReportEffectiveConnectionTypeForTesting(EffectiveConnectionType effective_connection_type)481 void NetworkQualityEstimator::ReportEffectiveConnectionTypeForTesting(
482     EffectiveConnectionType effective_connection_type) {
483   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
484 
485   event_creator_.MaybeAddNetworkQualityChangedEventToNetLog(
486       effective_connection_type_,
487       params_->TypicalNetworkQuality(effective_connection_type));
488 
489   for (auto& observer : effective_connection_type_observer_list_)
490     observer.OnEffectiveConnectionTypeChanged(effective_connection_type);
491 
492   network_quality_store_->Add(current_network_id_,
493                               nqe::internal::CachedNetworkQuality(
494                                   tick_clock_->NowTicks(), network_quality_,
495                                   effective_connection_type));
496 }
497 
ReportRTTsAndThroughputForTesting(base::TimeDelta http_rtt,base::TimeDelta transport_rtt,int32_t downstream_throughput_kbps)498 void NetworkQualityEstimator::ReportRTTsAndThroughputForTesting(
499     base::TimeDelta http_rtt,
500     base::TimeDelta transport_rtt,
501     int32_t downstream_throughput_kbps) {
502   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
503 
504   for (auto& observer : rtt_and_throughput_estimates_observer_list_)
505     observer.OnRTTOrThroughputEstimatesComputed(http_rtt, transport_rtt,
506                                                 downstream_throughput_kbps);
507 }
508 
RequestProvidesRTTObservation(const URLRequest & request) const509 bool NetworkQualityEstimator::RequestProvidesRTTObservation(
510     const URLRequest& request) const {
511   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
512 
513   bool private_network_request =
514       nqe::internal::IsRequestForPrivateHost(request);
515 
516   return (use_localhost_requests_ || !private_network_request) &&
517          // Verify that response headers are received, so it can be ensured that
518          // response is not cached.
519          !request.response_info().response_time.is_null() &&
520          !request.was_cached() &&
521          request.creation_time() >= last_connection_change_ &&
522          request.method() == "GET";
523 }
524 
OnConnectionTypeChanged(NetworkChangeNotifier::ConnectionType type)525 void NetworkQualityEstimator::OnConnectionTypeChanged(
526     NetworkChangeNotifier::ConnectionType type) {
527   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
528 
529   // It's possible that |type| has the same value as |current_network_id_.type|.
530   // This can happen if the device switches from one WiFi SSID to another.
531 
532   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
533             base::size(rtt_ms_observations_));
534 
535   // Write the estimates of the previous network to the cache.
536   network_quality_store_->Add(
537       current_network_id_, nqe::internal::CachedNetworkQuality(
538                                last_effective_connection_type_computation_,
539                                network_quality_, effective_connection_type_));
540 
541   // Clear the local state.
542   last_connection_change_ = tick_clock_->NowTicks();
543   http_downstream_throughput_kbps_observations_.Clear();
544   for (int i = 0; i < nqe::internal::OBSERVATION_CATEGORY_COUNT; ++i)
545     rtt_ms_observations_[i].Clear();
546 
547 #if defined(OS_ANDROID)
548 
549   bool is_cell_connection =
550       NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type);
551   bool is_wifi_connection =
552       (current_network_id_.type == NetworkChangeNotifier::CONNECTION_WIFI);
553 
554   if (params_->weight_multiplier_per_signal_strength_level() < 1.0 &&
555       (is_cell_connection || is_wifi_connection)) {
556     bool signal_strength_available =
557         min_signal_strength_since_connection_change_ &&
558         max_signal_strength_since_connection_change_;
559 
560     std::string histogram_name =
561         is_cell_connection ? "NQE.CellularSignalStrength.LevelAvailable"
562                            : "NQE.WifiSignalStrength.LevelAvailable";
563 
564     base::UmaHistogramBoolean(histogram_name, signal_strength_available);
565   }
566 #endif  // OS_ANDROID
567   current_network_id_.signal_strength = INT32_MIN;
568   min_signal_strength_since_connection_change_.reset();
569   max_signal_strength_since_connection_change_.reset();
570   network_quality_ = nqe::internal::NetworkQuality();
571   end_to_end_rtt_ = base::nullopt;
572   effective_connection_type_ = EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
573   effective_connection_type_at_last_main_frame_ =
574       EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
575   rtt_observations_size_at_last_ect_computation_ = 0;
576   throughput_observations_size_at_last_ect_computation_ = 0;
577   new_rtt_observations_since_last_ect_computation_ = 0;
578   new_throughput_observations_since_last_ect_computation_ = 0;
579   transport_rtt_observation_count_last_ect_computation_ = 0;
580   end_to_end_rtt_observation_count_at_last_ect_computation_ = 0;
581   last_socket_watcher_rtt_notification_ = base::TimeTicks();
582   estimated_quality_at_last_main_frame_ = nqe::internal::NetworkQuality();
583   cached_estimate_applied_ = false;
584 
585   GatherEstimatesForNextConnectionType();
586   throughput_analyzer_->OnConnectionTypeChanged();
587   connectivity_monitor_->NotifyConnectionTypeChanged(type);
588 }
589 
GatherEstimatesForNextConnectionType()590 void NetworkQualityEstimator::GatherEstimatesForNextConnectionType() {
591   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
592 
593 #if defined(OS_CHROMEOS)
594   if (get_network_id_asynchronously_) {
595     // Doing PostTaskAndReplyWithResult by handle because it requires the result
596     // type have a default constructor and nqe::internal::NetworkID does not
597     // have that.
598     g_get_network_id_task_runner.Get()->PostTask(
599         FROM_HERE,
600         base::BindOnce(
601             [](scoped_refptr<base::TaskRunner> reply_task_runner,
602                base::OnceCallback<void(const nqe::internal::NetworkID&)>
603                    reply_callback) {
604               reply_task_runner->PostTask(
605                   FROM_HERE, base::BindOnce(std::move(reply_callback),
606                                             DoGetCurrentNetworkID(nullptr)));
607             },
608             base::ThreadTaskRunnerHandle::Get(),
609             base::BindOnce(&NetworkQualityEstimator::
610                                ContinueGatherEstimatesForNextConnectionType,
611                            weak_ptr_factory_.GetWeakPtr())));
612     return;
613   }
614 #endif  // defined(OS_CHROMEOS)
615 
616   ContinueGatherEstimatesForNextConnectionType(GetCurrentNetworkID());
617 }
618 
ContinueGatherEstimatesForNextConnectionType(const nqe::internal::NetworkID & network_id)619 void NetworkQualityEstimator::ContinueGatherEstimatesForNextConnectionType(
620     const nqe::internal::NetworkID& network_id) {
621   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
622   // Update the local state as part of preparation for the new connection.
623   current_network_id_ = network_id;
624   RecordNetworkIDAvailability();
625 
626   // Read any cached estimates for the new network. If cached estimates are
627   // unavailable, add the default estimates.
628   if (!ReadCachedNetworkQualityEstimate())
629     AddDefaultEstimates();
630 
631   ComputeEffectiveConnectionType();
632 }
633 
634 base::Optional<int32_t>
GetCurrentSignalStrengthWithThrottling()635 NetworkQualityEstimator::GetCurrentSignalStrengthWithThrottling() {
636   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
637 
638   if (!params_->get_signal_strength_and_detailed_network_id())
639     return base::nullopt;
640 
641   if (params_->weight_multiplier_per_signal_strength_level() >= 1.0)
642     return base::nullopt;
643 
644   if ((current_network_id_.type != NetworkChangeNotifier::CONNECTION_WIFI) &&
645       !NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) {
646     return base::nullopt;
647   }
648 
649   // Do not call more than once per |wifi_signal_strength_query_interval|
650   // duration.
651   if (last_signal_strength_check_timestamp_.has_value() &&
652       (tick_clock_->NowTicks() - last_signal_strength_check_timestamp_.value() <
653        params_->wifi_signal_strength_query_interval()) &&
654       (last_signal_strength_check_timestamp_.value() >
655        last_connection_change_)) {
656     return base::nullopt;
657   }
658 
659   last_signal_strength_check_timestamp_ = tick_clock_->NowTicks();
660 
661   if (current_network_id_.type == NetworkChangeNotifier::CONNECTION_WIFI) {
662     UMA_HISTOGRAM_BOOLEAN("NQE.SignalStrengthQueried.WiFi", true);
663 
664 #if defined(OS_ANDROID)
665     return android::GetWifiSignalLevel();
666 #endif  // OS_ANDROID
667   }
668 
669   if (NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) {
670     UMA_HISTOGRAM_BOOLEAN("NQE.SignalStrengthQueried.Cellular", true);
671 #if defined(OS_ANDROID)
672     return android::cellular_signal_strength::GetSignalStrengthLevel();
673 #endif  // OS_ANDROID
674   }
675 
676   return base::nullopt;
677 }
678 
UpdateSignalStrength()679 void NetworkQualityEstimator::UpdateSignalStrength() {
680   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
681 
682   int32_t past_signal_strength = current_network_id_.signal_strength;
683   base::Optional<int32_t> new_signal_strength =
684       GetCurrentSignalStrengthWithThrottling();
685 
686   // A fresh value is unavailable. So, return early.
687   if (!new_signal_strength)
688     return;
689 
690   // Check if there is no change in the signal strength.
691   if (past_signal_strength == new_signal_strength.value())
692     return;
693 
694   // Check if the signal strength is unavailable.
695   if (new_signal_strength.value() == INT32_MIN)
696     return;
697 
698   DCHECK(new_signal_strength.value() >= 0 && new_signal_strength.value() <= 4);
699 
700   // Record the network quality we experienced for the previous signal strength
701   // (for when we return to that signal strength).
702   network_quality_store_->Add(current_network_id_,
703                               nqe::internal::CachedNetworkQuality(
704                                   tick_clock_->NowTicks(), network_quality_,
705                                   effective_connection_type_));
706 
707   current_network_id_.signal_strength = new_signal_strength.value();
708   // Update network quality from cached value for new signal strength.
709   ReadCachedNetworkQualityEstimate();
710 
711   min_signal_strength_since_connection_change_ =
712       std::min(min_signal_strength_since_connection_change_.value_or(INT32_MAX),
713                current_network_id_.signal_strength);
714   max_signal_strength_since_connection_change_ =
715       std::max(max_signal_strength_since_connection_change_.value_or(INT32_MIN),
716                current_network_id_.signal_strength);
717 }
718 
RecordNetworkIDAvailability() const719 void NetworkQualityEstimator::RecordNetworkIDAvailability() const {
720   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
721   if (current_network_id_.type ==
722           NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI ||
723       NetworkChangeNotifier::IsConnectionCellular(current_network_id_.type)) {
724     UMA_HISTOGRAM_BOOLEAN("NQE.NetworkIdAvailable",
725                           !current_network_id_.id.empty());
726   }
727 }
728 
RecordMetricsOnMainFrameRequest() const729 void NetworkQualityEstimator::RecordMetricsOnMainFrameRequest() const {
730   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
731 
732   if (estimated_quality_at_last_main_frame_.http_rtt() !=
733       nqe::internal::InvalidRTT()) {
734     // Add the 50th percentile value.
735     LOCAL_HISTOGRAM_TIMES("NQE.MainFrame.RTT.Percentile50",
736                           estimated_quality_at_last_main_frame_.http_rtt());
737   }
738 
739   if (estimated_quality_at_last_main_frame_.transport_rtt() !=
740       nqe::internal::InvalidRTT()) {
741     // Add the 50th percentile value.
742     LOCAL_HISTOGRAM_TIMES(
743         "NQE.MainFrame.TransportRTT.Percentile50",
744         estimated_quality_at_last_main_frame_.transport_rtt());
745   }
746 
747   if (estimated_quality_at_last_main_frame_.downstream_throughput_kbps() !=
748       nqe::internal::INVALID_RTT_THROUGHPUT) {
749     // Add the 50th percentile value.
750     LOCAL_HISTOGRAM_COUNTS_1000000(
751         "NQE.MainFrame.Kbps.Percentile50",
752         estimated_quality_at_last_main_frame_.downstream_throughput_kbps());
753   }
754 
755   LOCAL_HISTOGRAM_ENUMERATION("NQE.MainFrame.EffectiveConnectionType",
756                               effective_connection_type_at_last_main_frame_,
757                               EFFECTIVE_CONNECTION_TYPE_LAST);
758 }
759 
ShouldComputeNetworkQueueingDelay() const760 bool NetworkQualityEstimator::ShouldComputeNetworkQueueingDelay() const {
761   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
762 
763   const base::TimeTicks now = tick_clock_->NowTicks();
764   // Recomputes the queueing delay estimate if |queueing_delay_update_interval_|
765   // has passed.
766   return (now - last_queueing_delay_computation_ >=
767           queueing_delay_update_interval_);
768 }
769 
ComputeNetworkQueueingDelay()770 void NetworkQualityEstimator::ComputeNetworkQueueingDelay() {
771   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
772 
773   if (!ShouldComputeNetworkQueueingDelay())
774     return;
775 
776   const base::TimeTicks now = tick_clock_->NowTicks();
777   last_queueing_delay_computation_ = now;
778   // The time after which observations are considered as recent data.
779   const base::TimeTicks recent_start_time =
780       now - base::TimeDelta::FromMilliseconds(1000);
781   // The time after which observations are considered as historical data.
782   const base::TimeTicks historical_start_time =
783       now - base::TimeDelta::FromMilliseconds(30000);
784 
785   // Checks if a valid downlink throughput estimation is available.
786   int32_t downlink_kbps = 0;
787   if (!GetRecentDownlinkThroughputKbps(recent_start_time, &downlink_kbps))
788     downlink_kbps = nqe::internal::INVALID_RTT_THROUGHPUT;
789 
790   // Gets recent RTT statistic values.
791   std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats>
792       recent_rtt_stats =
793           rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT]
794               .GetCanonicalStatsKeyedByHosts(recent_start_time,
795                                              std::set<nqe::internal::IPHash>());
796 
797   if (recent_rtt_stats.empty())
798     return;
799 
800   // Gets the set of active hosts. Only computes the historical stats for recent
801   // active hosts.
802   std::set<nqe::internal::IPHash> active_hosts;
803   for (const auto& host_stat : recent_rtt_stats)
804     active_hosts.insert(host_stat.first);
805 
806   std::map<nqe::internal::IPHash, nqe::internal::CanonicalStats>
807       historical_rtt_stats =
808           rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT]
809               .GetCanonicalStatsKeyedByHosts(historical_start_time,
810                                              active_hosts);
811 
812   network_congestion_analyzer_.ComputeRecentQueueingDelay(
813       recent_rtt_stats, historical_rtt_stats, downlink_kbps);
814 
815   // Gets the total number of inflight requests including hanging GETs. The app
816   // cannot determine whether a request is hanging or is still in the wire.
817   size_t count_inflight_requests =
818       throughput_analyzer_->CountTotalInFlightRequests();
819 
820   // Tracks the mapping between the peak observed queueing delay to the peak
821   // count of in-flight requests.
822   network_congestion_analyzer_.UpdatePeakDelayMapping(
823       network_congestion_analyzer_.recent_queueing_delay(),
824       count_inflight_requests);
825 }
826 
ComputeEffectiveConnectionType()827 void NetworkQualityEstimator::ComputeEffectiveConnectionType() {
828   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
829 
830   UpdateSignalStrength();
831 
832   const base::TimeTicks now = tick_clock_->NowTicks();
833 
834   const EffectiveConnectionType past_type = effective_connection_type_;
835   last_effective_connection_type_computation_ = now;
836 
837   base::TimeDelta http_rtt = nqe::internal::InvalidRTT();
838   base::TimeDelta transport_rtt = nqe::internal::InvalidRTT();
839   base::TimeDelta end_to_end_rtt = nqe::internal::InvalidRTT();
840   int32_t downstream_throughput_kbps = nqe::internal::INVALID_RTT_THROUGHPUT;
841 
842   effective_connection_type_ = GetRecentEffectiveConnectionTypeUsingMetrics(
843       &http_rtt, &transport_rtt, &end_to_end_rtt, &downstream_throughput_kbps,
844       &transport_rtt_observation_count_last_ect_computation_,
845       &end_to_end_rtt_observation_count_at_last_ect_computation_);
846 
847   network_quality_ = nqe::internal::NetworkQuality(http_rtt, transport_rtt,
848                                                    downstream_throughput_kbps);
849   net::EffectiveConnectionType signal_strength_capped_ect =
850       GetCappedECTBasedOnSignalStrength();
851 
852   if (signal_strength_capped_ect != effective_connection_type_) {
853     DCHECK_LE(signal_strength_capped_ect, effective_connection_type_);
854     UMA_HISTOGRAM_EXACT_LINEAR(
855         "NQE.CellularSignalStrength.ECTReduction",
856         effective_connection_type_ - signal_strength_capped_ect,
857         static_cast<int>(EFFECTIVE_CONNECTION_TYPE_LAST));
858 
859     effective_connection_type_ = signal_strength_capped_ect;
860 
861     // Reset |network_quality_| based on the updated effective connection type.
862     network_quality_ = nqe::internal::NetworkQuality(
863         params_->TypicalNetworkQuality(effective_connection_type_).http_rtt(),
864         params_->TypicalNetworkQuality(effective_connection_type_)
865             .transport_rtt(),
866         params_->TypicalNetworkQuality(effective_connection_type_)
867             .downstream_throughput_kbps());
868   }
869 
870   ClampKbpsBasedOnEct();
871 
872   UMA_HISTOGRAM_ENUMERATION("NQE.EffectiveConnectionType.OnECTComputation",
873                             effective_connection_type_,
874                             EFFECTIVE_CONNECTION_TYPE_LAST);
875   if (network_quality_.http_rtt() != nqe::internal::InvalidRTT()) {
876     UMA_HISTOGRAM_TIMES("NQE.RTT.OnECTComputation",
877                         network_quality_.http_rtt());
878   }
879 
880   if (network_quality_.transport_rtt() != nqe::internal::InvalidRTT()) {
881     UMA_HISTOGRAM_TIMES("NQE.TransportRTT.OnECTComputation",
882                         network_quality_.transport_rtt());
883   }
884 
885   if (end_to_end_rtt != nqe::internal::InvalidRTT()) {
886     UMA_HISTOGRAM_TIMES("NQE.EndToEndRTT.OnECTComputation", end_to_end_rtt);
887   }
888   end_to_end_rtt_ = base::nullopt;
889   if (end_to_end_rtt != nqe::internal::InvalidRTT())
890     end_to_end_rtt_ = end_to_end_rtt;
891 
892   if (network_quality_.downstream_throughput_kbps() !=
893       nqe::internal::INVALID_RTT_THROUGHPUT) {
894     UMA_HISTOGRAM_COUNTS_1M("NQE.Kbps.OnECTComputation",
895                             network_quality_.downstream_throughput_kbps());
896   }
897 
898   NotifyObserversOfRTTOrThroughputComputed();
899 
900   if (past_type != effective_connection_type_)
901     NotifyObserversOfEffectiveConnectionTypeChanged();
902 
903   event_creator_.MaybeAddNetworkQualityChangedEventToNetLog(
904       effective_connection_type_, network_quality_);
905 
906   rtt_observations_size_at_last_ect_computation_ =
907       rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_HTTP].Size() +
908       rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT]
909           .Size();
910   throughput_observations_size_at_last_ect_computation_ =
911       http_downstream_throughput_kbps_observations_.Size();
912   new_rtt_observations_since_last_ect_computation_ = 0;
913   new_throughput_observations_since_last_ect_computation_ = 0;
914 }
915 
916 base::Optional<net::EffectiveConnectionType>
GetOverrideECT() const917 NetworkQualityEstimator::GetOverrideECT() const {
918   return base::nullopt;
919 }
920 
ClampKbpsBasedOnEct()921 void NetworkQualityEstimator::ClampKbpsBasedOnEct() {
922   // No need to clamp when ECT is unknown or if the connection speed is fast.
923   if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
924       effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_OFFLINE ||
925       effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_4G) {
926     return;
927   }
928 
929   if (params_->upper_bound_typical_kbps_multiplier() <= 0.0)
930     return;
931 
932   DCHECK_LT(0, params_->TypicalNetworkQuality(effective_connection_type_)
933                    .downstream_throughput_kbps());
934   // For a given ECT, upper bound on Kbps can't be less than the typical Kbps
935   // for that ECT.
936   DCHECK_LE(1.0, params_->upper_bound_typical_kbps_multiplier());
937 
938   DCHECK(effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_SLOW_2G ||
939          effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_2G ||
940          effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_3G);
941 
942   // Put an upper bound on Kbps.
943   network_quality_.set_downstream_throughput_kbps(
944       std::min(network_quality_.downstream_throughput_kbps(),
945                static_cast<int>(
946                    params_->TypicalNetworkQuality(effective_connection_type_)
947                        .downstream_throughput_kbps() *
948                    params_->upper_bound_typical_kbps_multiplier())));
949 }
950 
951 EffectiveConnectionType
GetCappedECTBasedOnSignalStrength() const952 NetworkQualityEstimator::GetCappedECTBasedOnSignalStrength() const {
953   if (!params_->cap_ect_based_on_signal_strength())
954     return effective_connection_type_;
955 
956   // Check if signal strength is available.
957   if (current_network_id_.signal_strength == INT32_MIN)
958     return effective_connection_type_;
959 
960   if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
961       effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
962     return effective_connection_type_;
963   }
964 
965   // Do not cap ECT if the signal strength is high.
966   if (current_network_id_.signal_strength > 2)
967     return effective_connection_type_;
968 
969   DCHECK_LE(0, current_network_id_.signal_strength);
970 
971   // When signal strength is 0, the device is almost offline.
972   if (current_network_id_.signal_strength == 0) {
973     switch (current_network_id_.type) {
974       case NetworkChangeNotifier::CONNECTION_2G:
975       case NetworkChangeNotifier::CONNECTION_3G:
976         return std::min(effective_connection_type_,
977                         EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
978       case NetworkChangeNotifier::CONNECTION_4G:
979       case NetworkChangeNotifier::CONNECTION_5G:
980       case NetworkChangeNotifier::CONNECTION_WIFI:
981         return std::min(effective_connection_type_,
982                         EFFECTIVE_CONNECTION_TYPE_2G);
983       default:
984         NOTREACHED();
985         return effective_connection_type_;
986     }
987   }
988 
989   if (current_network_id_.signal_strength == 1) {
990     switch (current_network_id_.type) {
991       case NetworkChangeNotifier::CONNECTION_2G:
992         return std::min(effective_connection_type_,
993                         EFFECTIVE_CONNECTION_TYPE_SLOW_2G);
994       case NetworkChangeNotifier::CONNECTION_3G:
995         return std::min(effective_connection_type_,
996                         EFFECTIVE_CONNECTION_TYPE_2G);
997       case NetworkChangeNotifier::CONNECTION_4G:
998       case NetworkChangeNotifier::CONNECTION_5G:
999       case NetworkChangeNotifier::CONNECTION_WIFI:
1000         return std::min(effective_connection_type_,
1001                         EFFECTIVE_CONNECTION_TYPE_3G);
1002       default:
1003         NOTREACHED();
1004         return effective_connection_type_;
1005     }
1006   }
1007 
1008   if (current_network_id_.signal_strength == 2) {
1009     switch (current_network_id_.type) {
1010       case NetworkChangeNotifier::CONNECTION_2G:
1011         return std::min(effective_connection_type_,
1012                         EFFECTIVE_CONNECTION_TYPE_2G);
1013       case NetworkChangeNotifier::CONNECTION_3G:
1014         return std::min(effective_connection_type_,
1015                         EFFECTIVE_CONNECTION_TYPE_3G);
1016       case NetworkChangeNotifier::CONNECTION_4G:
1017       case NetworkChangeNotifier::CONNECTION_5G:
1018       case NetworkChangeNotifier::CONNECTION_WIFI:
1019         return std::min(effective_connection_type_,
1020                         EFFECTIVE_CONNECTION_TYPE_4G);
1021       default:
1022         NOTREACHED();
1023         return effective_connection_type_;
1024     }
1025   }
1026   NOTREACHED();
1027   return effective_connection_type_;
1028 }
1029 
GetEffectiveConnectionType() const1030 EffectiveConnectionType NetworkQualityEstimator::GetEffectiveConnectionType()
1031     const {
1032   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1033 
1034   base::Optional<net::EffectiveConnectionType> override_ect = GetOverrideECT();
1035   if (override_ect) {
1036     return override_ect.value();
1037   }
1038   return effective_connection_type_;
1039 }
1040 
UpdateHttpRttUsingAllRttValues(base::TimeDelta * http_rtt,const base::TimeDelta transport_rtt,const base::TimeDelta end_to_end_rtt) const1041 void NetworkQualityEstimator::UpdateHttpRttUsingAllRttValues(
1042     base::TimeDelta* http_rtt,
1043     const base::TimeDelta transport_rtt,
1044     const base::TimeDelta end_to_end_rtt) const {
1045   DCHECK(http_rtt);
1046 
1047   // Use transport RTT to clamp the lower bound on HTTP RTT.
1048   // To improve accuracy, the transport RTT estimate is used only when the
1049   // transport RTT estimate was computed using at least
1050   // |params_->http_rtt_transport_rtt_min_count()| observations.
1051   if (*http_rtt != nqe::internal::InvalidRTT() &&
1052       transport_rtt != nqe::internal::InvalidRTT() &&
1053       transport_rtt_observation_count_last_ect_computation_ >=
1054           params_->http_rtt_transport_rtt_min_count() &&
1055       params_->lower_bound_http_rtt_transport_rtt_multiplier() > 0) {
1056     *http_rtt =
1057         std::max(*http_rtt,
1058                  transport_rtt *
1059                      params_->lower_bound_http_rtt_transport_rtt_multiplier());
1060   }
1061 
1062   // Put lower bound on |http_rtt| using |end_to_end_rtt|.
1063   if (*http_rtt != nqe::internal::InvalidRTT() &&
1064       params_->use_end_to_end_rtt() &&
1065       end_to_end_rtt != nqe::internal::InvalidRTT() &&
1066       end_to_end_rtt_observation_count_at_last_ect_computation_ >=
1067           params_->http_rtt_transport_rtt_min_count() &&
1068       params_->lower_bound_http_rtt_transport_rtt_multiplier() > 0) {
1069     *http_rtt =
1070         std::max(*http_rtt,
1071                  end_to_end_rtt *
1072                      params_->lower_bound_http_rtt_transport_rtt_multiplier());
1073   }
1074 
1075   // Put upper bound on |http_rtt| using |end_to_end_rtt|.
1076   if (*http_rtt != nqe::internal::InvalidRTT() &&
1077       params_->use_end_to_end_rtt() &&
1078       end_to_end_rtt != nqe::internal::InvalidRTT() &&
1079       end_to_end_rtt_observation_count_at_last_ect_computation_ >=
1080           params_->http_rtt_transport_rtt_min_count() &&
1081       params_->upper_bound_http_rtt_endtoend_rtt_multiplier() > 0) {
1082     *http_rtt = std::min(
1083         *http_rtt, end_to_end_rtt *
1084                        params_->upper_bound_http_rtt_endtoend_rtt_multiplier());
1085   }
1086 }
1087 
1088 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) const1089 NetworkQualityEstimator::GetRecentEffectiveConnectionTypeUsingMetrics(
1090     base::TimeDelta* http_rtt,
1091     base::TimeDelta* transport_rtt,
1092     base::TimeDelta* end_to_end_rtt,
1093     int32_t* downstream_throughput_kbps,
1094     size_t* transport_rtt_observation_count,
1095     size_t* end_to_end_rtt_observation_count) const {
1096   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1097 
1098   *http_rtt = nqe::internal::InvalidRTT();
1099   *transport_rtt = nqe::internal::InvalidRTT();
1100   *end_to_end_rtt = nqe::internal::InvalidRTT();
1101   *downstream_throughput_kbps = nqe::internal::INVALID_RTT_THROUGHPUT;
1102 
1103   auto forced_ect =
1104       params_->GetForcedEffectiveConnectionType(current_network_id_.type);
1105   if (forced_ect) {
1106     *http_rtt = params_->TypicalNetworkQuality(forced_ect.value()).http_rtt();
1107     *transport_rtt =
1108         params_->TypicalNetworkQuality(forced_ect.value()).transport_rtt();
1109     *downstream_throughput_kbps =
1110         params_->TypicalNetworkQuality(forced_ect.value())
1111             .downstream_throughput_kbps();
1112     return forced_ect.value();
1113   }
1114 
1115   // If the device is currently offline, then return
1116   // EFFECTIVE_CONNECTION_TYPE_OFFLINE.
1117   if (current_network_id_.type == NetworkChangeNotifier::CONNECTION_NONE &&
1118       !disable_offline_check_) {
1119     return EFFECTIVE_CONNECTION_TYPE_OFFLINE;
1120   }
1121 
1122   if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_HTTP, base::TimeTicks(),
1123                     http_rtt, nullptr)) {
1124     *http_rtt = nqe::internal::InvalidRTT();
1125   }
1126 
1127   if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_TRANSPORT,
1128                     base::TimeTicks(), transport_rtt,
1129                     transport_rtt_observation_count)) {
1130     *transport_rtt = nqe::internal::InvalidRTT();
1131   }
1132 
1133   if (!GetRecentRTT(nqe::internal::OBSERVATION_CATEGORY_END_TO_END,
1134                     base::TimeTicks(), end_to_end_rtt,
1135                     end_to_end_rtt_observation_count)) {
1136     *end_to_end_rtt = nqe::internal::InvalidRTT();
1137   }
1138 
1139   UpdateHttpRttUsingAllRttValues(http_rtt, *transport_rtt, *end_to_end_rtt);
1140 
1141   if (!GetRecentDownlinkThroughputKbps(base::TimeTicks(),
1142                                        downstream_throughput_kbps)) {
1143     *downstream_throughput_kbps = nqe::internal::INVALID_RTT_THROUGHPUT;
1144   }
1145 
1146   if (*http_rtt == nqe::internal::InvalidRTT()) {
1147     return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
1148   }
1149 
1150   if (*http_rtt == nqe::internal::InvalidRTT() &&
1151       *transport_rtt == nqe::internal::InvalidRTT() &&
1152       *downstream_throughput_kbps == nqe::internal::INVALID_RTT_THROUGHPUT) {
1153     // None of the metrics are available.
1154     return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
1155   }
1156 
1157   // Search from the slowest connection type to the fastest to find the
1158   // EffectiveConnectionType that best matches the current connection's
1159   // performance. The match is done by comparing RTT and throughput.
1160   for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
1161     EffectiveConnectionType type = static_cast<EffectiveConnectionType>(i);
1162     if (i == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
1163       continue;
1164 
1165     const bool estimated_http_rtt_is_higher_than_threshold =
1166         *http_rtt != nqe::internal::InvalidRTT() &&
1167         params_->ConnectionThreshold(type).http_rtt() !=
1168             nqe::internal::InvalidRTT() &&
1169         *http_rtt >= params_->ConnectionThreshold(type).http_rtt();
1170 
1171     if (estimated_http_rtt_is_higher_than_threshold)
1172       return type;
1173   }
1174   // Return the fastest connection type.
1175   return static_cast<EffectiveConnectionType>(EFFECTIVE_CONNECTION_TYPE_LAST -
1176                                               1);
1177 }
1178 
AddEffectiveConnectionTypeObserver(EffectiveConnectionTypeObserver * observer)1179 void NetworkQualityEstimator::AddEffectiveConnectionTypeObserver(
1180     EffectiveConnectionTypeObserver* observer) {
1181   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1182   DCHECK(observer);
1183   effective_connection_type_observer_list_.AddObserver(observer);
1184 
1185   // Notify the |observer| on the next message pump since |observer| may not
1186   // be completely set up for receiving the callbacks.
1187   base::ThreadTaskRunnerHandle::Get()->PostTask(
1188       FROM_HERE,
1189       base::BindOnce(&NetworkQualityEstimator::
1190                          NotifyEffectiveConnectionTypeObserverIfPresent,
1191                      weak_ptr_factory_.GetWeakPtr(), observer));
1192 }
1193 
RemoveEffectiveConnectionTypeObserver(EffectiveConnectionTypeObserver * observer)1194 void NetworkQualityEstimator::RemoveEffectiveConnectionTypeObserver(
1195     EffectiveConnectionTypeObserver* observer) {
1196   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1197   effective_connection_type_observer_list_.RemoveObserver(observer);
1198 }
1199 
AddPeerToPeerConnectionsCountObserver(PeerToPeerConnectionsCountObserver * observer)1200 void NetworkQualityEstimator::AddPeerToPeerConnectionsCountObserver(
1201     PeerToPeerConnectionsCountObserver* observer) {
1202   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1203   DCHECK(observer);
1204   peer_to_peer_type_observer_list_.AddObserver(observer);
1205 
1206   // Notify the |observer| on the next message pump since |observer| may not
1207   // be completely set up for receiving the callbacks.
1208   base::ThreadTaskRunnerHandle::Get()->PostTask(
1209       FROM_HERE,
1210       base::BindOnce(&NetworkQualityEstimator::
1211                          NotifyPeerToPeerConnectionsCountObserverIfPresent,
1212                      weak_ptr_factory_.GetWeakPtr(), observer));
1213 }
1214 
RemovePeerToPeerConnectionsCountObserver(PeerToPeerConnectionsCountObserver * observer)1215 void NetworkQualityEstimator::RemovePeerToPeerConnectionsCountObserver(
1216     PeerToPeerConnectionsCountObserver* observer) {
1217   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1218   peer_to_peer_type_observer_list_.RemoveObserver(observer);
1219 }
1220 
AddRTTAndThroughputEstimatesObserver(RTTAndThroughputEstimatesObserver * observer)1221 void NetworkQualityEstimator::AddRTTAndThroughputEstimatesObserver(
1222     RTTAndThroughputEstimatesObserver* observer) {
1223   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1224   DCHECK(observer);
1225   rtt_and_throughput_estimates_observer_list_.AddObserver(observer);
1226 
1227   // Notify the |observer| on the next message pump since |observer| may not
1228   // be completely set up for receiving the callbacks.
1229   base::ThreadTaskRunnerHandle::Get()->PostTask(
1230       FROM_HERE,
1231       base::BindOnce(&NetworkQualityEstimator::
1232                          NotifyRTTAndThroughputEstimatesObserverIfPresent,
1233                      weak_ptr_factory_.GetWeakPtr(), observer));
1234 }
1235 
RemoveRTTAndThroughputEstimatesObserver(RTTAndThroughputEstimatesObserver * observer)1236 void NetworkQualityEstimator::RemoveRTTAndThroughputEstimatesObserver(
1237     RTTAndThroughputEstimatesObserver* observer) {
1238   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1239   rtt_and_throughput_estimates_observer_list_.RemoveObserver(observer);
1240 }
1241 
GetRecentRTT(nqe::internal::ObservationCategory observation_category,const base::TimeTicks & start_time,base::TimeDelta * rtt,size_t * observations_count) const1242 bool NetworkQualityEstimator::GetRecentRTT(
1243     nqe::internal::ObservationCategory observation_category,
1244     const base::TimeTicks& start_time,
1245     base::TimeDelta* rtt,
1246     size_t* observations_count) const {
1247   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1248   *rtt = GetRTTEstimateInternal(start_time, observation_category, 50,
1249                                 observations_count);
1250   return (*rtt != nqe::internal::InvalidRTT());
1251 }
1252 
GetRecentDownlinkThroughputKbps(const base::TimeTicks & start_time,int32_t * kbps) const1253 bool NetworkQualityEstimator::GetRecentDownlinkThroughputKbps(
1254     const base::TimeTicks& start_time,
1255     int32_t* kbps) const {
1256   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1257   *kbps = GetDownlinkThroughputKbpsEstimateInternal(start_time, 50);
1258   return (*kbps != nqe::internal::INVALID_RTT_THROUGHPUT);
1259 }
1260 
GetRTTEstimateInternal(base::TimeTicks start_time,nqe::internal::ObservationCategory observation_category,int percentile,size_t * observations_count) const1261 base::TimeDelta NetworkQualityEstimator::GetRTTEstimateInternal(
1262     base::TimeTicks start_time,
1263     nqe::internal::ObservationCategory observation_category,
1264     int percentile,
1265     size_t* observations_count) const {
1266   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1267   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
1268             base::size(rtt_ms_observations_));
1269 
1270   // RTT observations are sorted by duration from shortest to longest, thus
1271   // a higher percentile RTT will have a longer RTT than a lower percentile.
1272   switch (observation_category) {
1273     case nqe::internal::OBSERVATION_CATEGORY_HTTP:
1274     case nqe::internal::OBSERVATION_CATEGORY_TRANSPORT:
1275     case nqe::internal::OBSERVATION_CATEGORY_END_TO_END:
1276       return base::TimeDelta::FromMilliseconds(
1277           rtt_ms_observations_[observation_category]
1278               .GetPercentile(start_time, current_network_id_.signal_strength,
1279                              percentile, observations_count)
1280               .value_or(nqe::internal::INVALID_RTT_THROUGHPUT));
1281     case nqe::internal::OBSERVATION_CATEGORY_COUNT:
1282       NOTREACHED();
1283       return base::TimeDelta();
1284   }
1285 }
1286 
GetDownlinkThroughputKbpsEstimateInternal(const base::TimeTicks & start_time,int percentile) const1287 int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal(
1288     const base::TimeTicks& start_time,
1289     int percentile) const {
1290   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1291 
1292   // Throughput observations are sorted by kbps from slowest to fastest,
1293   // thus a higher percentile throughput will be faster than a lower one.
1294   return http_downstream_throughput_kbps_observations_
1295       .GetPercentile(start_time, current_network_id_.signal_strength,
1296                      100 - percentile, nullptr)
1297       .value_or(nqe::internal::INVALID_RTT_THROUGHPUT);
1298 }
1299 
GetCurrentNetworkID() const1300 nqe::internal::NetworkID NetworkQualityEstimator::GetCurrentNetworkID() const {
1301   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1302 
1303   // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class
1304   // that overrides this method on the Android platform.
1305 
1306   return DoGetCurrentNetworkID(params_.get());
1307 }
1308 
ReadCachedNetworkQualityEstimate()1309 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
1310   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1311 
1312   if (!params_->persistent_cache_reading_enabled())
1313     return false;
1314 
1315   nqe::internal::CachedNetworkQuality cached_network_quality;
1316 
1317   const bool cached_estimate_available = network_quality_store_->GetById(
1318       current_network_id_, &cached_network_quality);
1319   UMA_HISTOGRAM_BOOLEAN("NQE.CachedNetworkQualityAvailable",
1320                         cached_estimate_available);
1321 
1322   if (!cached_estimate_available)
1323     return false;
1324 
1325   EffectiveConnectionType effective_connection_type =
1326       cached_network_quality.effective_connection_type();
1327 
1328   if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
1329       effective_connection_type == EFFECTIVE_CONNECTION_TYPE_OFFLINE ||
1330       effective_connection_type == EFFECTIVE_CONNECTION_TYPE_LAST) {
1331     return false;
1332   }
1333 
1334   nqe::internal::NetworkQuality network_quality =
1335       cached_network_quality.network_quality();
1336 
1337   bool update_network_quality_store = false;
1338 
1339   // Populate |network_quality| with synthetic RTT and throughput observations
1340   // if they are missing.
1341   if (network_quality.http_rtt().InMilliseconds() ==
1342       nqe::internal::INVALID_RTT_THROUGHPUT) {
1343     network_quality.set_http_rtt(
1344         params_->TypicalNetworkQuality(effective_connection_type).http_rtt());
1345     update_network_quality_store = true;
1346   }
1347 
1348   if (network_quality.transport_rtt().InMilliseconds() ==
1349       nqe::internal::INVALID_RTT_THROUGHPUT) {
1350     network_quality.set_transport_rtt(
1351         params_->TypicalNetworkQuality(effective_connection_type)
1352             .transport_rtt());
1353     update_network_quality_store = true;
1354   }
1355 
1356   if (network_quality.downstream_throughput_kbps() ==
1357       nqe::internal::INVALID_RTT_THROUGHPUT) {
1358     network_quality.set_downstream_throughput_kbps(
1359         params_->TypicalNetworkQuality(effective_connection_type)
1360             .downstream_throughput_kbps());
1361     update_network_quality_store = true;
1362   }
1363 
1364   if (update_network_quality_store) {
1365     network_quality_store_->Add(current_network_id_,
1366                                 nqe::internal::CachedNetworkQuality(
1367                                     tick_clock_->NowTicks(), network_quality,
1368                                     effective_connection_type));
1369   }
1370 
1371   Observation http_rtt_observation(
1372       network_quality.http_rtt().InMilliseconds(), tick_clock_->NowTicks(),
1373       INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE);
1374   AddAndNotifyObserversOfRTT(http_rtt_observation);
1375 
1376   Observation transport_rtt_observation(
1377       network_quality.transport_rtt().InMilliseconds(), tick_clock_->NowTicks(),
1378       INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE);
1379   AddAndNotifyObserversOfRTT(transport_rtt_observation);
1380 
1381   Observation througphput_observation(
1382       network_quality.downstream_throughput_kbps(), tick_clock_->NowTicks(),
1383       INT32_MIN, NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE);
1384   AddAndNotifyObserversOfThroughput(througphput_observation);
1385 
1386   ComputeEffectiveConnectionType();
1387   return true;
1388 }
1389 
SetTickClockForTesting(const base::TickClock * tick_clock)1390 void NetworkQualityEstimator::SetTickClockForTesting(
1391     const base::TickClock* tick_clock) {
1392   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1393   tick_clock_ = tick_clock;
1394   for (int i = 0; i < nqe::internal::OBSERVATION_CATEGORY_COUNT; ++i)
1395     rtt_ms_observations_[i].SetTickClockForTesting(tick_clock_);
1396   http_downstream_throughput_kbps_observations_.SetTickClockForTesting(
1397       tick_clock_);
1398   throughput_analyzer_->SetTickClockForTesting(tick_clock_);
1399   watcher_factory_->SetTickClockForTesting(tick_clock_);
1400 }
1401 
OnUpdatedTransportRTTAvailable(SocketPerformanceWatcherFactory::Protocol protocol,const base::TimeDelta & rtt,const base::Optional<nqe::internal::IPHash> & host)1402 void NetworkQualityEstimator::OnUpdatedTransportRTTAvailable(
1403     SocketPerformanceWatcherFactory::Protocol protocol,
1404     const base::TimeDelta& rtt,
1405     const base::Optional<nqe::internal::IPHash>& host) {
1406   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1407   DCHECK_LT(nqe::internal::INVALID_RTT_THROUGHPUT, rtt.InMilliseconds());
1408   Observation observation(rtt.InMilliseconds(), tick_clock_->NowTicks(),
1409                           current_network_id_.signal_strength,
1410                           ProtocolSourceToObservationSource(protocol), host);
1411   AddAndNotifyObserversOfRTT(observation);
1412 
1413   ComputeNetworkQueueingDelay();
1414 }
1415 
AddAndNotifyObserversOfRTT(const Observation & observation)1416 void NetworkQualityEstimator::AddAndNotifyObserversOfRTT(
1417     const Observation& observation) {
1418   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1419   DCHECK_NE(nqe::internal::InvalidRTT(),
1420             base::TimeDelta::FromMilliseconds(observation.value()));
1421   DCHECK_GT(NETWORK_QUALITY_OBSERVATION_SOURCE_MAX, observation.source());
1422 
1423   if (!ShouldAddObservation(observation))
1424     return;
1425 
1426   MaybeUpdateCachedEstimateApplied(
1427       observation,
1428       &rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_HTTP]);
1429   MaybeUpdateCachedEstimateApplied(
1430       observation,
1431       &rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT]);
1432   ++new_rtt_observations_since_last_ect_computation_;
1433 
1434   std::vector<nqe::internal::ObservationCategory> observation_categories =
1435       observation.GetObservationCategories();
1436   for (nqe::internal::ObservationCategory observation_category :
1437        observation_categories) {
1438     rtt_ms_observations_[observation_category].AddObservation(observation);
1439   }
1440 
1441   if (observation.source() == NETWORK_QUALITY_OBSERVATION_SOURCE_TCP ||
1442       observation.source() == NETWORK_QUALITY_OBSERVATION_SOURCE_QUIC) {
1443     last_socket_watcher_rtt_notification_ = tick_clock_->NowTicks();
1444   }
1445 
1446   UMA_HISTOGRAM_ENUMERATION("NQE.RTT.ObservationSource", observation.source(),
1447                             NETWORK_QUALITY_OBSERVATION_SOURCE_MAX);
1448 
1449   // Maybe recompute the effective connection type since a new RTT observation
1450   // is available.
1451   if (observation.source() !=
1452           NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE &&
1453       observation.source() !=
1454           NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE) {
1455     MaybeComputeEffectiveConnectionType();
1456   }
1457   for (auto& observer : rtt_observer_list_) {
1458     observer.OnRTTObservation(observation.value(), observation.timestamp(),
1459                               observation.source());
1460   }
1461 }
1462 
AddAndNotifyObserversOfThroughput(const Observation & observation)1463 void NetworkQualityEstimator::AddAndNotifyObserversOfThroughput(
1464     const Observation& observation) {
1465   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1466   DCHECK_NE(nqe::internal::INVALID_RTT_THROUGHPUT, observation.value());
1467   DCHECK_GT(NETWORK_QUALITY_OBSERVATION_SOURCE_MAX, observation.source());
1468   DCHECK_EQ(1u, observation.GetObservationCategories().size());
1469   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_HTTP,
1470             observation.GetObservationCategories().front());
1471 
1472   if (!ShouldAddObservation(observation))
1473     return;
1474 
1475   MaybeUpdateCachedEstimateApplied(
1476       observation, &http_downstream_throughput_kbps_observations_);
1477   ++new_throughput_observations_since_last_ect_computation_;
1478   http_downstream_throughput_kbps_observations_.AddObservation(observation);
1479 
1480   LOCAL_HISTOGRAM_ENUMERATION("NQE.Kbps.ObservationSource",
1481                               observation.source(),
1482                               NETWORK_QUALITY_OBSERVATION_SOURCE_MAX);
1483 
1484   // Maybe recompute the effective connection type since a new throughput
1485   // observation is available.
1486   if (observation.source() !=
1487           NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE &&
1488       observation.source() !=
1489           NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE) {
1490     MaybeComputeEffectiveConnectionType();
1491   }
1492   for (auto& observer : throughput_observer_list_) {
1493     observer.OnThroughputObservation(
1494         observation.value(), observation.timestamp(), observation.source());
1495   }
1496 }
1497 
OnNewThroughputObservationAvailable(int32_t downstream_kbps)1498 void NetworkQualityEstimator::OnNewThroughputObservationAvailable(
1499     int32_t downstream_kbps) {
1500   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1501 
1502   if (downstream_kbps <= 0)
1503     return;
1504 
1505   DCHECK_NE(nqe::internal::INVALID_RTT_THROUGHPUT, downstream_kbps);
1506 
1507   Observation throughput_observation(downstream_kbps, tick_clock_->NowTicks(),
1508                                      current_network_id_.signal_strength,
1509                                      NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP);
1510   AddAndNotifyObserversOfThroughput(throughput_observation);
1511 }
1512 
ShouldComputeEffectiveConnectionType() const1513 bool NetworkQualityEstimator::ShouldComputeEffectiveConnectionType() const {
1514   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1515   DCHECK_EQ(nqe::internal::OBSERVATION_CATEGORY_COUNT,
1516             base::size(rtt_ms_observations_));
1517 
1518   const base::TimeTicks now = tick_clock_->NowTicks();
1519   // Recompute effective connection type only if
1520   // |effective_connection_type_recomputation_interval_| has passed since it was
1521   // last computed or a connection change event was observed since the last
1522   // computation. Strict inequalities are used to ensure that effective
1523   // connection type is recomputed on connection change events even if the clock
1524   // has not updated.
1525   if (now - last_effective_connection_type_computation_ >=
1526       effective_connection_type_recomputation_interval_) {
1527     return true;
1528   }
1529 
1530   if (last_connection_change_ >= last_effective_connection_type_computation_) {
1531     return true;
1532   }
1533 
1534   // Recompute the effective connection type if the previously computed
1535   // effective connection type was unknown.
1536   if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN) {
1537     return true;
1538   }
1539 
1540   // Recompute the effective connection type if the number of samples
1541   // available now are 50% more than the number of samples that were
1542   // available when the effective connection type was last computed.
1543   if (rtt_observations_size_at_last_ect_computation_ * 1.5 <
1544       (rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_HTTP].Size() +
1545        rtt_ms_observations_[nqe::internal::OBSERVATION_CATEGORY_TRANSPORT]
1546            .Size())) {
1547     return true;
1548   }
1549 
1550   if (throughput_observations_size_at_last_ect_computation_ * 1.5 <
1551       http_downstream_throughput_kbps_observations_.Size()) {
1552     return true;
1553   }
1554 
1555   if ((new_rtt_observations_since_last_ect_computation_ +
1556        new_throughput_observations_since_last_ect_computation_) >=
1557       params_->count_new_observations_received_compute_ect()) {
1558     return true;
1559   }
1560   return false;
1561 }
1562 
MaybeComputeEffectiveConnectionType()1563 void NetworkQualityEstimator::MaybeComputeEffectiveConnectionType() {
1564   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1565 
1566   if (!ShouldComputeEffectiveConnectionType())
1567     return;
1568   ComputeEffectiveConnectionType();
1569 }
1570 
1571 void NetworkQualityEstimator::
NotifyObserversOfEffectiveConnectionTypeChanged()1572     NotifyObserversOfEffectiveConnectionTypeChanged() {
1573   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1574   DCHECK_NE(EFFECTIVE_CONNECTION_TYPE_LAST, effective_connection_type_);
1575 
1576   base::Optional<net::EffectiveConnectionType> override_ect = GetOverrideECT();
1577 
1578   // TODO(tbansal): Add hysteresis in the notification.
1579   for (auto& observer : effective_connection_type_observer_list_)
1580     observer.OnEffectiveConnectionTypeChanged(
1581         override_ect ? override_ect.value() : effective_connection_type_);
1582   // Add the estimates of the current network to the cache store.
1583   network_quality_store_->Add(current_network_id_,
1584                               nqe::internal::CachedNetworkQuality(
1585                                   tick_clock_->NowTicks(), network_quality_,
1586                                   effective_connection_type_));
1587 }
1588 
NotifyObserversOfRTTOrThroughputComputed() const1589 void NetworkQualityEstimator::NotifyObserversOfRTTOrThroughputComputed() const {
1590   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1591 
1592   // TODO(tbansal): Add hysteresis in the notification.
1593   for (auto& observer : rtt_and_throughput_estimates_observer_list_) {
1594     observer.OnRTTOrThroughputEstimatesComputed(
1595         network_quality_.http_rtt(), network_quality_.transport_rtt(),
1596         network_quality_.downstream_throughput_kbps());
1597   }
1598 }
1599 
NotifyEffectiveConnectionTypeObserverIfPresent(EffectiveConnectionTypeObserver * observer) const1600 void NetworkQualityEstimator::NotifyEffectiveConnectionTypeObserverIfPresent(
1601     EffectiveConnectionTypeObserver* observer) const {
1602   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1603 
1604   if (!effective_connection_type_observer_list_.HasObserver(observer))
1605     return;
1606 
1607   base::Optional<net::EffectiveConnectionType> override_ect = GetOverrideECT();
1608   if (override_ect) {
1609     observer->OnEffectiveConnectionTypeChanged(override_ect.value());
1610     return;
1611   }
1612   if (effective_connection_type_ == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
1613     return;
1614   observer->OnEffectiveConnectionTypeChanged(effective_connection_type_);
1615 }
1616 
NotifyPeerToPeerConnectionsCountObserverIfPresent(PeerToPeerConnectionsCountObserver * observer) const1617 void NetworkQualityEstimator::NotifyPeerToPeerConnectionsCountObserverIfPresent(
1618     PeerToPeerConnectionsCountObserver* observer) const {
1619   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1620 
1621   if (!peer_to_peer_type_observer_list_.HasObserver(observer))
1622     return;
1623   observer->OnPeerToPeerConnectionsCountChange(p2p_connections_count_);
1624 }
1625 
NotifyRTTAndThroughputEstimatesObserverIfPresent(RTTAndThroughputEstimatesObserver * observer) const1626 void NetworkQualityEstimator::NotifyRTTAndThroughputEstimatesObserverIfPresent(
1627     RTTAndThroughputEstimatesObserver* observer) const {
1628   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1629 
1630   if (!rtt_and_throughput_estimates_observer_list_.HasObserver(observer))
1631     return;
1632   observer->OnRTTOrThroughputEstimatesComputed(
1633       network_quality_.http_rtt(), network_quality_.transport_rtt(),
1634       network_quality_.downstream_throughput_kbps());
1635 }
1636 
AddNetworkQualitiesCacheObserver(nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver * observer)1637 void NetworkQualityEstimator::AddNetworkQualitiesCacheObserver(
1638     nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
1639         observer) {
1640   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1641   network_quality_store_->AddNetworkQualitiesCacheObserver(observer);
1642 }
1643 
RemoveNetworkQualitiesCacheObserver(nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver * observer)1644 void NetworkQualityEstimator::RemoveNetworkQualitiesCacheObserver(
1645     nqe::internal::NetworkQualityStore::NetworkQualitiesCacheObserver*
1646         observer) {
1647   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1648   network_quality_store_->RemoveNetworkQualitiesCacheObserver(observer);
1649 }
1650 
OnPrefsRead(const std::map<nqe::internal::NetworkID,nqe::internal::CachedNetworkQuality> read_prefs)1651 void NetworkQualityEstimator::OnPrefsRead(
1652     const std::map<nqe::internal::NetworkID,
1653                    nqe::internal::CachedNetworkQuality> read_prefs) {
1654   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1655 
1656   UMA_HISTOGRAM_COUNTS_1M("NQE.Prefs.ReadSize", read_prefs.size());
1657   for (auto& it : read_prefs) {
1658     EffectiveConnectionType effective_connection_type =
1659         it.second.effective_connection_type();
1660     if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN ||
1661         effective_connection_type == EFFECTIVE_CONNECTION_TYPE_OFFLINE) {
1662       continue;
1663     }
1664 
1665     // RTT and throughput values are not set in the prefs.
1666     DCHECK_EQ(nqe::internal::InvalidRTT(),
1667               it.second.network_quality().http_rtt());
1668     DCHECK_EQ(nqe::internal::InvalidRTT(),
1669               it.second.network_quality().transport_rtt());
1670     DCHECK_EQ(nqe::internal::INVALID_RTT_THROUGHPUT,
1671               it.second.network_quality().downstream_throughput_kbps());
1672 
1673     nqe::internal::CachedNetworkQuality cached_network_quality(
1674         tick_clock_->NowTicks(),
1675         params_->TypicalNetworkQuality(effective_connection_type),
1676         effective_connection_type);
1677 
1678     network_quality_store_->Add(it.first, cached_network_quality);
1679   }
1680   ReadCachedNetworkQualityEstimate();
1681 }
1682 
1683 #if defined(OS_CHROMEOS)
EnableGetNetworkIdAsynchronously()1684 void NetworkQualityEstimator::EnableGetNetworkIdAsynchronously() {
1685   get_network_id_asynchronously_ = true;
1686 }
1687 #endif  // defined(OS_CHROMEOS)
1688 
GetHttpRTT() const1689 base::Optional<base::TimeDelta> NetworkQualityEstimator::GetHttpRTT() const {
1690   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1691 
1692   if (network_quality_.http_rtt() == nqe::internal::InvalidRTT())
1693     return base::Optional<base::TimeDelta>();
1694   return network_quality_.http_rtt();
1695 }
1696 
GetTransportRTT() const1697 base::Optional<base::TimeDelta> NetworkQualityEstimator::GetTransportRTT()
1698     const {
1699   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1700 
1701   if (network_quality_.transport_rtt() == nqe::internal::InvalidRTT())
1702     return base::Optional<base::TimeDelta>();
1703   return network_quality_.transport_rtt();
1704 }
1705 
GetDownstreamThroughputKbps() const1706 base::Optional<int32_t> NetworkQualityEstimator::GetDownstreamThroughputKbps()
1707     const {
1708   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1709 
1710   if (network_quality_.downstream_throughput_kbps() ==
1711       nqe::internal::INVALID_RTT_THROUGHPUT) {
1712     return base::Optional<int32_t>();
1713   }
1714   return network_quality_.downstream_throughput_kbps();
1715 }
1716 
MaybeUpdateCachedEstimateApplied(const Observation & observation,ObservationBuffer * buffer)1717 void NetworkQualityEstimator::MaybeUpdateCachedEstimateApplied(
1718     const Observation& observation,
1719     ObservationBuffer* buffer) {
1720   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1721   if (observation.source() !=
1722           NETWORK_QUALITY_OBSERVATION_SOURCE_HTTP_CACHED_ESTIMATE &&
1723       observation.source() !=
1724           NETWORK_QUALITY_OBSERVATION_SOURCE_TRANSPORT_CACHED_ESTIMATE) {
1725     return;
1726   }
1727 
1728   cached_estimate_applied_ = true;
1729   bool deleted_observation_sources[NETWORK_QUALITY_OBSERVATION_SOURCE_MAX] = {
1730       false};
1731   deleted_observation_sources
1732       [NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM] = true;
1733   deleted_observation_sources
1734       [NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM] =
1735           true;
1736 
1737   buffer->RemoveObservationsWithSource(deleted_observation_sources);
1738 }
1739 
ShouldAddObservation(const Observation & observation) const1740 bool NetworkQualityEstimator::ShouldAddObservation(
1741     const Observation& observation) const {
1742   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1743 
1744   if (cached_estimate_applied_ &&
1745       (observation.source() ==
1746            NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_HTTP_FROM_PLATFORM ||
1747        observation.source() ==
1748            NETWORK_QUALITY_OBSERVATION_SOURCE_DEFAULT_TRANSPORT_FROM_PLATFORM)) {
1749     return false;
1750   }
1751   return true;
1752 }
1753 
ShouldSocketWatcherNotifyRTT(base::TimeTicks now)1754 bool NetworkQualityEstimator::ShouldSocketWatcherNotifyRTT(
1755     base::TimeTicks now) {
1756   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1757   return (now - last_socket_watcher_rtt_notification_ >=
1758           params_->socket_watchers_min_notification_interval());
1759 }
1760 
SimulateNetworkQualityChangeForTesting(net::EffectiveConnectionType type)1761 void NetworkQualityEstimator::SimulateNetworkQualityChangeForTesting(
1762     net::EffectiveConnectionType type) {
1763   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1764   params_->SetForcedEffectiveConnectionTypeForTesting(type);
1765   ComputeEffectiveConnectionType();
1766 }
1767 
RecordSpdyPingLatency(const HostPortPair & host_port_pair,base::TimeDelta rtt)1768 void NetworkQualityEstimator::RecordSpdyPingLatency(
1769     const HostPortPair& host_port_pair,
1770     base::TimeDelta rtt) {
1771   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1772   DCHECK_LT(nqe::internal::INVALID_RTT_THROUGHPUT, rtt.InMilliseconds());
1773 
1774   Observation observation(rtt.InMilliseconds(), tick_clock_->NowTicks(),
1775                           current_network_id_.signal_strength,
1776                           NETWORK_QUALITY_OBSERVATION_SOURCE_H2_PINGS);
1777   AddAndNotifyObserversOfRTT(observation);
1778 }
1779 
OnPeerToPeerConnectionsCountChange(uint32_t count)1780 void NetworkQualityEstimator::OnPeerToPeerConnectionsCountChange(
1781     uint32_t count) {
1782   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1783 
1784   if (p2p_connections_count_ == count)
1785     return;
1786 
1787   if (p2p_connections_count_ == 0 && count > 0) {
1788     DCHECK(!p2p_connections_count_active_timestamp_);
1789     p2p_connections_count_active_timestamp_ = tick_clock_->NowTicks();
1790   }
1791 
1792   if (p2p_connections_count_ > 0 && count == 0) {
1793     DCHECK(p2p_connections_count_active_timestamp_);
1794     base::TimeDelta duration = tick_clock_->NowTicks() -
1795                                p2p_connections_count_active_timestamp_.value();
1796     LOCAL_HISTOGRAM_CUSTOM_TIMES("NQE.PeerToPeerConnectionsDuration", duration,
1797                                  base::TimeDelta::FromMilliseconds(1),
1798                                  base::TimeDelta::FromHours(1), 50);
1799     p2p_connections_count_active_timestamp_ = base::nullopt;
1800   }
1801 
1802   p2p_connections_count_ = count;
1803 
1804   for (auto& observer : peer_to_peer_type_observer_list_) {
1805     observer.OnPeerToPeerConnectionsCountChange(p2p_connections_count_);
1806   }
1807 }
1808 
GetPeerToPeerConnectionsCountChange() const1809 uint32_t NetworkQualityEstimator::GetPeerToPeerConnectionsCountChange() const {
1810   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
1811   return p2p_connections_count_;
1812 }
1813 
1814 }  // namespace net
1815