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.
5 #include "net/base/network_quality_estimator.h"
9 #include "base/logging.h"
10 #include "base/metrics/histogram.h"
11 #include "net/base/net_util.h"
12 #include "net/base/network_quality.h"
13 #include "net/url_request/url_request.h"
18 NetworkQualityEstimator::NetworkQualityEstimator()
19 : NetworkQualityEstimator(false) {
22 NetworkQualityEstimator::NetworkQualityEstimator(
23 bool allow_local_host_requests_for_tests
)
24 : allow_localhost_requests_(allow_local_host_requests_for_tests
),
25 last_connection_change_(base::TimeTicks::Now()),
26 current_connection_type_(NetworkChangeNotifier::GetConnectionType()),
27 bytes_read_since_last_connection_change_(false),
28 peak_kbps_since_last_connection_change_(0) {
29 static_assert(kMinRequestDurationMicroseconds
> 0,
30 "Minimum request duration must be > 0");
31 NetworkChangeNotifier::AddConnectionTypeObserver(this);
34 NetworkQualityEstimator::~NetworkQualityEstimator() {
35 DCHECK(thread_checker_
.CalledOnValidThread());
36 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
39 void NetworkQualityEstimator::NotifyDataReceived(const URLRequest
& request
,
40 int64_t prefilter_bytes_read
) {
41 DCHECK(thread_checker_
.CalledOnValidThread());
42 DCHECK_GT(prefilter_bytes_read
, 0);
44 if (!request
.url().is_valid() ||
45 (!allow_localhost_requests_
&& IsLocalhost(request
.url().host())) ||
46 !request
.url().SchemeIsHTTPOrHTTPS() ||
47 // Verify that response headers are received, so it can be ensured that
48 // response is not cached.
49 request
.response_info().response_time
.is_null() || request
.was_cached() ||
50 request
.creation_time() < last_connection_change_
) {
54 base::TimeTicks now
= base::TimeTicks::Now();
55 base::TimeDelta request_duration
= now
- request
.creation_time();
56 DCHECK_GE(request_duration
, base::TimeDelta());
57 if (!bytes_read_since_last_connection_change_
)
58 fastest_RTT_since_last_connection_change_
= request_duration
;
60 bytes_read_since_last_connection_change_
= true;
61 if (request_duration
< fastest_RTT_since_last_connection_change_
)
62 fastest_RTT_since_last_connection_change_
= request_duration
;
64 // Ignore tiny transfers which will not produce accurate rates.
65 // Ignore short duration transfers.
66 if (prefilter_bytes_read
>= kMinTransferSizeInBytes
&&
68 base::TimeDelta::FromMicroseconds(kMinRequestDurationMicroseconds
)) {
69 uint64_t kbps
= static_cast<uint64_t>(prefilter_bytes_read
* 8 * 1000 /
70 request_duration
.InMicroseconds());
71 if (kbps
> peak_kbps_since_last_connection_change_
)
72 peak_kbps_since_last_connection_change_
= kbps
;
76 void NetworkQualityEstimator::OnConnectionTypeChanged(
77 NetworkChangeNotifier::ConnectionType type
) {
78 DCHECK(thread_checker_
.CalledOnValidThread());
79 if (bytes_read_since_last_connection_change_
) {
80 switch (current_connection_type_
) {
81 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
82 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Unknown",
83 fastest_RTT_since_last_connection_change_
);
85 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
86 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Ethernet",
87 fastest_RTT_since_last_connection_change_
);
89 case NetworkChangeNotifier::CONNECTION_WIFI
:
90 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Wifi",
91 fastest_RTT_since_last_connection_change_
);
93 case NetworkChangeNotifier::CONNECTION_2G
:
94 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.2G",
95 fastest_RTT_since_last_connection_change_
);
97 case NetworkChangeNotifier::CONNECTION_3G
:
98 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.3G",
99 fastest_RTT_since_last_connection_change_
);
101 case NetworkChangeNotifier::CONNECTION_4G
:
102 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.4G",
103 fastest_RTT_since_last_connection_change_
);
105 case NetworkChangeNotifier::CONNECTION_NONE
:
106 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.None",
107 fastest_RTT_since_last_connection_change_
);
109 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
110 UMA_HISTOGRAM_TIMES("NQE.FastestRTT.Bluetooth",
111 fastest_RTT_since_last_connection_change_
);
119 if (peak_kbps_since_last_connection_change_
) {
120 switch (current_connection_type_
) {
121 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
122 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Unknown",
123 peak_kbps_since_last_connection_change_
);
125 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
126 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Ethernet",
127 peak_kbps_since_last_connection_change_
);
129 case NetworkChangeNotifier::CONNECTION_WIFI
:
130 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Wifi",
131 peak_kbps_since_last_connection_change_
);
133 case NetworkChangeNotifier::CONNECTION_2G
:
134 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.2G",
135 peak_kbps_since_last_connection_change_
);
137 case NetworkChangeNotifier::CONNECTION_3G
:
138 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.3G",
139 peak_kbps_since_last_connection_change_
);
141 case NetworkChangeNotifier::CONNECTION_4G
:
142 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.4G",
143 peak_kbps_since_last_connection_change_
);
145 case NetworkChangeNotifier::CONNECTION_NONE
:
146 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.None",
147 peak_kbps_since_last_connection_change_
);
149 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
150 UMA_HISTOGRAM_COUNTS("NQE.PeakKbps.Bluetooth",
151 peak_kbps_since_last_connection_change_
);
159 last_connection_change_
= base::TimeTicks::Now();
160 bytes_read_since_last_connection_change_
= false;
161 peak_kbps_since_last_connection_change_
= 0;
162 current_connection_type_
= type
;
165 NetworkQuality
NetworkQualityEstimator::GetEstimate() const {
166 DCHECK(thread_checker_
.CalledOnValidThread());
168 if (!bytes_read_since_last_connection_change_
) {
169 return NetworkQuality(fastest_RTT_since_last_connection_change_
, 0,
170 peak_kbps_since_last_connection_change_
, 0);
172 if (!peak_kbps_since_last_connection_change_
) {
173 return NetworkQuality(fastest_RTT_since_last_connection_change_
, 0.1,
174 peak_kbps_since_last_connection_change_
, 0);
176 return NetworkQuality(fastest_RTT_since_last_connection_change_
, 0.1,
177 peak_kbps_since_last_connection_change_
, 0.1);