PlzNavigate: Improvements to RFHM commit logic.
[chromium-blink-merge.git] / net / base / network_change_notifier.cc
blob3ec6369fc47019b1e0933d0938c7e0d40d8edfe8
1 // Copyright (c) 2012 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_change_notifier.h"
7 #include <limits>
9 #include "base/metrics/histogram.h"
10 #include "base/synchronization/lock.h"
11 #include "base/threading/thread_checker.h"
12 #include "build/build_config.h"
13 #include "net/base/net_util.h"
14 #include "net/base/network_change_notifier_factory.h"
15 #include "net/dns/dns_config_service.h"
16 #include "net/url_request/url_request.h"
17 #include "url/gurl.h"
19 #if defined(OS_ANDROID)
20 #include "base/metrics/sparse_histogram.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "net/android/network_library.h"
23 #endif
25 #if defined(OS_WIN)
26 #include "net/base/network_change_notifier_win.h"
27 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
28 #include "net/base/network_change_notifier_linux.h"
29 #elif defined(OS_MACOSX)
30 #include "net/base/network_change_notifier_mac.h"
31 #endif
33 namespace net {
35 namespace {
37 // The actual singleton notifier. The class contract forbids usage of the API
38 // in ways that would require us to place locks around access to this object.
39 // (The prohibition on global non-POD objects makes it tricky to do such a thing
40 // anyway.)
41 NetworkChangeNotifier* g_network_change_notifier = NULL;
43 // Class factory singleton.
44 NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL;
46 class MockNetworkChangeNotifier : public NetworkChangeNotifier {
47 public:
48 ConnectionType GetCurrentConnectionType() const override {
49 return CONNECTION_UNKNOWN;
53 } // namespace
55 // The main observer class that records UMAs for network events.
56 class HistogramWatcher
57 : public NetworkChangeNotifier::ConnectionTypeObserver,
58 public NetworkChangeNotifier::IPAddressObserver,
59 public NetworkChangeNotifier::DNSObserver,
60 public NetworkChangeNotifier::NetworkChangeObserver {
61 public:
62 HistogramWatcher()
63 : last_ip_address_change_(base::TimeTicks::Now()),
64 last_connection_change_(base::TimeTicks::Now()),
65 last_dns_change_(base::TimeTicks::Now()),
66 last_network_change_(base::TimeTicks::Now()),
67 last_connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
68 offline_packets_received_(0),
69 bytes_read_since_last_connection_change_(0),
70 peak_kbps_since_last_connection_change_(0) {}
72 // Registers our three Observer implementations. This is called from the
73 // network thread so that our Observer implementations are also called
74 // from the network thread. This avoids multi-threaded race conditions
75 // because the only other interface, |NotifyDataReceived| is also
76 // only called from the network thread.
77 void Init() {
78 DCHECK(thread_checker_.CalledOnValidThread());
79 DCHECK(g_network_change_notifier);
80 NetworkChangeNotifier::AddConnectionTypeObserver(this);
81 NetworkChangeNotifier::AddIPAddressObserver(this);
82 NetworkChangeNotifier::AddDNSObserver(this);
83 NetworkChangeNotifier::AddNetworkChangeObserver(this);
86 ~HistogramWatcher() override {
87 DCHECK(thread_checker_.CalledOnValidThread());
88 DCHECK(g_network_change_notifier);
89 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
90 NetworkChangeNotifier::RemoveIPAddressObserver(this);
91 NetworkChangeNotifier::RemoveDNSObserver(this);
92 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
95 // NetworkChangeNotifier::IPAddressObserver implementation.
96 void OnIPAddressChanged() override {
97 DCHECK(thread_checker_.CalledOnValidThread());
98 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.IPAddressChange",
99 SinceLast(&last_ip_address_change_));
100 UMA_HISTOGRAM_MEDIUM_TIMES(
101 "NCN.ConnectionTypeChangeToIPAddressChange",
102 last_ip_address_change_ - last_connection_change_);
105 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
106 void OnConnectionTypeChanged(
107 NetworkChangeNotifier::ConnectionType type) override {
108 DCHECK(thread_checker_.CalledOnValidThread());
109 base::TimeTicks now = base::TimeTicks::Now();
110 int32 kilobytes_read = bytes_read_since_last_connection_change_ / 1000;
111 base::TimeDelta state_duration = SinceLast(&last_connection_change_);
112 if (bytes_read_since_last_connection_change_) {
113 switch (last_connection_type_) {
114 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
115 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnUnknown",
116 first_byte_after_connection_change_);
117 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnUnknown",
118 fastest_RTT_since_last_connection_change_);
119 break;
120 case NetworkChangeNotifier::CONNECTION_ETHERNET:
121 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnEthernet",
122 first_byte_after_connection_change_);
123 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnEthernet",
124 fastest_RTT_since_last_connection_change_);
125 break;
126 case NetworkChangeNotifier::CONNECTION_WIFI:
127 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnWifi",
128 first_byte_after_connection_change_);
129 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnWifi",
130 fastest_RTT_since_last_connection_change_);
131 break;
132 case NetworkChangeNotifier::CONNECTION_2G:
133 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn2G",
134 first_byte_after_connection_change_);
135 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn2G",
136 fastest_RTT_since_last_connection_change_);
137 break;
138 case NetworkChangeNotifier::CONNECTION_3G:
139 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn3G",
140 first_byte_after_connection_change_);
141 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn3G",
142 fastest_RTT_since_last_connection_change_);
143 break;
144 case NetworkChangeNotifier::CONNECTION_4G:
145 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn4G",
146 first_byte_after_connection_change_);
147 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn4G",
148 fastest_RTT_since_last_connection_change_);
149 break;
150 case NetworkChangeNotifier::CONNECTION_NONE:
151 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnNone",
152 first_byte_after_connection_change_);
153 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnNone",
154 fastest_RTT_since_last_connection_change_);
155 break;
156 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
157 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnBluetooth",
158 first_byte_after_connection_change_);
159 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnBluetooth",
160 fastest_RTT_since_last_connection_change_);
163 if (peak_kbps_since_last_connection_change_) {
164 switch (last_connection_type_) {
165 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
166 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnUnknown",
167 peak_kbps_since_last_connection_change_);
168 break;
169 case NetworkChangeNotifier::CONNECTION_ETHERNET:
170 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
171 peak_kbps_since_last_connection_change_);
172 break;
173 case NetworkChangeNotifier::CONNECTION_WIFI:
174 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
175 peak_kbps_since_last_connection_change_);
176 break;
177 case NetworkChangeNotifier::CONNECTION_2G:
178 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
179 peak_kbps_since_last_connection_change_);
180 break;
181 case NetworkChangeNotifier::CONNECTION_3G:
182 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
183 peak_kbps_since_last_connection_change_);
184 break;
185 case NetworkChangeNotifier::CONNECTION_4G:
186 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
187 peak_kbps_since_last_connection_change_);
188 break;
189 case NetworkChangeNotifier::CONNECTION_NONE:
190 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
191 peak_kbps_since_last_connection_change_);
192 break;
193 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
194 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnBluetooth",
195 peak_kbps_since_last_connection_change_);
196 break;
199 switch (last_connection_type_) {
200 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
201 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnUnknown", state_duration);
202 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnUnknown", kilobytes_read);
203 break;
204 case NetworkChangeNotifier::CONNECTION_ETHERNET:
205 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration);
206 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read);
207 break;
208 case NetworkChangeNotifier::CONNECTION_WIFI:
209 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration);
210 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read);
211 break;
212 case NetworkChangeNotifier::CONNECTION_2G:
213 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration);
214 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read);
215 break;
216 case NetworkChangeNotifier::CONNECTION_3G:
217 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration);
218 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read);
219 break;
220 case NetworkChangeNotifier::CONNECTION_4G:
221 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration);
222 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read);
223 break;
224 case NetworkChangeNotifier::CONNECTION_NONE:
225 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration);
226 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read);
227 break;
228 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
229 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnBluetooth", state_duration);
230 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnBluetooth", kilobytes_read);
231 break;
234 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
235 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration);
237 if (offline_packets_received_) {
238 if ((now - last_offline_packet_received_) <
239 base::TimeDelta::FromSeconds(5)) {
240 // We can compare this sum with the sum of NCN.OfflineDataRecv.
241 UMA_HISTOGRAM_COUNTS_10000(
242 "NCN.OfflineDataRecvAny5sBeforeOnline",
243 offline_packets_received_);
246 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
247 now - last_offline_packet_received_);
249 } else {
250 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration);
253 NetworkChangeNotifier::LogOperatorCodeHistogram(type);
255 UMA_HISTOGRAM_MEDIUM_TIMES(
256 "NCN.IPAddressChangeToConnectionTypeChange",
257 now - last_ip_address_change_);
259 offline_packets_received_ = 0;
260 bytes_read_since_last_connection_change_ = 0;
261 peak_kbps_since_last_connection_change_ = 0;
262 last_connection_type_ = type;
263 polling_interval_ = base::TimeDelta::FromSeconds(1);
266 // NetworkChangeNotifier::DNSObserver implementation.
267 void OnDNSChanged() override {
268 DCHECK(thread_checker_.CalledOnValidThread());
269 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
270 SinceLast(&last_dns_change_));
273 // NetworkChangeNotifier::NetworkChangeObserver implementation.
274 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override {
275 DCHECK(thread_checker_.CalledOnValidThread());
276 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
277 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOnlineChange",
278 SinceLast(&last_network_change_));
279 } else {
280 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
281 SinceLast(&last_network_change_));
285 // Record histogram data whenever we receive a packet. Should only be called
286 // from the network thread.
287 void NotifyDataReceived(const URLRequest& request, int bytes_read) {
288 DCHECK(thread_checker_.CalledOnValidThread());
289 if (IsLocalhost(request.url().host()) ||
290 !request.url().SchemeIsHTTPOrHTTPS()) {
291 return;
294 base::TimeTicks now = base::TimeTicks::Now();
295 base::TimeDelta request_duration = now - request.creation_time();
296 if (bytes_read_since_last_connection_change_ == 0) {
297 first_byte_after_connection_change_ = now - last_connection_change_;
298 fastest_RTT_since_last_connection_change_ = request_duration;
300 bytes_read_since_last_connection_change_ += bytes_read;
301 if (request_duration < fastest_RTT_since_last_connection_change_)
302 fastest_RTT_since_last_connection_change_ = request_duration;
303 // Ignore tiny transfers which will not produce accurate rates.
304 // Ignore zero duration transfers which might cause divide by zero.
305 if (bytes_read > 10000 &&
306 request_duration > base::TimeDelta::FromMilliseconds(1) &&
307 request.creation_time() > last_connection_change_) {
308 int32 kbps = static_cast<int32>(
309 bytes_read * 8 / request_duration.InMilliseconds());
310 if (kbps > peak_kbps_since_last_connection_change_)
311 peak_kbps_since_last_connection_change_ = kbps;
314 if (last_connection_type_ != NetworkChangeNotifier::CONNECTION_NONE)
315 return;
317 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
318 now - last_connection_change_);
319 offline_packets_received_++;
320 last_offline_packet_received_ = now;
322 if ((now - last_polled_connection_) > polling_interval_) {
323 polling_interval_ *= 2;
324 last_polled_connection_ = now;
325 last_polled_connection_type_ =
326 NetworkChangeNotifier::GetConnectionType();
328 if (last_polled_connection_type_ ==
329 NetworkChangeNotifier::CONNECTION_NONE) {
330 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
331 now - last_connection_change_);
335 private:
336 static base::TimeDelta SinceLast(base::TimeTicks *last_time) {
337 base::TimeTicks current_time = base::TimeTicks::Now();
338 base::TimeDelta delta = current_time - *last_time;
339 *last_time = current_time;
340 return delta;
343 base::TimeTicks last_ip_address_change_;
344 base::TimeTicks last_connection_change_;
345 base::TimeTicks last_dns_change_;
346 base::TimeTicks last_network_change_;
347 base::TimeTicks last_offline_packet_received_;
348 base::TimeTicks last_polled_connection_;
349 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
350 // first transition to offline and on subsequent transitions. Once offline,
351 // |polling_interval_| doubles as offline data is received and we poll
352 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
353 // state.
354 base::TimeDelta polling_interval_;
355 // |last_connection_type_| is the last value passed to
356 // |OnConnectionTypeChanged|.
357 NetworkChangeNotifier::ConnectionType last_connection_type_;
358 // |last_polled_connection_type_| is last result from calling
359 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
360 NetworkChangeNotifier::ConnectionType last_polled_connection_type_;
361 // Count of how many times NotifyDataReceived() has been called while the
362 // NetworkChangeNotifier thought network connection was offline.
363 int32 offline_packets_received_;
364 // Number of bytes of network data received since last connectivity change.
365 int32 bytes_read_since_last_connection_change_;
366 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
367 // from URLRequest creation until first byte received.
368 base::TimeDelta fastest_RTT_since_last_connection_change_;
369 // Time between connectivity change and first network data byte received.
370 base::TimeDelta first_byte_after_connection_change_;
371 // Rough measurement of peak KB/s witnessed since last connectivity change.
372 // The accuracy is decreased by ignoring these factors:
373 // 1) Multiple URLRequests can occur concurrently.
374 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest.
375 // 3) The transfer time includes at least one RTT while no bytes are read.
376 // Erring on the conservative side is hopefully offset by taking the maximum.
377 int32 peak_kbps_since_last_connection_change_;
379 base::ThreadChecker thread_checker_;
381 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher);
384 // NetworkState is thread safe.
385 class NetworkChangeNotifier::NetworkState {
386 public:
387 NetworkState() {}
388 ~NetworkState() {}
390 void GetDnsConfig(DnsConfig* config) const {
391 base::AutoLock lock(lock_);
392 *config = dns_config_;
395 void SetDnsConfig(const DnsConfig& dns_config) {
396 base::AutoLock lock(lock_);
397 dns_config_ = dns_config;
400 private:
401 mutable base::Lock lock_;
402 DnsConfig dns_config_;
405 NetworkChangeNotifier::NetworkChangeCalculatorParams::
406 NetworkChangeCalculatorParams() {
409 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
410 class NetworkChangeNotifier::NetworkChangeCalculator
411 : public ConnectionTypeObserver,
412 public IPAddressObserver {
413 public:
414 NetworkChangeCalculator(const NetworkChangeCalculatorParams& params)
415 : params_(params),
416 have_announced_(false),
417 last_announced_connection_type_(CONNECTION_NONE),
418 pending_connection_type_(CONNECTION_NONE) {}
420 void Init() {
421 DCHECK(thread_checker_.CalledOnValidThread());
422 DCHECK(g_network_change_notifier);
423 AddConnectionTypeObserver(this);
424 AddIPAddressObserver(this);
427 ~NetworkChangeCalculator() override {
428 DCHECK(thread_checker_.CalledOnValidThread());
429 DCHECK(g_network_change_notifier);
430 RemoveConnectionTypeObserver(this);
431 RemoveIPAddressObserver(this);
434 // NetworkChangeNotifier::IPAddressObserver implementation.
435 void OnIPAddressChanged() override {
436 DCHECK(thread_checker_.CalledOnValidThread());
437 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
438 ? params_.ip_address_offline_delay_ : params_.ip_address_online_delay_;
439 // Cancels any previous timer.
440 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
443 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
444 void OnConnectionTypeChanged(ConnectionType type) override {
445 DCHECK(thread_checker_.CalledOnValidThread());
446 pending_connection_type_ = type;
447 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
448 ? params_.connection_type_offline_delay_
449 : params_.connection_type_online_delay_;
450 // Cancels any previous timer.
451 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
454 private:
455 void Notify() {
456 DCHECK(thread_checker_.CalledOnValidThread());
457 // Don't bother signaling about dead connections.
458 if (have_announced_ &&
459 (last_announced_connection_type_ == CONNECTION_NONE) &&
460 (pending_connection_type_ == CONNECTION_NONE)) {
461 return;
463 have_announced_ = true;
464 last_announced_connection_type_ = pending_connection_type_;
465 // Immediately before sending out an online signal, send out an offline
466 // signal to perform any destructive actions before constructive actions.
467 if (pending_connection_type_ != CONNECTION_NONE)
468 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE);
469 NetworkChangeNotifier::NotifyObserversOfNetworkChange(
470 pending_connection_type_);
473 const NetworkChangeCalculatorParams params_;
475 // Indicates if NotifyObserversOfNetworkChange has been called yet.
476 bool have_announced_;
477 // Last value passed to NotifyObserversOfNetworkChange.
478 ConnectionType last_announced_connection_type_;
479 // Value to pass to NotifyObserversOfNetworkChange when Notify is called.
480 ConnectionType pending_connection_type_;
481 // Used to delay notifications so duplicates can be combined.
482 base::OneShotTimer<NetworkChangeCalculator> timer_;
484 base::ThreadChecker thread_checker_;
486 DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator);
489 NetworkChangeNotifier::~NetworkChangeNotifier() {
490 network_change_calculator_.reset();
491 DCHECK_EQ(this, g_network_change_notifier);
492 g_network_change_notifier = NULL;
495 // static
496 void NetworkChangeNotifier::SetFactory(
497 NetworkChangeNotifierFactory* factory) {
498 CHECK(!g_network_change_notifier_factory);
499 g_network_change_notifier_factory = factory;
502 // static
503 NetworkChangeNotifier* NetworkChangeNotifier::Create() {
504 if (g_network_change_notifier_factory)
505 return g_network_change_notifier_factory->CreateInstance();
507 #if defined(OS_WIN)
508 NetworkChangeNotifierWin* network_change_notifier =
509 new NetworkChangeNotifierWin();
510 network_change_notifier->WatchForAddressChange();
511 return network_change_notifier;
512 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
513 // ChromeOS and Android builds MUST use their own class factory.
514 #if !defined(OS_CHROMEOS)
515 // TODO(oshima): ash_shell do not have access to chromeos'es
516 // notifier yet. Re-enable this when chromeos'es notifier moved to
517 // chromeos root directory. crbug.com/119298.
518 CHECK(false);
519 #endif
520 return NULL;
521 #elif defined(OS_LINUX)
522 return NetworkChangeNotifierLinux::Create();
523 #elif defined(OS_MACOSX)
524 return new NetworkChangeNotifierMac();
525 #else
526 NOTIMPLEMENTED();
527 return NULL;
528 #endif
531 // static
532 NetworkChangeNotifier::ConnectionType
533 NetworkChangeNotifier::GetConnectionType() {
534 return g_network_change_notifier ?
535 g_network_change_notifier->GetCurrentConnectionType() :
536 CONNECTION_UNKNOWN;
539 // static
540 double NetworkChangeNotifier::GetMaxBandwidth() {
541 return g_network_change_notifier ?
542 g_network_change_notifier->GetCurrentMaxBandwidth() :
543 std::numeric_limits<double>::infinity();
546 // static
547 void NetworkChangeNotifier::GetDnsConfig(DnsConfig* config) {
548 if (!g_network_change_notifier) {
549 *config = DnsConfig();
550 } else {
551 g_network_change_notifier->network_state_->GetDnsConfig(config);
555 // static
556 const char* NetworkChangeNotifier::ConnectionTypeToString(
557 ConnectionType type) {
558 static const char* const kConnectionTypeNames[] = {
559 "CONNECTION_UNKNOWN",
560 "CONNECTION_ETHERNET",
561 "CONNECTION_WIFI",
562 "CONNECTION_2G",
563 "CONNECTION_3G",
564 "CONNECTION_4G",
565 "CONNECTION_NONE",
566 "CONNECTION_BLUETOOTH"
568 static_assert(arraysize(kConnectionTypeNames) ==
569 NetworkChangeNotifier::CONNECTION_LAST + 1,
570 "ConnectionType name count should match");
571 if (type < CONNECTION_UNKNOWN || type > CONNECTION_LAST) {
572 NOTREACHED();
573 return "CONNECTION_INVALID";
575 return kConnectionTypeNames[type];
578 // static
579 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest& request,
580 int bytes_read) {
581 if (!g_network_change_notifier ||
582 !g_network_change_notifier->histogram_watcher_) {
583 return;
585 g_network_change_notifier->histogram_watcher_->NotifyDataReceived(request,
586 bytes_read);
589 // static
590 void NetworkChangeNotifier::InitHistogramWatcher() {
591 if (!g_network_change_notifier)
592 return;
593 g_network_change_notifier->histogram_watcher_.reset(new HistogramWatcher());
594 g_network_change_notifier->histogram_watcher_->Init();
597 // static
598 void NetworkChangeNotifier::ShutdownHistogramWatcher() {
599 if (!g_network_change_notifier)
600 return;
601 g_network_change_notifier->histogram_watcher_.reset();
604 // static
605 void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type) {
606 #if defined(OS_ANDROID)
607 // On a connection type change to 2/3/4G, log the network operator MCC/MNC.
608 // Log zero in other cases.
609 unsigned mcc_mnc = 0;
610 if (type == NetworkChangeNotifier::CONNECTION_2G ||
611 type == NetworkChangeNotifier::CONNECTION_3G ||
612 type == NetworkChangeNotifier::CONNECTION_4G) {
613 // Log zero if not perfectly converted.
614 if (!base::StringToUint(
615 net::android::GetTelephonyNetworkOperator(), &mcc_mnc)) {
616 mcc_mnc = 0;
619 UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc);
620 #endif
623 #if defined(OS_LINUX)
624 // static
625 const internal::AddressTrackerLinux*
626 NetworkChangeNotifier::GetAddressTracker() {
627 return g_network_change_notifier ?
628 g_network_change_notifier->GetAddressTrackerInternal() : NULL;
630 #endif
632 // static
633 bool NetworkChangeNotifier::IsOffline() {
634 return GetConnectionType() == CONNECTION_NONE;
637 // static
638 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) {
639 bool is_cellular = false;
640 switch (type) {
641 case CONNECTION_2G:
642 case CONNECTION_3G:
643 case CONNECTION_4G:
644 is_cellular = true;
645 break;
646 case CONNECTION_UNKNOWN:
647 case CONNECTION_ETHERNET:
648 case CONNECTION_WIFI:
649 case CONNECTION_NONE:
650 case CONNECTION_BLUETOOTH:
651 is_cellular = false;
652 break;
654 return is_cellular;
657 // static
658 NetworkChangeNotifier::ConnectionType
659 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(
660 const NetworkInterfaceList& interfaces) {
661 bool first = true;
662 ConnectionType result = CONNECTION_NONE;
663 for (size_t i = 0; i < interfaces.size(); ++i) {
664 #if defined(OS_WIN)
665 if (interfaces[i].friendly_name == "Teredo Tunneling Pseudo-Interface")
666 continue;
667 #endif
668 if (first) {
669 first = false;
670 result = interfaces[i].type;
671 } else if (result != interfaces[i].type) {
672 return CONNECTION_UNKNOWN;
675 return result;
678 // static
679 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
680 return new MockNetworkChangeNotifier();
683 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
684 if (g_network_change_notifier)
685 g_network_change_notifier->ip_address_observer_list_->AddObserver(observer);
688 void NetworkChangeNotifier::AddConnectionTypeObserver(
689 ConnectionTypeObserver* observer) {
690 if (g_network_change_notifier) {
691 g_network_change_notifier->connection_type_observer_list_->AddObserver(
692 observer);
696 void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
697 if (g_network_change_notifier) {
698 g_network_change_notifier->resolver_state_observer_list_->AddObserver(
699 observer);
703 void NetworkChangeNotifier::AddNetworkChangeObserver(
704 NetworkChangeObserver* observer) {
705 if (g_network_change_notifier) {
706 g_network_change_notifier->network_change_observer_list_->AddObserver(
707 observer);
711 void NetworkChangeNotifier::AddMaxBandwidthObserver(
712 MaxBandwidthObserver* observer) {
713 if (g_network_change_notifier) {
714 g_network_change_notifier->max_bandwidth_observer_list_->AddObserver(
715 observer);
719 void NetworkChangeNotifier::RemoveIPAddressObserver(
720 IPAddressObserver* observer) {
721 if (g_network_change_notifier) {
722 g_network_change_notifier->ip_address_observer_list_->RemoveObserver(
723 observer);
727 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
728 ConnectionTypeObserver* observer) {
729 if (g_network_change_notifier) {
730 g_network_change_notifier->connection_type_observer_list_->RemoveObserver(
731 observer);
735 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
736 if (g_network_change_notifier) {
737 g_network_change_notifier->resolver_state_observer_list_->RemoveObserver(
738 observer);
742 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
743 NetworkChangeObserver* observer) {
744 if (g_network_change_notifier) {
745 g_network_change_notifier->network_change_observer_list_->RemoveObserver(
746 observer);
750 void NetworkChangeNotifier::RemoveMaxBandwidthObserver(
751 MaxBandwidthObserver* observer) {
752 if (g_network_change_notifier) {
753 g_network_change_notifier->max_bandwidth_observer_list_->RemoveObserver(
754 observer);
758 // static
759 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
760 if (g_network_change_notifier)
761 g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
764 // static
765 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
766 ConnectionType type) {
767 if (g_network_change_notifier)
768 g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type);
771 // static
772 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
773 ConnectionType type) {
774 if (g_network_change_notifier)
775 g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
778 // static
779 void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only) {
780 if (g_network_change_notifier)
781 g_network_change_notifier->test_notifications_only_ = test_only;
784 NetworkChangeNotifier::NetworkChangeNotifier(
785 const NetworkChangeCalculatorParams& params
786 /*= NetworkChangeCalculatorParams()*/)
787 : ip_address_observer_list_(new ObserverListThreadSafe<IPAddressObserver>(
788 ObserverListBase<IPAddressObserver>::NOTIFY_EXISTING_ONLY)),
789 connection_type_observer_list_(
790 new ObserverListThreadSafe<ConnectionTypeObserver>(
791 ObserverListBase<ConnectionTypeObserver>::NOTIFY_EXISTING_ONLY)),
792 resolver_state_observer_list_(new ObserverListThreadSafe<DNSObserver>(
793 ObserverListBase<DNSObserver>::NOTIFY_EXISTING_ONLY)),
794 network_change_observer_list_(
795 new ObserverListThreadSafe<NetworkChangeObserver>(
796 ObserverListBase<NetworkChangeObserver>::NOTIFY_EXISTING_ONLY)),
797 max_bandwidth_observer_list_(
798 new ObserverListThreadSafe<MaxBandwidthObserver>(
799 ObserverListBase<MaxBandwidthObserver>::NOTIFY_EXISTING_ONLY)),
800 network_state_(new NetworkState()),
801 network_change_calculator_(new NetworkChangeCalculator(params)),
802 test_notifications_only_(false) {
803 DCHECK(!g_network_change_notifier);
804 g_network_change_notifier = this;
805 network_change_calculator_->Init();
808 #if defined(OS_LINUX)
809 const internal::AddressTrackerLinux*
810 NetworkChangeNotifier::GetAddressTrackerInternal() const {
811 return NULL;
813 #endif
815 double NetworkChangeNotifier::GetCurrentMaxBandwidth() const {
816 // This default implementation conforms to the NetInfo V3 specification but
817 // should be overridden to provide specific bandwidth data based on the
818 // platform.
819 if (GetCurrentConnectionType() == CONNECTION_NONE)
820 return 0.0;
821 return std::numeric_limits<double>::infinity();
824 // static
825 double NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype(
826 ConnectionSubtype subtype) {
827 switch (subtype) {
828 case SUBTYPE_GSM:
829 return 0.01;
830 case SUBTYPE_IDEN:
831 return 0.064;
832 case SUBTYPE_CDMA:
833 return 0.115;
834 case SUBTYPE_1XRTT:
835 return 0.153;
836 case SUBTYPE_GPRS:
837 return 0.237;
838 case SUBTYPE_EDGE:
839 return 0.384;
840 case SUBTYPE_UMTS:
841 return 2.0;
842 case SUBTYPE_EVDO_REV_0:
843 return 2.46;
844 case SUBTYPE_EVDO_REV_A:
845 return 3.1;
846 case SUBTYPE_HSPA:
847 return 3.6;
848 case SUBTYPE_EVDO_REV_B:
849 return 14.7;
850 case SUBTYPE_HSDPA:
851 return 14.3;
852 case SUBTYPE_HSUPA:
853 return 14.4;
854 case SUBTYPE_EHRPD:
855 return 21.0;
856 case SUBTYPE_HSPAP:
857 return 42.0;
858 case SUBTYPE_LTE:
859 return 100.0;
860 case SUBTYPE_LTE_ADVANCED:
861 return 100.0;
862 case SUBTYPE_BLUETOOTH_1_2:
863 return 1.0;
864 case SUBTYPE_BLUETOOTH_2_1:
865 return 3.0;
866 case SUBTYPE_BLUETOOTH_3_0:
867 return 24.0;
868 case SUBTYPE_BLUETOOTH_4_0:
869 return 1.0;
870 case SUBTYPE_ETHERNET:
871 return 10.0;
872 case SUBTYPE_FAST_ETHERNET:
873 return 100.0;
874 case SUBTYPE_GIGABIT_ETHERNET:
875 return 1000.0;
876 case SUBTYPE_10_GIGABIT_ETHERNET:
877 return 10000.0;
878 case SUBTYPE_WIFI_B:
879 return 11.0;
880 case SUBTYPE_WIFI_G:
881 return 54.0;
882 case SUBTYPE_WIFI_N:
883 return 600.0;
884 case SUBTYPE_WIFI_AC:
885 return 1300.0;
886 case SUBTYPE_WIFI_AD:
887 return 7000.0;
888 case SUBTYPE_UNKNOWN:
889 return std::numeric_limits<double>::infinity();
890 case SUBTYPE_NONE:
891 return 0.0;
892 case SUBTYPE_OTHER:
893 return std::numeric_limits<double>::infinity();
895 NOTREACHED();
896 return std::numeric_limits<double>::infinity();
899 // static
900 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
901 if (g_network_change_notifier &&
902 !g_network_change_notifier->test_notifications_only_) {
903 g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
907 // static
908 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
909 if (g_network_change_notifier &&
910 !g_network_change_notifier->test_notifications_only_) {
911 g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(
912 GetConnectionType());
916 // static
917 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
918 ConnectionType type) {
919 if (g_network_change_notifier &&
920 !g_network_change_notifier->test_notifications_only_) {
921 g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
925 // static
926 void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange(
927 double max_bandwidth_mbps) {
928 if (g_network_change_notifier &&
929 !g_network_change_notifier->test_notifications_only_) {
930 g_network_change_notifier->NotifyObserversOfMaxBandwidthChangeImpl(
931 max_bandwidth_mbps);
935 // static
936 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
937 if (g_network_change_notifier &&
938 !g_network_change_notifier->test_notifications_only_) {
939 g_network_change_notifier->NotifyObserversOfDNSChangeImpl();
943 // static
944 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) {
945 if (!g_network_change_notifier)
946 return;
947 g_network_change_notifier->network_state_->SetDnsConfig(config);
948 NotifyObserversOfDNSChange();
951 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
952 ip_address_observer_list_->Notify(FROM_HERE,
953 &IPAddressObserver::OnIPAddressChanged);
956 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
957 ConnectionType type) {
958 connection_type_observer_list_->Notify(
959 FROM_HERE, &ConnectionTypeObserver::OnConnectionTypeChanged, type);
962 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
963 ConnectionType type) {
964 network_change_observer_list_->Notify(
965 FROM_HERE, &NetworkChangeObserver::OnNetworkChanged, type);
968 void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
969 resolver_state_observer_list_->Notify(FROM_HERE, &DNSObserver::OnDNSChanged);
972 void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeImpl(
973 double max_bandwidth_mbps) {
974 max_bandwidth_observer_list_->Notify(
975 FROM_HERE, &MaxBandwidthObserver::OnMaxBandwidthChanged,
976 max_bandwidth_mbps);
979 NetworkChangeNotifier::DisableForTest::DisableForTest()
980 : network_change_notifier_(g_network_change_notifier) {
981 DCHECK(g_network_change_notifier);
982 g_network_change_notifier = NULL;
985 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
986 DCHECK(!g_network_change_notifier);
987 g_network_change_notifier = network_change_notifier_;
990 } // namespace net