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