Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(55)

Side by Side Diff: net/base/network_quality_estimator.cc

Issue 1898603002: Move Network Quality Estimator files to //net/nqe (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebased, removed //net/socket/OWNERS Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/base/network_quality_estimator.h ('k') | net/base/network_quality_estimator_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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/base/network_quality_estimator.h"
6
7 #include <float.h>
8 #include <algorithm>
9 #include <cmath>
10 #include <limits>
11 #include <utility>
12 #include <vector>
13
14 #include "base/logging.h"
15 #include "base/metrics/histogram.h"
16 #include "base/metrics/histogram_base.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "base/trace_event/trace_event.h"
20 #include "build/build_config.h"
21 #include "net/base/load_flags.h"
22 #include "net/base/load_timing_info.h"
23 #include "net/base/network_interfaces.h"
24 #include "net/base/socket_performance_watcher.h"
25 #include "net/base/url_util.h"
26 #include "net/url_request/url_request.h"
27 #include "url/gurl.h"
28
29 #if defined(OS_ANDROID)
30 #include "net/android/network_library.h"
31 #endif // OS_ANDROID
32
33 namespace {
34
35 // Default value of the half life (in seconds) for computing time weighted
36 // percentiles. Every half life, the weight of all observations reduces by
37 // half. Lowering the half life would reduce the weight of older values faster.
38 const int kDefaultHalfLifeSeconds = 60;
39
40 // Name of the variation parameter that holds the value of the half life (in
41 // seconds) of the observations.
42 const char kHalfLifeSecondsParamName[] = "HalfLifeSeconds";
43
44 // Returns a descriptive name corresponding to |connection_type|.
45 const char* GetNameForConnectionType(
46 net::NetworkChangeNotifier::ConnectionType connection_type) {
47 switch (connection_type) {
48 case net::NetworkChangeNotifier::CONNECTION_UNKNOWN:
49 return "Unknown";
50 case net::NetworkChangeNotifier::CONNECTION_ETHERNET:
51 return "Ethernet";
52 case net::NetworkChangeNotifier::CONNECTION_WIFI:
53 return "WiFi";
54 case net::NetworkChangeNotifier::CONNECTION_2G:
55 return "2G";
56 case net::NetworkChangeNotifier::CONNECTION_3G:
57 return "3G";
58 case net::NetworkChangeNotifier::CONNECTION_4G:
59 return "4G";
60 case net::NetworkChangeNotifier::CONNECTION_NONE:
61 return "None";
62 case net::NetworkChangeNotifier::CONNECTION_BLUETOOTH:
63 return "Bluetooth";
64 default:
65 NOTREACHED();
66 break;
67 }
68 return "";
69 }
70
71 // Suffix of the name of the variation parameter that contains the default RTT
72 // observation (in milliseconds). Complete name of the variation parameter
73 // would be |ConnectionType|.|kDefaultRTTMsecObservationSuffix| where
74 // |ConnectionType| is from |kConnectionTypeNames|. For example, variation
75 // parameter for Wi-Fi would be "WiFi.DefaultMedianRTTMsec".
76 const char kDefaultRTTMsecObservationSuffix[] = ".DefaultMedianRTTMsec";
77
78 // Suffix of the name of the variation parameter that contains the default
79 // downstream throughput observation (in Kbps). Complete name of the variation
80 // parameter would be |ConnectionType|.|kDefaultKbpsObservationSuffix| where
81 // |ConnectionType| is from |kConnectionTypeNames|. For example, variation
82 // parameter for Wi-Fi would be "WiFi.DefaultMedianKbps".
83 const char kDefaultKbpsObservationSuffix[] = ".DefaultMedianKbps";
84
85 // Suffix of the name of the variation parameter that contains the threshold
86 // RTTs (in milliseconds) for different effective connection types. Complete
87 // name of the variation parameter would be
88 // |EffectiveConnectionType|.|kThresholdURLRTTMsecSuffix|.
89 const char kThresholdURLRTTMsecSuffix[] = ".ThresholdMedianURLRTTMsec";
90
91 // Suffix of the name of the variation parameter that contains the threshold
92 // downlink throughput (in kbps) for different effective connection types.
93 // Complete name of the variation parameter would be
94 // |EffectiveConnectionType|.|kThresholdKbpsSuffix|.
95 const char kThresholdKbpsSuffix[] = ".ThresholdMedianKbps";
96
97 // Computes and returns the weight multiplier per second.
98 // |variation_params| is the map containing all field trial parameters
99 // related to NetworkQualityEstimator field trial.
100 double GetWeightMultiplierPerSecond(
101 const std::map<std::string, std::string>& variation_params) {
102 int half_life_seconds = kDefaultHalfLifeSeconds;
103 int32_t variations_value = 0;
104 auto it = variation_params.find(kHalfLifeSecondsParamName);
105 if (it != variation_params.end() &&
106 base::StringToInt(it->second, &variations_value) &&
107 variations_value >= 1) {
108 half_life_seconds = variations_value;
109 }
110 DCHECK_GT(half_life_seconds, 0);
111 return exp(log(0.5) / half_life_seconds);
112 }
113
114 // Returns the histogram that should be used to record the given statistic.
115 // |max_limit| is the maximum value that can be stored in the histogram.
116 base::HistogramBase* GetHistogram(
117 const std::string& statistic_name,
118 net::NetworkChangeNotifier::ConnectionType type,
119 int32_t max_limit) {
120 const base::LinearHistogram::Sample kLowerLimit = 1;
121 DCHECK_GT(max_limit, kLowerLimit);
122 const size_t kBucketCount = 50;
123
124 // Prefix of network quality estimator histograms.
125 const char prefix[] = "NQE.";
126 return base::Histogram::FactoryGet(
127 prefix + statistic_name + GetNameForConnectionType(type), kLowerLimit,
128 max_limit, kBucketCount, base::HistogramBase::kUmaTargetedHistogramFlag);
129 }
130
131 bool GetValueForVariationParam(
132 const std::map<std::string, std::string>& variation_params,
133 const std::string& parameter_name,
134 int32_t* variations_value) {
135 auto it = variation_params.find(parameter_name);
136 return it != variation_params.end() &&
137 base::StringToInt(it->second, variations_value);
138 }
139
140 } // namespace
141
142 namespace net {
143
144 // SocketWatcher implements SocketPerformanceWatcher, and notifies
145 // NetworkQualityEstimator of various socket performance events. SocketWatcher
146 // is not thread-safe.
147 class NetworkQualityEstimator::SocketWatcher : public SocketPerformanceWatcher {
148 public:
149 SocketWatcher(
150 SocketPerformanceWatcherFactory::Protocol protocol,
151 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
152 const base::WeakPtr<NetworkQualityEstimator>& network_quality_estimator)
153 : protocol_(protocol),
154 task_runner_(std::move(task_runner)),
155 network_quality_estimator_(network_quality_estimator) {}
156
157 ~SocketWatcher() override {}
158
159 // SocketPerformanceWatcher implementation:
160 bool ShouldNotifyUpdatedRTT() const override {
161 DCHECK(thread_checker_.CalledOnValidThread());
162
163 return true;
164 }
165
166 void OnUpdatedRTTAvailable(const base::TimeDelta& rtt) override {
167 DCHECK(thread_checker_.CalledOnValidThread());
168
169 task_runner_->PostTask(
170 FROM_HERE, base::Bind(&NetworkQualityEstimator::OnUpdatedRTTAvailable,
171 network_quality_estimator_, protocol_, rtt));
172 }
173
174 void OnConnectionChanged() override {
175 DCHECK(thread_checker_.CalledOnValidThread());
176 }
177
178 private:
179 // Transport layer protocol used by the socket that |this| is watching.
180 const SocketPerformanceWatcherFactory::Protocol protocol_;
181
182 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
183
184 base::WeakPtr<NetworkQualityEstimator> network_quality_estimator_;
185
186 base::ThreadChecker thread_checker_;
187
188 DISALLOW_COPY_AND_ASSIGN(SocketWatcher);
189 };
190
191 // SocketWatcherFactory implements SocketPerformanceWatcherFactory, and is
192 // owned by NetworkQualityEstimator. SocketWatcherFactory is thread safe.
193 class NetworkQualityEstimator::SocketWatcherFactory
194 : public SocketPerformanceWatcherFactory {
195 public:
196 SocketWatcherFactory(
197 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
198 const base::WeakPtr<NetworkQualityEstimator>& network_quality_estimator)
199 : task_runner_(std::move(task_runner)),
200 network_quality_estimator_(network_quality_estimator) {}
201
202 ~SocketWatcherFactory() override {}
203
204 // SocketPerformanceWatcherFactory implementation:
205 std::unique_ptr<SocketPerformanceWatcher> CreateSocketPerformanceWatcher(
206 const Protocol protocol) override {
207 return std::unique_ptr<SocketPerformanceWatcher>(
208 new SocketWatcher(protocol, task_runner_, network_quality_estimator_));
209 }
210
211 private:
212 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
213
214 base::WeakPtr<NetworkQualityEstimator> network_quality_estimator_;
215
216 DISALLOW_COPY_AND_ASSIGN(SocketWatcherFactory);
217 };
218
219 const int32_t NetworkQualityEstimator::kInvalidThroughput = 0;
220
221 NetworkQualityEstimator::NetworkQualityEstimator(
222 std::unique_ptr<ExternalEstimateProvider> external_estimates_provider,
223 const std::map<std::string, std::string>& variation_params)
224 : NetworkQualityEstimator(std::move(external_estimates_provider),
225 variation_params,
226 false,
227 false) {}
228
229 NetworkQualityEstimator::NetworkQualityEstimator(
230 std::unique_ptr<ExternalEstimateProvider> external_estimates_provider,
231 const std::map<std::string, std::string>& variation_params,
232 bool allow_local_host_requests_for_tests,
233 bool allow_smaller_responses_for_tests)
234 : allow_localhost_requests_(allow_local_host_requests_for_tests),
235 allow_small_responses_(allow_smaller_responses_for_tests),
236 weight_multiplier_per_second_(
237 GetWeightMultiplierPerSecond(variation_params)),
238 last_connection_change_(base::TimeTicks::Now()),
239 current_network_id_(
240 NetworkID(NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN,
241 std::string())),
242 downstream_throughput_kbps_observations_(weight_multiplier_per_second_),
243 rtt_observations_(weight_multiplier_per_second_),
244 external_estimate_provider_(std::move(external_estimates_provider)),
245 weak_ptr_factory_(this) {
246 static_assert(kMinRequestDurationMicroseconds > 0,
247 "Minimum request duration must be > 0");
248 static_assert(kDefaultHalfLifeSeconds > 0,
249 "Default half life duration must be > 0");
250 static_assert(kMaximumNetworkQualityCacheSize > 0,
251 "Size of the network quality cache must be > 0");
252 // This limit should not be increased unless the logic for removing the
253 // oldest cache entry is rewritten to use a doubly-linked-list LRU queue.
254 static_assert(kMaximumNetworkQualityCacheSize <= 10,
255 "Size of the network quality cache must <= 10");
256
257 ObtainOperatingParams(variation_params);
258 ObtainEffectiveConnectionTypeModelParams(variation_params);
259 NetworkChangeNotifier::AddConnectionTypeObserver(this);
260 if (external_estimate_provider_) {
261 RecordExternalEstimateProviderMetrics(
262 EXTERNAL_ESTIMATE_PROVIDER_STATUS_AVAILABLE);
263 external_estimate_provider_->SetUpdatedEstimateDelegate(this);
264 QueryExternalEstimateProvider();
265 } else {
266 RecordExternalEstimateProviderMetrics(
267 EXTERNAL_ESTIMATE_PROVIDER_STATUS_NOT_AVAILABLE);
268 }
269 current_network_id_ = GetCurrentNetworkID();
270 AddDefaultEstimates();
271
272 watcher_factory_.reset(new SocketWatcherFactory(
273 base::ThreadTaskRunnerHandle::Get(), weak_ptr_factory_.GetWeakPtr()));
274 }
275
276 // static
277 const base::TimeDelta NetworkQualityEstimator::InvalidRTT() {
278 return base::TimeDelta::Max();
279 }
280
281 void NetworkQualityEstimator::ObtainOperatingParams(
282 const std::map<std::string, std::string>& variation_params) {
283 DCHECK(thread_checker_.CalledOnValidThread());
284
285 for (size_t i = 0; i <= NetworkChangeNotifier::CONNECTION_LAST; ++i) {
286 NetworkChangeNotifier::ConnectionType type =
287 static_cast<NetworkChangeNotifier::ConnectionType>(i);
288 DCHECK_EQ(InvalidRTT(), default_observations_[i].rtt());
289 DCHECK_EQ(kInvalidThroughput,
290 default_observations_[i].downstream_throughput_kbps());
291 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1;
292 // Name of the parameter that holds the RTT value for this connection type.
293 std::string rtt_parameter_name =
294 std::string(GetNameForConnectionType(type))
295 .append(kDefaultRTTMsecObservationSuffix);
296 auto it = variation_params.find(rtt_parameter_name);
297 if (it != variation_params.end() &&
298 base::StringToInt(it->second, &variations_value) &&
299 variations_value >= kMinimumRTTVariationParameterMsec) {
300 default_observations_[i] =
301 NetworkQuality(base::TimeDelta::FromMilliseconds(variations_value),
302 default_observations_[i].downstream_throughput_kbps());
303 }
304
305 variations_value = kMinimumThroughputVariationParameterKbps - 1;
306 // Name of the parameter that holds the Kbps value for this connection
307 // type.
308 std::string kbps_parameter_name =
309 std::string(GetNameForConnectionType(type))
310 .append(kDefaultKbpsObservationSuffix);
311 it = variation_params.find(kbps_parameter_name);
312 if (it != variation_params.end() &&
313 base::StringToInt(it->second, &variations_value) &&
314 variations_value >= kMinimumThroughputVariationParameterKbps) {
315 default_observations_[i] =
316 NetworkQuality(default_observations_[i].rtt(), variations_value);
317 }
318 }
319 }
320
321 void NetworkQualityEstimator::ObtainEffectiveConnectionTypeModelParams(
322 const std::map<std::string, std::string>& variation_params) {
323 DCHECK(thread_checker_.CalledOnValidThread());
324
325 for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
326 EffectiveConnectionType effective_connection_type =
327 static_cast<EffectiveConnectionType>(i);
328 DCHECK_EQ(InvalidRTT(), connection_thresholds_[i].rtt());
329 DCHECK_EQ(kInvalidThroughput,
330 connection_thresholds_[i].downstream_throughput_kbps());
331 if (effective_connection_type == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
332 continue;
333
334 std::string connection_type_name = std::string(
335 GetNameForEffectiveConnectionType(effective_connection_type));
336
337 int32_t variations_value = kMinimumRTTVariationParameterMsec - 1;
338 if (GetValueForVariationParam(
339 variation_params, connection_type_name + kThresholdURLRTTMsecSuffix,
340 &variations_value) &&
341 variations_value >= kMinimumRTTVariationParameterMsec) {
342 base::TimeDelta rtt(base::TimeDelta::FromMilliseconds(variations_value));
343 connection_thresholds_[i] = NetworkQuality(
344 rtt, connection_thresholds_[i].downstream_throughput_kbps());
345
346 // Verify that the RTT values are in decreasing order as the network
347 // quality improves.
348 DCHECK(i == 0 || connection_thresholds_[i - 1].rtt() == InvalidRTT() ||
349 rtt <= connection_thresholds_[i - 1].rtt());
350 }
351
352 variations_value = kMinimumThroughputVariationParameterKbps - 1;
353 if (GetValueForVariationParam(variation_params,
354 connection_type_name + kThresholdKbpsSuffix,
355 &variations_value) &&
356 variations_value >= kMinimumThroughputVariationParameterKbps) {
357 int32_t throughput_kbps = variations_value;
358 connection_thresholds_[i] =
359 NetworkQuality(connection_thresholds_[i].rtt(), throughput_kbps);
360
361 // Verify that the throughput values are in increasing order as the
362 // network quality improves.
363 DCHECK(i == 0 ||
364 connection_thresholds_[i - 1].downstream_throughput_kbps() ==
365 kMinimumThroughputVariationParameterKbps ||
366 throughput_kbps >=
367 connection_thresholds_[i - 1].downstream_throughput_kbps());
368 }
369 }
370 }
371
372 void NetworkQualityEstimator::AddDefaultEstimates() {
373 DCHECK(thread_checker_.CalledOnValidThread());
374 if (default_observations_[current_network_id_.type].rtt() != InvalidRTT()) {
375 RttObservation rtt_observation(
376 default_observations_[current_network_id_.type].rtt(),
377 base::TimeTicks::Now(), DEFAULT_FROM_PLATFORM);
378 rtt_observations_.AddObservation(rtt_observation);
379 NotifyObserversOfRTT(rtt_observation);
380 }
381 if (default_observations_[current_network_id_.type]
382 .downstream_throughput_kbps() != kInvalidThroughput) {
383 ThroughputObservation throughput_observation(
384 default_observations_[current_network_id_.type]
385 .downstream_throughput_kbps(),
386 base::TimeTicks::Now(), DEFAULT_FROM_PLATFORM);
387 downstream_throughput_kbps_observations_.AddObservation(
388 throughput_observation);
389 NotifyObserversOfThroughput(throughput_observation);
390 }
391 }
392
393 NetworkQualityEstimator::~NetworkQualityEstimator() {
394 DCHECK(thread_checker_.CalledOnValidThread());
395 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
396 }
397
398 void NetworkQualityEstimator::NotifyHeadersReceived(const URLRequest& request) {
399 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("net"),
400 "NetworkQualityEstimator::NotifyHeadersReceived");
401 DCHECK(thread_checker_.CalledOnValidThread());
402
403 if (!RequestProvidesUsefulObservations(request))
404 return;
405
406 // Update |estimated_median_network_quality_| if this is a main frame request.
407 if (request.load_flags() & LOAD_MAIN_FRAME) {
408 base::TimeDelta rtt;
409 if (!GetURLRequestRTTEstimate(&rtt))
410 rtt = InvalidRTT();
411
412 int32_t downstream_throughput_kbps;
413 if (!GetDownlinkThroughputKbpsEstimate(&downstream_throughput_kbps))
414 downstream_throughput_kbps = kInvalidThroughput;
415
416 estimated_median_network_quality_ =
417 NetworkQuality(rtt, downstream_throughput_kbps);
418 }
419
420 base::TimeTicks now = base::TimeTicks::Now();
421 LoadTimingInfo load_timing_info;
422 request.GetLoadTimingInfo(&load_timing_info);
423
424 // If the load timing info is unavailable, it probably means that the request
425 // did not go over the network.
426 if (load_timing_info.send_start.is_null() ||
427 load_timing_info.receive_headers_end.is_null()) {
428 return;
429 }
430
431 // Time when the resource was requested.
432 base::TimeTicks request_start_time = load_timing_info.send_start;
433
434 // Time when the headers were received.
435 base::TimeTicks headers_received_time = load_timing_info.receive_headers_end;
436
437 // Duration between when the resource was requested and when response
438 // headers were received.
439 base::TimeDelta observed_rtt = headers_received_time - request_start_time;
440 DCHECK_GE(observed_rtt, base::TimeDelta());
441 if (observed_rtt < peak_network_quality_.rtt()) {
442 peak_network_quality_ = NetworkQuality(
443 observed_rtt, peak_network_quality_.downstream_throughput_kbps());
444 }
445
446 RttObservation rtt_observation(observed_rtt, now, URL_REQUEST);
447 rtt_observations_.AddObservation(rtt_observation);
448 NotifyObserversOfRTT(rtt_observation);
449
450 // Compare the RTT observation with the estimated value and record it.
451 if (estimated_median_network_quality_.rtt() != InvalidRTT()) {
452 RecordRTTUMA(estimated_median_network_quality_.rtt().InMilliseconds(),
453 observed_rtt.InMilliseconds());
454 }
455 }
456
457 void NetworkQualityEstimator::NotifyRequestCompleted(
458 const URLRequest& request) {
459 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("net"),
460 "NetworkQualityEstimator::NotifyRequestCompleted");
461 DCHECK(thread_checker_.CalledOnValidThread());
462
463 if (!RequestProvidesUsefulObservations(request))
464 return;
465
466 base::TimeTicks now = base::TimeTicks::Now();
467 LoadTimingInfo load_timing_info;
468 request.GetLoadTimingInfo(&load_timing_info);
469
470 // If the load timing info is unavailable, it probably means that the request
471 // did not go over the network.
472 if (load_timing_info.send_start.is_null() ||
473 load_timing_info.receive_headers_end.is_null()) {
474 return;
475 }
476
477 // Time since the resource was requested.
478 // TODO(tbansal): Change the start time to receive_headers_end, once we use
479 // NetworkActivityMonitor.
480 base::TimeDelta request_start_to_completed =
481 now - load_timing_info.send_start;
482 DCHECK_GE(request_start_to_completed, base::TimeDelta());
483
484 // Ignore tiny transfers which will not produce accurate rates.
485 // Ignore short duration transfers.
486 // Skip the checks if |allow_small_responses_| is true.
487 if (!allow_small_responses_ &&
488 (request.GetTotalReceivedBytes() < kMinTransferSizeInBytes ||
489 request_start_to_completed < base::TimeDelta::FromMicroseconds(
490 kMinRequestDurationMicroseconds))) {
491 return;
492 }
493
494 double downstream_kbps = request.GetTotalReceivedBytes() * 8.0 / 1000.0 /
495 request_start_to_completed.InSecondsF();
496 DCHECK_GE(downstream_kbps, 0.0);
497
498 // Check overflow errors. This may happen if the downstream_kbps is more than
499 // 2 * 10^9 (= 2000 Gbps).
500 if (downstream_kbps >= std::numeric_limits<int32_t>::max())
501 downstream_kbps = std::numeric_limits<int32_t>::max();
502
503 int32_t downstream_kbps_as_integer = static_cast<int32_t>(downstream_kbps);
504
505 // Round up |downstream_kbps_as_integer|. If the |downstream_kbps_as_integer|
506 // is less than 1, it is set to 1 to differentiate from case when there is no
507 // connection.
508 if (downstream_kbps - downstream_kbps_as_integer > 0)
509 downstream_kbps_as_integer++;
510
511 DCHECK_GT(downstream_kbps_as_integer, 0.0);
512 if (downstream_kbps_as_integer >
513 peak_network_quality_.downstream_throughput_kbps())
514 peak_network_quality_ =
515 NetworkQuality(peak_network_quality_.rtt(), downstream_kbps_as_integer);
516
517 ThroughputObservation throughput_observation(downstream_kbps_as_integer, now,
518 URL_REQUEST);
519 downstream_throughput_kbps_observations_.AddObservation(
520 throughput_observation);
521 NotifyObserversOfThroughput(throughput_observation);
522 }
523
524 void NetworkQualityEstimator::AddRTTObserver(RTTObserver* rtt_observer) {
525 DCHECK(thread_checker_.CalledOnValidThread());
526 rtt_observer_list_.AddObserver(rtt_observer);
527 }
528
529 void NetworkQualityEstimator::RemoveRTTObserver(RTTObserver* rtt_observer) {
530 DCHECK(thread_checker_.CalledOnValidThread());
531 rtt_observer_list_.RemoveObserver(rtt_observer);
532 }
533
534 void NetworkQualityEstimator::AddThroughputObserver(
535 ThroughputObserver* throughput_observer) {
536 DCHECK(thread_checker_.CalledOnValidThread());
537 throughput_observer_list_.AddObserver(throughput_observer);
538 }
539
540 void NetworkQualityEstimator::RemoveThroughputObserver(
541 ThroughputObserver* throughput_observer) {
542 DCHECK(thread_checker_.CalledOnValidThread());
543 throughput_observer_list_.RemoveObserver(throughput_observer);
544 }
545
546 SocketPerformanceWatcherFactory*
547 NetworkQualityEstimator::GetSocketPerformanceWatcherFactory() {
548 DCHECK(thread_checker_.CalledOnValidThread());
549
550 return watcher_factory_.get();
551 }
552
553 void NetworkQualityEstimator::RecordRTTUMA(int32_t estimated_value_msec,
554 int32_t actual_value_msec) const {
555 DCHECK(thread_checker_.CalledOnValidThread());
556
557 // Record the difference between the actual and the estimated value.
558 if (estimated_value_msec >= actual_value_msec) {
559 base::HistogramBase* difference_rtt =
560 GetHistogram("DifferenceRTTEstimatedAndActual.",
561 current_network_id_.type, 10 * 1000); // 10 seconds
562 difference_rtt->Add(estimated_value_msec - actual_value_msec);
563 } else {
564 base::HistogramBase* difference_rtt =
565 GetHistogram("DifferenceRTTActualAndEstimated.",
566 current_network_id_.type, 10 * 1000); // 10 seconds
567 difference_rtt->Add(actual_value_msec - estimated_value_msec);
568 }
569
570 // Record all the RTT observations.
571 base::HistogramBase* rtt_observations =
572 GetHistogram("RTTObservations.", current_network_id_.type,
573 10 * 1000); // 10 seconds upper bound
574 rtt_observations->Add(actual_value_msec);
575
576 if (actual_value_msec == 0)
577 return;
578
579 int32_t ratio = (estimated_value_msec * 100) / actual_value_msec;
580
581 // Record the accuracy of estimation by recording the ratio of estimated
582 // value to the actual value.
583 base::HistogramBase* ratio_median_rtt = GetHistogram(
584 "RatioEstimatedToActualRTT.", current_network_id_.type, 1000);
585 ratio_median_rtt->Add(ratio);
586 }
587
588 bool NetworkQualityEstimator::RequestProvidesUsefulObservations(
589 const URLRequest& request) const {
590 return request.url().is_valid() &&
591 (allow_localhost_requests_ || !IsLocalhost(request.url().host())) &&
592 request.url().SchemeIsHTTPOrHTTPS() &&
593 // Verify that response headers are received, so it can be ensured that
594 // response is not cached.
595 !request.response_info().response_time.is_null() &&
596 !request.was_cached() &&
597 request.creation_time() >= last_connection_change_;
598 }
599
600 void NetworkQualityEstimator::RecordExternalEstimateProviderMetrics(
601 NQEExternalEstimateProviderStatus status) const {
602 UMA_HISTOGRAM_ENUMERATION("NQE.ExternalEstimateProviderStatus", status,
603 EXTERNAL_ESTIMATE_PROVIDER_STATUS_BOUNDARY);
604 }
605
606 void NetworkQualityEstimator::OnConnectionTypeChanged(
607 NetworkChangeNotifier::ConnectionType type) {
608 DCHECK(thread_checker_.CalledOnValidThread());
609 if (peak_network_quality_.rtt() != InvalidRTT()) {
610 base::HistogramBase* rtt_histogram =
611 GetHistogram("FastestRTT.", current_network_id_.type, 10 * 1000);
612 rtt_histogram->Add(peak_network_quality_.rtt().InMilliseconds());
613 }
614
615 if (peak_network_quality_.downstream_throughput_kbps() !=
616 kInvalidThroughput) {
617 base::HistogramBase* downstream_throughput_histogram =
618 GetHistogram("PeakKbps.", current_network_id_.type, 1000 * 1000);
619 downstream_throughput_histogram->Add(
620 peak_network_quality_.downstream_throughput_kbps());
621 }
622
623 base::TimeDelta rtt;
624 if (GetURLRequestRTTEstimate(&rtt)) {
625 // Add the 50th percentile value.
626 base::HistogramBase* rtt_percentile =
627 GetHistogram("RTT.Percentile50.", current_network_id_.type, 10 * 1000);
628 rtt_percentile->Add(rtt.InMilliseconds());
629
630 // Add the remaining percentile values.
631 static const int kPercentiles[] = {0, 10, 90, 100};
632 std::vector<ObservationSource> disallowed_observation_sources;
633 disallowed_observation_sources.push_back(TCP);
634 disallowed_observation_sources.push_back(QUIC);
635 for (size_t i = 0; i < arraysize(kPercentiles); ++i) {
636 rtt = GetRTTEstimateInternal(disallowed_observation_sources,
637 base::TimeTicks(), kPercentiles[i]);
638
639 rtt_percentile = GetHistogram(
640 "RTT.Percentile" + base::IntToString(kPercentiles[i]) + ".",
641 current_network_id_.type, 10 * 1000); // 10 seconds
642 rtt_percentile->Add(rtt.InMilliseconds());
643 }
644 }
645
646 // Write the estimates of the previous network to the cache.
647 CacheNetworkQualityEstimate();
648
649 // Clear the local state.
650 last_connection_change_ = base::TimeTicks::Now();
651 peak_network_quality_ = NetworkQuality();
652 downstream_throughput_kbps_observations_.Clear();
653 rtt_observations_.Clear();
654 current_network_id_ = GetCurrentNetworkID();
655
656 QueryExternalEstimateProvider();
657
658 // Read any cached estimates for the new network. If cached estimates are
659 // unavailable, add the default estimates.
660 if (!ReadCachedNetworkQualityEstimate())
661 AddDefaultEstimates();
662 estimated_median_network_quality_ = NetworkQuality();
663 }
664
665 NetworkQualityEstimator::EffectiveConnectionType
666 NetworkQualityEstimator::GetEffectiveConnectionType() const {
667 DCHECK(thread_checker_.CalledOnValidThread());
668
669 base::TimeDelta url_request_rtt = InvalidRTT();
670 if (!GetURLRequestRTTEstimate(&url_request_rtt))
671 url_request_rtt = InvalidRTT();
672
673 int32_t kbps = kInvalidThroughput;
674 if (!GetDownlinkThroughputKbpsEstimate(&kbps))
675 kbps = kInvalidThroughput;
676
677 if (url_request_rtt == InvalidRTT() && kbps == kInvalidThroughput) {
678 // Quality of the current network is unknown.
679 return EFFECTIVE_CONNECTION_TYPE_UNKNOWN;
680 }
681
682 // Search from the slowest connection type to the fastest to find the
683 // EffectiveConnectionType that best matches the current connection's
684 // performance. The match is done by comparing RTT and throughput.
685 for (size_t i = 0; i < EFFECTIVE_CONNECTION_TYPE_LAST; ++i) {
686 EffectiveConnectionType type = static_cast<EffectiveConnectionType>(i);
687 if (i == EFFECTIVE_CONNECTION_TYPE_UNKNOWN)
688 continue;
689 bool estimated_rtt_is_higher_than_threshold =
690 url_request_rtt != InvalidRTT() &&
691 connection_thresholds_[i].rtt() != InvalidRTT() &&
692 url_request_rtt >= connection_thresholds_[i].rtt();
693 bool estimated_throughput_is_lower_than_threshold =
694 kbps != kInvalidThroughput &&
695 connection_thresholds_[i].downstream_throughput_kbps() !=
696 kInvalidThroughput &&
697 kbps <= connection_thresholds_[i].downstream_throughput_kbps();
698 // Return |type| as the effective connection type if the current network's
699 // RTT is worse than the threshold RTT for |type|, or if the current
700 // network's throughput is lower than the threshold throughput for |type|.
701 if (estimated_rtt_is_higher_than_threshold ||
702 estimated_throughput_is_lower_than_threshold) {
703 return type;
704 }
705 }
706 // Return the fastest connection type.
707 return static_cast<EffectiveConnectionType>(EFFECTIVE_CONNECTION_TYPE_LAST -
708 1);
709 }
710
711 bool NetworkQualityEstimator::GetURLRequestRTTEstimate(
712 base::TimeDelta* rtt) const {
713 DCHECK(thread_checker_.CalledOnValidThread());
714 std::vector<ObservationSource> disallowed_observation_sources;
715 disallowed_observation_sources.push_back(TCP);
716 disallowed_observation_sources.push_back(QUIC);
717 *rtt = GetRTTEstimateInternal(disallowed_observation_sources,
718 base::TimeTicks(), 50);
719 return (*rtt != InvalidRTT());
720 }
721
722 bool NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimate(
723 int32_t* kbps) const {
724 DCHECK(thread_checker_.CalledOnValidThread());
725 *kbps = GetDownlinkThroughputKbpsEstimateInternal(base::TimeTicks(), 50);
726 return (*kbps != kInvalidThroughput);
727 }
728
729 bool NetworkQualityEstimator::GetRecentURLRequestRTTMedian(
730 const base::TimeTicks& begin_timestamp,
731 base::TimeDelta* rtt) const {
732 DCHECK(thread_checker_.CalledOnValidThread());
733 std::vector<ObservationSource> disallowed_observation_sources;
734 disallowed_observation_sources.push_back(TCP);
735 disallowed_observation_sources.push_back(QUIC);
736 *rtt = GetRTTEstimateInternal(disallowed_observation_sources, begin_timestamp,
737 50);
738 return (*rtt != InvalidRTT());
739 }
740
741 bool NetworkQualityEstimator::GetRecentMedianDownlinkThroughputKbps(
742 const base::TimeTicks& begin_timestamp,
743 int32_t* kbps) const {
744 DCHECK(thread_checker_.CalledOnValidThread());
745 *kbps = GetDownlinkThroughputKbpsEstimateInternal(begin_timestamp, 50);
746 return (*kbps != kInvalidThroughput);
747 }
748
749 template <typename ValueType>
750 NetworkQualityEstimator::ObservationBuffer<ValueType>::ObservationBuffer(
751 double weight_multiplier_per_second)
752 : weight_multiplier_per_second_(weight_multiplier_per_second) {
753 static_assert(kMaximumObservationsBufferSize > 0U,
754 "Minimum size of observation buffer must be > 0");
755 DCHECK_GE(weight_multiplier_per_second_, 0.0);
756 DCHECK_LE(weight_multiplier_per_second_, 1.0);
757 }
758
759 template <typename ValueType>
760 NetworkQualityEstimator::ObservationBuffer<ValueType>::~ObservationBuffer() {}
761
762 base::TimeDelta NetworkQualityEstimator::GetRTTEstimateInternal(
763 const std::vector<ObservationSource>& disallowed_observation_sources,
764 const base::TimeTicks& begin_timestamp,
765 int percentile) const {
766 DCHECK(thread_checker_.CalledOnValidThread());
767
768 // RTT observations are sorted by duration from shortest to longest, thus
769 // a higher percentile RTT will have a longer RTT than a lower percentile.
770 base::TimeDelta rtt = InvalidRTT();
771 if (!rtt_observations_.GetPercentile(begin_timestamp, &rtt, percentile,
772 disallowed_observation_sources)) {
773 return InvalidRTT();
774 }
775 return rtt;
776 }
777
778 int32_t NetworkQualityEstimator::GetDownlinkThroughputKbpsEstimateInternal(
779 const base::TimeTicks& begin_timestamp,
780 int percentile) const {
781 DCHECK(thread_checker_.CalledOnValidThread());
782
783 // Throughput observations are sorted by kbps from slowest to fastest,
784 // thus a higher percentile throughput will be faster than a lower one.
785 int32_t kbps = kInvalidThroughput;
786 if (!downstream_throughput_kbps_observations_.GetPercentile(
787 begin_timestamp, &kbps, 100 - percentile,
788 std::vector<ObservationSource>())) {
789 return kInvalidThroughput;
790 }
791 return kbps;
792 }
793
794 template <typename ValueType>
795 void NetworkQualityEstimator::ObservationBuffer<ValueType>::
796 ComputeWeightedObservations(
797 const base::TimeTicks& begin_timestamp,
798 std::vector<WeightedObservation<ValueType>>& weighted_observations,
799 double* total_weight,
800 const std::vector<ObservationSource>& disallowed_observation_sources)
801 const {
802 weighted_observations.clear();
803 double total_weight_observations = 0.0;
804 base::TimeTicks now = base::TimeTicks::Now();
805
806 for (const auto& observation : observations_) {
807 if (observation.timestamp < begin_timestamp)
808 continue;
809 bool disallowed = false;
810 for (const auto& disallowed_source : disallowed_observation_sources) {
811 if (disallowed_source == observation.source)
812 disallowed = true;
813 }
814 if (disallowed)
815 continue;
816 base::TimeDelta time_since_sample_taken = now - observation.timestamp;
817 double weight =
818 pow(weight_multiplier_per_second_, time_since_sample_taken.InSeconds());
819 weight = std::max(DBL_MIN, std::min(1.0, weight));
820
821 weighted_observations.push_back(
822 WeightedObservation<ValueType>(observation.value, weight));
823 total_weight_observations += weight;
824 }
825
826 // Sort the samples by value in ascending order.
827 std::sort(weighted_observations.begin(), weighted_observations.end());
828 *total_weight = total_weight_observations;
829 }
830
831 template <typename ValueType>
832 bool NetworkQualityEstimator::ObservationBuffer<ValueType>::GetPercentile(
833 const base::TimeTicks& begin_timestamp,
834 ValueType* result,
835 int percentile,
836 const std::vector<ObservationSource>& disallowed_observation_sources)
837 const {
838 DCHECK(result);
839 DCHECK_GE(percentile, 0);
840 DCHECK_LE(percentile, 100);
841
842 // Stores WeightedObservation in increasing order of value.
843 std::vector<WeightedObservation<ValueType>> weighted_observations;
844
845 // Total weight of all observations in |weighted_observations|.
846 double total_weight = 0.0;
847
848 ComputeWeightedObservations(begin_timestamp, weighted_observations,
849 &total_weight, disallowed_observation_sources);
850 if (weighted_observations.empty())
851 return false;
852
853 DCHECK(!weighted_observations.empty());
854 DCHECK_GT(total_weight, 0.0);
855
856 // weighted_observations may have a smaller size than observations_ since the
857 // former contains only the observations later than begin_timestamp.
858 DCHECK_GE(observations_.size(), weighted_observations.size());
859
860 double desired_weight = percentile / 100.0 * total_weight;
861
862 double cumulative_weight_seen_so_far = 0.0;
863 for (const auto& weighted_observation : weighted_observations) {
864 cumulative_weight_seen_so_far += weighted_observation.weight;
865
866 if (cumulative_weight_seen_so_far >= desired_weight) {
867 *result = weighted_observation.value;
868 return true;
869 }
870 }
871
872 // Computation may reach here due to floating point errors. This may happen
873 // if |percentile| was 100 (or close to 100), and |desired_weight| was
874 // slightly larger than |total_weight| (due to floating point errors).
875 // In this case, we return the highest |value| among all observations.
876 // This is same as value of the last observation in the sorted vector.
877 *result = weighted_observations.at(weighted_observations.size() - 1).value;
878 return true;
879 }
880
881 NetworkQualityEstimator::NetworkID
882 NetworkQualityEstimator::GetCurrentNetworkID() const {
883 DCHECK(thread_checker_.CalledOnValidThread());
884
885 // TODO(tbansal): crbug.com/498068 Add NetworkQualityEstimatorAndroid class
886 // that overrides this method on the Android platform.
887
888 // It is possible that the connection type changed between when
889 // GetConnectionType() was called and when the API to determine the
890 // network name was called. Check if that happened and retry until the
891 // connection type stabilizes. This is an imperfect solution but should
892 // capture majority of cases, and should not significantly affect estimates
893 // (that are approximate to begin with).
894 while (true) {
895 NetworkQualityEstimator::NetworkID network_id(
896 NetworkChangeNotifier::GetConnectionType(), std::string());
897
898 switch (network_id.type) {
899 case NetworkChangeNotifier::ConnectionType::CONNECTION_UNKNOWN:
900 case NetworkChangeNotifier::ConnectionType::CONNECTION_NONE:
901 case NetworkChangeNotifier::ConnectionType::CONNECTION_BLUETOOTH:
902 case NetworkChangeNotifier::ConnectionType::CONNECTION_ETHERNET:
903 break;
904 case NetworkChangeNotifier::ConnectionType::CONNECTION_WIFI:
905 #if defined(OS_ANDROID) || defined(OS_LINUX) || defined(OS_CHROMEOS) || \
906 defined(OS_WIN)
907 network_id.id = GetWifiSSID();
908 #endif
909 break;
910 case NetworkChangeNotifier::ConnectionType::CONNECTION_2G:
911 case NetworkChangeNotifier::ConnectionType::CONNECTION_3G:
912 case NetworkChangeNotifier::ConnectionType::CONNECTION_4G:
913 #if defined(OS_ANDROID)
914 network_id.id = android::GetTelephonyNetworkOperator();
915 #endif
916 break;
917 default:
918 NOTREACHED() << "Unexpected connection type = " << network_id.type;
919 break;
920 }
921
922 if (network_id.type == NetworkChangeNotifier::GetConnectionType())
923 return network_id;
924 }
925 NOTREACHED();
926 }
927
928 bool NetworkQualityEstimator::ReadCachedNetworkQualityEstimate() {
929 DCHECK(thread_checker_.CalledOnValidThread());
930
931 // If the network name is unavailable, caching should not be performed.
932 if (current_network_id_.id.empty())
933 return false;
934
935 CachedNetworkQualities::const_iterator it =
936 cached_network_qualities_.find(current_network_id_);
937
938 if (it == cached_network_qualities_.end())
939 return false;
940
941 NetworkQuality network_quality(it->second.network_quality());
942
943 DCHECK_NE(InvalidRTT(), network_quality.rtt());
944 DCHECK_NE(kInvalidThroughput, network_quality.downstream_throughput_kbps());
945
946 ThroughputObservation througphput_observation(
947 network_quality.downstream_throughput_kbps(), base::TimeTicks::Now(),
948 CACHED_ESTIMATE);
949 downstream_throughput_kbps_observations_.AddObservation(
950 througphput_observation);
951 NotifyObserversOfThroughput(througphput_observation);
952
953 RttObservation rtt_observation(network_quality.rtt(), base::TimeTicks::Now(),
954 CACHED_ESTIMATE);
955 rtt_observations_.AddObservation(rtt_observation);
956 NotifyObserversOfRTT(rtt_observation);
957
958 return true;
959 }
960
961 void NetworkQualityEstimator::OnUpdatedEstimateAvailable() {
962 DCHECK(thread_checker_.CalledOnValidThread());
963 DCHECK(external_estimate_provider_);
964
965 RecordExternalEstimateProviderMetrics(
966 EXTERNAL_ESTIMATE_PROVIDER_STATUS_CALLBACK);
967 QueryExternalEstimateProvider();
968 }
969
970 const char* NetworkQualityEstimator::GetNameForEffectiveConnectionType(
971 EffectiveConnectionType type) const {
972 switch (type) {
973 case EFFECTIVE_CONNECTION_TYPE_UNKNOWN:
974 return "Unknown";
975 case EFFECTIVE_CONNECTION_TYPE_OFFLINE:
976 return "Offline";
977 case EFFECTIVE_CONNECTION_TYPE_SLOW_2G:
978 return "Slow2G";
979 case EFFECTIVE_CONNECTION_TYPE_2G:
980 return "2G";
981 case EFFECTIVE_CONNECTION_TYPE_3G:
982 return "3G";
983 case EFFECTIVE_CONNECTION_TYPE_4G:
984 return "4G";
985 case EFFECTIVE_CONNECTION_TYPE_BROADBAND:
986 return "Broadband";
987 default:
988 NOTREACHED();
989 break;
990 }
991 return "";
992 }
993
994 void NetworkQualityEstimator::QueryExternalEstimateProvider() {
995 DCHECK(thread_checker_.CalledOnValidThread());
996
997 if (!external_estimate_provider_)
998 return;
999 RecordExternalEstimateProviderMetrics(
1000 EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERIED);
1001
1002 base::TimeDelta time_since_last_update;
1003
1004 // Request a new estimate if estimate is not available, or if the available
1005 // estimate is not fresh.
1006 if (!external_estimate_provider_->GetTimeSinceLastUpdate(
1007 &time_since_last_update) ||
1008 time_since_last_update >
1009 base::TimeDelta::FromMilliseconds(
1010 kExternalEstimateProviderFreshnessDurationMsec)) {
1011 // Request the external estimate provider for updated estimates. When the
1012 // updates estimates are available, OnUpdatedEstimateAvailable() will be
1013 // called.
1014 external_estimate_provider_->Update();
1015 return;
1016 }
1017
1018 RecordExternalEstimateProviderMetrics(
1019 EXTERNAL_ESTIMATE_PROVIDER_STATUS_QUERY_SUCCESSFUL);
1020 base::TimeDelta rtt;
1021 if (external_estimate_provider_->GetRTT(&rtt)) {
1022 RecordExternalEstimateProviderMetrics(
1023 EXTERNAL_ESTIMATE_PROVIDER_STATUS_RTT_AVAILABLE);
1024 UMA_HISTOGRAM_TIMES("NQE.ExternalEstimateProvider.RTT", rtt);
1025 rtt_observations_.AddObservation(
1026 RttObservation(rtt, base::TimeTicks::Now(), EXTERNAL_ESTIMATE));
1027 }
1028
1029 int32_t downstream_throughput_kbps;
1030 if (external_estimate_provider_->GetDownstreamThroughputKbps(
1031 &downstream_throughput_kbps)) {
1032 RecordExternalEstimateProviderMetrics(
1033 EXTERNAL_ESTIMATE_PROVIDER_STATUS_DOWNLINK_BANDWIDTH_AVAILABLE);
1034 UMA_HISTOGRAM_COUNTS("NQE.ExternalEstimateProvider.DownlinkBandwidth",
1035 downstream_throughput_kbps);
1036 downstream_throughput_kbps_observations_.AddObservation(
1037 ThroughputObservation(downstream_throughput_kbps,
1038 base::TimeTicks::Now(), EXTERNAL_ESTIMATE));
1039 }
1040 }
1041
1042 void NetworkQualityEstimator::CacheNetworkQualityEstimate() {
1043 DCHECK(thread_checker_.CalledOnValidThread());
1044 DCHECK_LE(cached_network_qualities_.size(),
1045 static_cast<size_t>(kMaximumNetworkQualityCacheSize));
1046
1047 // If the network name is unavailable, caching should not be performed.
1048 if (current_network_id_.id.empty())
1049 return;
1050
1051 base::TimeDelta rtt = InvalidRTT();
1052 int32_t downlink_throughput_kbps = kInvalidThroughput;
1053
1054 if (!GetURLRequestRTTEstimate(&rtt) ||
1055 !GetDownlinkThroughputKbpsEstimate(&downlink_throughput_kbps)) {
1056 return;
1057 }
1058
1059 NetworkQuality network_quality =
1060 NetworkQuality(rtt, downlink_throughput_kbps);
1061
1062 if (cached_network_qualities_.size() == kMaximumNetworkQualityCacheSize) {
1063 // Remove the oldest entry.
1064 CachedNetworkQualities::iterator oldest_entry_iterator =
1065 cached_network_qualities_.begin();
1066
1067 for (CachedNetworkQualities::iterator it =
1068 cached_network_qualities_.begin();
1069 it != cached_network_qualities_.end(); ++it) {
1070 if ((it->second).OlderThan(oldest_entry_iterator->second))
1071 oldest_entry_iterator = it;
1072 }
1073 cached_network_qualities_.erase(oldest_entry_iterator);
1074 }
1075 DCHECK_LT(cached_network_qualities_.size(),
1076 static_cast<size_t>(kMaximumNetworkQualityCacheSize));
1077
1078 cached_network_qualities_.insert(std::make_pair(
1079 current_network_id_, CachedNetworkQuality(network_quality)));
1080 DCHECK_LE(cached_network_qualities_.size(),
1081 static_cast<size_t>(kMaximumNetworkQualityCacheSize));
1082 }
1083
1084 void NetworkQualityEstimator::OnUpdatedRTTAvailable(
1085 SocketPerformanceWatcherFactory::Protocol protocol,
1086 const base::TimeDelta& rtt) {
1087 DCHECK(thread_checker_.CalledOnValidThread());
1088
1089 switch (protocol) {
1090 case SocketPerformanceWatcherFactory::PROTOCOL_TCP:
1091 NotifyObserversOfRTT(RttObservation(rtt, base::TimeTicks::Now(), TCP));
1092 return;
1093 case SocketPerformanceWatcherFactory::PROTOCOL_QUIC:
1094 NotifyObserversOfRTT(RttObservation(rtt, base::TimeTicks::Now(), QUIC));
1095 return;
1096 default:
1097 NOTREACHED();
1098 }
1099 }
1100
1101 void NetworkQualityEstimator::NotifyObserversOfRTT(
1102 const RttObservation& observation) {
1103 FOR_EACH_OBSERVER(
1104 RTTObserver, rtt_observer_list_,
1105 OnRTTObservation(observation.value.InMilliseconds(),
1106 observation.timestamp, observation.source));
1107 }
1108
1109 void NetworkQualityEstimator::NotifyObserversOfThroughput(
1110 const ThroughputObservation& observation) {
1111 FOR_EACH_OBSERVER(
1112 ThroughputObserver, throughput_observer_list_,
1113 OnThroughputObservation(observation.value, observation.timestamp,
1114 observation.source));
1115 }
1116
1117 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
1118 const NetworkQuality& network_quality)
1119 : last_update_time_(base::TimeTicks::Now()),
1120 network_quality_(network_quality) {
1121 }
1122
1123 NetworkQualityEstimator::CachedNetworkQuality::CachedNetworkQuality(
1124 const CachedNetworkQuality& other)
1125 : last_update_time_(other.last_update_time_),
1126 network_quality_(other.network_quality_) {
1127 }
1128
1129 NetworkQualityEstimator::CachedNetworkQuality::~CachedNetworkQuality() {
1130 }
1131
1132 bool NetworkQualityEstimator::CachedNetworkQuality::OlderThan(
1133 const CachedNetworkQuality& cached_network_quality) const {
1134 return last_update_time_ < cached_network_quality.last_update_time_;
1135 }
1136
1137 NetworkQualityEstimator::NetworkQuality::NetworkQuality()
1138 : NetworkQuality(NetworkQualityEstimator::InvalidRTT(),
1139 NetworkQualityEstimator::kInvalidThroughput) {}
1140
1141 NetworkQualityEstimator::NetworkQuality::NetworkQuality(
1142 const base::TimeDelta& rtt,
1143 int32_t downstream_throughput_kbps)
1144 : rtt_(rtt), downstream_throughput_kbps_(downstream_throughput_kbps) {
1145 DCHECK_GE(rtt_, base::TimeDelta());
1146 DCHECK_GE(downstream_throughput_kbps_, 0);
1147 }
1148
1149 NetworkQualityEstimator::NetworkQuality::NetworkQuality(
1150 const NetworkQuality& other)
1151 : NetworkQuality(other.rtt_, other.downstream_throughput_kbps_) {}
1152
1153 NetworkQualityEstimator::NetworkQuality::~NetworkQuality() {}
1154
1155 NetworkQualityEstimator::NetworkQuality&
1156 NetworkQualityEstimator::NetworkQuality::
1157 operator=(const NetworkQuality& other) {
1158 rtt_ = other.rtt_;
1159 downstream_throughput_kbps_ = other.downstream_throughput_kbps_;
1160 return *this;
1161 }
1162
1163 } // namespace net
OLDNEW
« no previous file with comments | « net/base/network_quality_estimator.h ('k') | net/base/network_quality_estimator_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698