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"
9 #include "base/metrics/histogram_macros.h"
10 #include "base/strings/string_util.h"
11 #include "base/synchronization/lock.h"
12 #include "base/threading/thread_checker.h"
13 #include "build/build_config.h"
14 #include "net/base/net_util.h"
15 #include "net/base/network_change_notifier_factory.h"
16 #include "net/dns/dns_config_service.h"
17 #include "net/url_request/url_request.h"
20 #if defined(OS_ANDROID)
21 #include "base/metrics/sparse_histogram.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "net/android/network_library.h"
27 #include "net/base/network_change_notifier_win.h"
28 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
29 #include "net/base/network_change_notifier_linux.h"
30 #elif defined(OS_MACOSX)
31 #include "net/base/network_change_notifier_mac.h"
38 // The actual singleton notifier. The class contract forbids usage of the API
39 // in ways that would require us to place locks around access to this object.
40 // (The prohibition on global non-POD objects makes it tricky to do such a thing
42 NetworkChangeNotifier
* g_network_change_notifier
= NULL
;
44 // Class factory singleton.
45 NetworkChangeNotifierFactory
* g_network_change_notifier_factory
= NULL
;
47 class MockNetworkChangeNotifier
: public NetworkChangeNotifier
{
49 ConnectionType
GetCurrentConnectionType() const override
{
50 return CONNECTION_UNKNOWN
;
57 bool NetworkChangeNotifier::test_notifications_only_
= false;
59 // The main observer class that records UMAs for network events.
60 class HistogramWatcher
61 : public NetworkChangeNotifier::ConnectionTypeObserver
,
62 public NetworkChangeNotifier::IPAddressObserver
,
63 public NetworkChangeNotifier::DNSObserver
,
64 public NetworkChangeNotifier::NetworkChangeObserver
{
67 : last_ip_address_change_(base::TimeTicks::Now()),
68 last_connection_change_(base::TimeTicks::Now()),
69 last_dns_change_(base::TimeTicks::Now()),
70 last_network_change_(base::TimeTicks::Now()),
71 last_connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN
),
72 offline_packets_received_(0),
73 bytes_read_since_last_connection_change_(0),
74 peak_kbps_since_last_connection_change_(0) {}
76 // Registers our three Observer implementations. This is called from the
77 // network thread so that our Observer implementations are also called
78 // from the network thread. This avoids multi-threaded race conditions
79 // because the only other interface, |NotifyDataReceived| is also
80 // only called from the network thread.
82 DCHECK(thread_checker_
.CalledOnValidThread());
83 DCHECK(g_network_change_notifier
);
84 NetworkChangeNotifier::AddConnectionTypeObserver(this);
85 NetworkChangeNotifier::AddIPAddressObserver(this);
86 NetworkChangeNotifier::AddDNSObserver(this);
87 NetworkChangeNotifier::AddNetworkChangeObserver(this);
90 ~HistogramWatcher() override
{
91 DCHECK(thread_checker_
.CalledOnValidThread());
92 DCHECK(g_network_change_notifier
);
93 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
94 NetworkChangeNotifier::RemoveIPAddressObserver(this);
95 NetworkChangeNotifier::RemoveDNSObserver(this);
96 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
99 // NetworkChangeNotifier::IPAddressObserver implementation.
100 void OnIPAddressChanged() override
{
101 DCHECK(thread_checker_
.CalledOnValidThread());
102 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.IPAddressChange",
103 SinceLast(&last_ip_address_change_
));
104 UMA_HISTOGRAM_MEDIUM_TIMES(
105 "NCN.ConnectionTypeChangeToIPAddressChange",
106 last_ip_address_change_
- last_connection_change_
);
109 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
110 void OnConnectionTypeChanged(
111 NetworkChangeNotifier::ConnectionType type
) override
{
112 DCHECK(thread_checker_
.CalledOnValidThread());
113 base::TimeTicks now
= base::TimeTicks::Now();
114 int32_t kilobytes_read
= bytes_read_since_last_connection_change_
/ 1000;
115 base::TimeDelta state_duration
= SinceLast(&last_connection_change_
);
116 if (bytes_read_since_last_connection_change_
) {
117 switch (last_connection_type_
) {
118 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
119 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnUnknown",
120 first_byte_after_connection_change_
);
121 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnUnknown",
122 fastest_RTT_since_last_connection_change_
);
124 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
125 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnEthernet",
126 first_byte_after_connection_change_
);
127 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnEthernet",
128 fastest_RTT_since_last_connection_change_
);
130 case NetworkChangeNotifier::CONNECTION_WIFI
:
131 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnWifi",
132 first_byte_after_connection_change_
);
133 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnWifi",
134 fastest_RTT_since_last_connection_change_
);
136 case NetworkChangeNotifier::CONNECTION_2G
:
137 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn2G",
138 first_byte_after_connection_change_
);
139 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn2G",
140 fastest_RTT_since_last_connection_change_
);
142 case NetworkChangeNotifier::CONNECTION_3G
:
143 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn3G",
144 first_byte_after_connection_change_
);
145 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn3G",
146 fastest_RTT_since_last_connection_change_
);
148 case NetworkChangeNotifier::CONNECTION_4G
:
149 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn4G",
150 first_byte_after_connection_change_
);
151 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn4G",
152 fastest_RTT_since_last_connection_change_
);
154 case NetworkChangeNotifier::CONNECTION_NONE
:
155 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnNone",
156 first_byte_after_connection_change_
);
157 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnNone",
158 fastest_RTT_since_last_connection_change_
);
160 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
161 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnBluetooth",
162 first_byte_after_connection_change_
);
163 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnBluetooth",
164 fastest_RTT_since_last_connection_change_
);
167 if (peak_kbps_since_last_connection_change_
) {
168 switch (last_connection_type_
) {
169 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
170 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnUnknown",
171 peak_kbps_since_last_connection_change_
);
173 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
174 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
175 peak_kbps_since_last_connection_change_
);
177 case NetworkChangeNotifier::CONNECTION_WIFI
:
178 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
179 peak_kbps_since_last_connection_change_
);
181 case NetworkChangeNotifier::CONNECTION_2G
:
182 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
183 peak_kbps_since_last_connection_change_
);
185 case NetworkChangeNotifier::CONNECTION_3G
:
186 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
187 peak_kbps_since_last_connection_change_
);
189 case NetworkChangeNotifier::CONNECTION_4G
:
190 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
191 peak_kbps_since_last_connection_change_
);
193 case NetworkChangeNotifier::CONNECTION_NONE
:
194 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
195 peak_kbps_since_last_connection_change_
);
197 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
198 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnBluetooth",
199 peak_kbps_since_last_connection_change_
);
203 switch (last_connection_type_
) {
204 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
205 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnUnknown", state_duration
);
206 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnUnknown", kilobytes_read
);
208 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
209 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration
);
210 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read
);
212 case NetworkChangeNotifier::CONNECTION_WIFI
:
213 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration
);
214 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read
);
216 case NetworkChangeNotifier::CONNECTION_2G
:
217 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration
);
218 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read
);
220 case NetworkChangeNotifier::CONNECTION_3G
:
221 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration
);
222 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read
);
224 case NetworkChangeNotifier::CONNECTION_4G
:
225 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration
);
226 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read
);
228 case NetworkChangeNotifier::CONNECTION_NONE
:
229 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration
);
230 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read
);
232 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
233 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnBluetooth", state_duration
);
234 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnBluetooth", kilobytes_read
);
238 if (type
!= NetworkChangeNotifier::CONNECTION_NONE
) {
239 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration
);
241 if (offline_packets_received_
) {
242 if ((now
- last_offline_packet_received_
) <
243 base::TimeDelta::FromSeconds(5)) {
244 // We can compare this sum with the sum of NCN.OfflineDataRecv.
245 UMA_HISTOGRAM_COUNTS_10000(
246 "NCN.OfflineDataRecvAny5sBeforeOnline",
247 offline_packets_received_
);
250 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
251 now
- last_offline_packet_received_
);
254 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration
);
257 NetworkChangeNotifier::LogOperatorCodeHistogram(type
);
259 UMA_HISTOGRAM_MEDIUM_TIMES(
260 "NCN.IPAddressChangeToConnectionTypeChange",
261 now
- last_ip_address_change_
);
263 offline_packets_received_
= 0;
264 bytes_read_since_last_connection_change_
= 0;
265 peak_kbps_since_last_connection_change_
= 0;
266 last_connection_type_
= type
;
267 polling_interval_
= base::TimeDelta::FromSeconds(1);
270 // NetworkChangeNotifier::DNSObserver implementation.
271 void OnDNSChanged() override
{
272 DCHECK(thread_checker_
.CalledOnValidThread());
273 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
274 SinceLast(&last_dns_change_
));
277 // NetworkChangeNotifier::NetworkChangeObserver implementation.
278 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type
) override
{
279 DCHECK(thread_checker_
.CalledOnValidThread());
280 if (type
!= NetworkChangeNotifier::CONNECTION_NONE
) {
281 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOnlineChange",
282 SinceLast(&last_network_change_
));
284 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
285 SinceLast(&last_network_change_
));
289 // Record histogram data whenever we receive a packet. Should only be called
290 // from the network thread.
291 void NotifyDataReceived(const URLRequest
& request
, int bytes_read
) {
292 DCHECK(thread_checker_
.CalledOnValidThread());
293 if (IsLocalhost(request
.url().host()) ||
294 !request
.url().SchemeIsHTTPOrHTTPS()) {
298 base::TimeTicks now
= base::TimeTicks::Now();
299 base::TimeDelta request_duration
= now
- request
.creation_time();
300 if (bytes_read_since_last_connection_change_
== 0) {
301 first_byte_after_connection_change_
= now
- last_connection_change_
;
302 fastest_RTT_since_last_connection_change_
= request_duration
;
304 bytes_read_since_last_connection_change_
+= bytes_read
;
305 if (request_duration
< fastest_RTT_since_last_connection_change_
)
306 fastest_RTT_since_last_connection_change_
= request_duration
;
307 // Ignore tiny transfers which will not produce accurate rates.
308 // Ignore zero duration transfers which might cause divide by zero.
309 if (bytes_read
> 10000 &&
310 request_duration
> base::TimeDelta::FromMilliseconds(1) &&
311 request
.creation_time() > last_connection_change_
) {
312 int32_t kbps
= static_cast<int32_t>(bytes_read
* 8 /
313 request_duration
.InMilliseconds());
314 if (kbps
> peak_kbps_since_last_connection_change_
)
315 peak_kbps_since_last_connection_change_
= kbps
;
318 if (last_connection_type_
!= NetworkChangeNotifier::CONNECTION_NONE
)
321 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
322 now
- last_connection_change_
);
323 offline_packets_received_
++;
324 last_offline_packet_received_
= now
;
326 if ((now
- last_polled_connection_
) > polling_interval_
) {
327 polling_interval_
*= 2;
328 last_polled_connection_
= now
;
329 last_polled_connection_type_
=
330 NetworkChangeNotifier::GetConnectionType();
332 if (last_polled_connection_type_
==
333 NetworkChangeNotifier::CONNECTION_NONE
) {
334 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
335 now
- last_connection_change_
);
340 static base::TimeDelta
SinceLast(base::TimeTicks
*last_time
) {
341 base::TimeTicks current_time
= base::TimeTicks::Now();
342 base::TimeDelta delta
= current_time
- *last_time
;
343 *last_time
= current_time
;
347 base::TimeTicks last_ip_address_change_
;
348 base::TimeTicks last_connection_change_
;
349 base::TimeTicks last_dns_change_
;
350 base::TimeTicks last_network_change_
;
351 base::TimeTicks last_offline_packet_received_
;
352 base::TimeTicks last_polled_connection_
;
353 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
354 // first transition to offline and on subsequent transitions. Once offline,
355 // |polling_interval_| doubles as offline data is received and we poll
356 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
358 base::TimeDelta polling_interval_
;
359 // |last_connection_type_| is the last value passed to
360 // |OnConnectionTypeChanged|.
361 NetworkChangeNotifier::ConnectionType last_connection_type_
;
362 // |last_polled_connection_type_| is last result from calling
363 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
364 NetworkChangeNotifier::ConnectionType last_polled_connection_type_
;
365 // Count of how many times NotifyDataReceived() has been called while the
366 // NetworkChangeNotifier thought network connection was offline.
367 int32_t offline_packets_received_
;
368 // Number of bytes of network data received since last connectivity change.
369 int32_t bytes_read_since_last_connection_change_
;
370 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
371 // from URLRequest creation until first byte received.
372 base::TimeDelta fastest_RTT_since_last_connection_change_
;
373 // Time between connectivity change and first network data byte received.
374 base::TimeDelta first_byte_after_connection_change_
;
375 // Rough measurement of peak KB/s witnessed since last connectivity change.
376 // The accuracy is decreased by ignoring these factors:
377 // 1) Multiple URLRequests can occur concurrently.
378 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest.
379 // 3) The transfer time includes at least one RTT while no bytes are read.
380 // Erring on the conservative side is hopefully offset by taking the maximum.
381 int32_t peak_kbps_since_last_connection_change_
;
383 base::ThreadChecker thread_checker_
;
385 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher
);
388 // NetworkState is thread safe.
389 class NetworkChangeNotifier::NetworkState
{
394 void GetDnsConfig(DnsConfig
* config
) const {
395 base::AutoLock
lock(lock_
);
396 *config
= dns_config_
;
399 void SetDnsConfig(const DnsConfig
& dns_config
) {
400 base::AutoLock
lock(lock_
);
401 dns_config_
= dns_config
;
405 mutable base::Lock lock_
;
406 DnsConfig dns_config_
;
409 NetworkChangeNotifier::NetworkChangeCalculatorParams::
410 NetworkChangeCalculatorParams() {
413 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
414 class NetworkChangeNotifier::NetworkChangeCalculator
415 : public ConnectionTypeObserver
,
416 public IPAddressObserver
{
418 NetworkChangeCalculator(const NetworkChangeCalculatorParams
& params
)
420 have_announced_(false),
421 last_announced_connection_type_(CONNECTION_NONE
),
422 pending_connection_type_(CONNECTION_NONE
) {}
425 DCHECK(thread_checker_
.CalledOnValidThread());
426 DCHECK(g_network_change_notifier
);
427 AddConnectionTypeObserver(this);
428 AddIPAddressObserver(this);
431 ~NetworkChangeCalculator() override
{
432 DCHECK(thread_checker_
.CalledOnValidThread());
433 DCHECK(g_network_change_notifier
);
434 RemoveConnectionTypeObserver(this);
435 RemoveIPAddressObserver(this);
438 // NetworkChangeNotifier::IPAddressObserver implementation.
439 void OnIPAddressChanged() override
{
440 DCHECK(thread_checker_
.CalledOnValidThread());
441 base::TimeDelta delay
= last_announced_connection_type_
== CONNECTION_NONE
442 ? params_
.ip_address_offline_delay_
: params_
.ip_address_online_delay_
;
443 // Cancels any previous timer.
444 timer_
.Start(FROM_HERE
, delay
, this, &NetworkChangeCalculator::Notify
);
447 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
448 void OnConnectionTypeChanged(ConnectionType type
) override
{
449 DCHECK(thread_checker_
.CalledOnValidThread());
450 pending_connection_type_
= type
;
451 base::TimeDelta delay
= last_announced_connection_type_
== CONNECTION_NONE
452 ? params_
.connection_type_offline_delay_
453 : params_
.connection_type_online_delay_
;
454 // Cancels any previous timer.
455 timer_
.Start(FROM_HERE
, delay
, this, &NetworkChangeCalculator::Notify
);
460 DCHECK(thread_checker_
.CalledOnValidThread());
461 // Don't bother signaling about dead connections.
462 if (have_announced_
&&
463 (last_announced_connection_type_
== CONNECTION_NONE
) &&
464 (pending_connection_type_
== CONNECTION_NONE
)) {
467 have_announced_
= true;
468 last_announced_connection_type_
= pending_connection_type_
;
469 // Immediately before sending out an online signal, send out an offline
470 // signal to perform any destructive actions before constructive actions.
471 if (pending_connection_type_
!= CONNECTION_NONE
)
472 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE
);
473 NetworkChangeNotifier::NotifyObserversOfNetworkChange(
474 pending_connection_type_
);
477 const NetworkChangeCalculatorParams params_
;
479 // Indicates if NotifyObserversOfNetworkChange has been called yet.
480 bool have_announced_
;
481 // Last value passed to NotifyObserversOfNetworkChange.
482 ConnectionType last_announced_connection_type_
;
483 // Value to pass to NotifyObserversOfNetworkChange when Notify is called.
484 ConnectionType pending_connection_type_
;
485 // Used to delay notifications so duplicates can be combined.
486 base::OneShotTimer
<NetworkChangeCalculator
> timer_
;
488 base::ThreadChecker thread_checker_
;
490 DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator
);
493 NetworkChangeNotifier::~NetworkChangeNotifier() {
494 network_change_calculator_
.reset();
495 DCHECK_EQ(this, g_network_change_notifier
);
496 g_network_change_notifier
= NULL
;
500 void NetworkChangeNotifier::SetFactory(
501 NetworkChangeNotifierFactory
* factory
) {
502 CHECK(!g_network_change_notifier_factory
);
503 g_network_change_notifier_factory
= factory
;
507 NetworkChangeNotifier
* NetworkChangeNotifier::Create() {
508 if (g_network_change_notifier_factory
)
509 return g_network_change_notifier_factory
->CreateInstance();
512 NetworkChangeNotifierWin
* network_change_notifier
=
513 new NetworkChangeNotifierWin();
514 network_change_notifier
->WatchForAddressChange();
515 return network_change_notifier
;
516 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
517 // ChromeOS and Android builds MUST use their own class factory.
518 #if !defined(OS_CHROMEOS)
519 // TODO(oshima): ash_shell do not have access to chromeos'es
520 // notifier yet. Re-enable this when chromeos'es notifier moved to
521 // chromeos root directory. crbug.com/119298.
525 #elif defined(OS_LINUX)
526 return new NetworkChangeNotifierLinux(base::hash_set
<std::string
>());
527 #elif defined(OS_MACOSX)
528 return new NetworkChangeNotifierMac();
536 NetworkChangeNotifier::ConnectionType
537 NetworkChangeNotifier::GetConnectionType() {
538 return g_network_change_notifier
?
539 g_network_change_notifier
->GetCurrentConnectionType() :
544 double NetworkChangeNotifier::GetMaxBandwidth() {
545 return g_network_change_notifier
?
546 g_network_change_notifier
->GetCurrentMaxBandwidth() :
547 std::numeric_limits
<double>::infinity();
551 void NetworkChangeNotifier::GetDnsConfig(DnsConfig
* config
) {
552 if (!g_network_change_notifier
) {
553 *config
= DnsConfig();
555 g_network_change_notifier
->network_state_
->GetDnsConfig(config
);
560 const char* NetworkChangeNotifier::ConnectionTypeToString(
561 ConnectionType type
) {
562 static const char* const kConnectionTypeNames
[] = {
563 "CONNECTION_UNKNOWN",
564 "CONNECTION_ETHERNET",
570 "CONNECTION_BLUETOOTH"
572 static_assert(arraysize(kConnectionTypeNames
) ==
573 NetworkChangeNotifier::CONNECTION_LAST
+ 1,
574 "ConnectionType name count should match");
575 if (type
< CONNECTION_UNKNOWN
|| type
> CONNECTION_LAST
) {
577 return "CONNECTION_INVALID";
579 return kConnectionTypeNames
[type
];
583 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest
& request
,
585 if (!g_network_change_notifier
||
586 !g_network_change_notifier
->histogram_watcher_
) {
589 g_network_change_notifier
->histogram_watcher_
->NotifyDataReceived(request
,
594 void NetworkChangeNotifier::InitHistogramWatcher() {
595 if (!g_network_change_notifier
)
597 g_network_change_notifier
->histogram_watcher_
.reset(new HistogramWatcher());
598 g_network_change_notifier
->histogram_watcher_
->Init();
602 void NetworkChangeNotifier::ShutdownHistogramWatcher() {
603 if (!g_network_change_notifier
)
605 g_network_change_notifier
->histogram_watcher_
.reset();
609 void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type
) {
610 #if defined(OS_ANDROID)
611 // On a connection type change to 2/3/4G, log the network operator MCC/MNC.
612 // Log zero in other cases.
613 unsigned mcc_mnc
= 0;
614 if (type
== NetworkChangeNotifier::CONNECTION_2G
||
615 type
== NetworkChangeNotifier::CONNECTION_3G
||
616 type
== NetworkChangeNotifier::CONNECTION_4G
) {
617 // Log zero if not perfectly converted.
618 if (!base::StringToUint(android::GetTelephonyNetworkOperator(), &mcc_mnc
)) {
622 UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc
);
626 #if defined(OS_LINUX)
628 const internal::AddressTrackerLinux
*
629 NetworkChangeNotifier::GetAddressTracker() {
630 return g_network_change_notifier
?
631 g_network_change_notifier
->GetAddressTrackerInternal() : NULL
;
636 bool NetworkChangeNotifier::IsOffline() {
637 return GetConnectionType() == CONNECTION_NONE
;
641 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type
) {
642 bool is_cellular
= false;
649 case CONNECTION_UNKNOWN
:
650 case CONNECTION_ETHERNET
:
651 case CONNECTION_WIFI
:
652 case CONNECTION_NONE
:
653 case CONNECTION_BLUETOOTH
:
661 NetworkChangeNotifier::ConnectionType
662 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(
663 const NetworkInterfaceList
& interfaces
) {
665 ConnectionType result
= CONNECTION_NONE
;
666 for (size_t i
= 0; i
< interfaces
.size(); ++i
) {
668 if (interfaces
[i
].friendly_name
== "Teredo Tunneling Pseudo-Interface")
671 // Remove VMware network interfaces as they're internal and should not be
672 // used to determine the network connection type.
673 if (base::ToLowerASCII(interfaces
[i
].friendly_name
).find("vmnet") !=
679 result
= interfaces
[i
].type
;
680 } else if (result
!= interfaces
[i
].type
) {
681 return CONNECTION_UNKNOWN
;
688 NetworkChangeNotifier
* NetworkChangeNotifier::CreateMock() {
689 return new MockNetworkChangeNotifier();
692 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver
* observer
) {
693 if (g_network_change_notifier
)
694 g_network_change_notifier
->ip_address_observer_list_
->AddObserver(observer
);
697 void NetworkChangeNotifier::AddConnectionTypeObserver(
698 ConnectionTypeObserver
* observer
) {
699 if (g_network_change_notifier
) {
700 g_network_change_notifier
->connection_type_observer_list_
->AddObserver(
705 void NetworkChangeNotifier::AddDNSObserver(DNSObserver
* observer
) {
706 if (g_network_change_notifier
) {
707 g_network_change_notifier
->resolver_state_observer_list_
->AddObserver(
712 void NetworkChangeNotifier::AddNetworkChangeObserver(
713 NetworkChangeObserver
* observer
) {
714 if (g_network_change_notifier
) {
715 g_network_change_notifier
->network_change_observer_list_
->AddObserver(
720 void NetworkChangeNotifier::AddMaxBandwidthObserver(
721 MaxBandwidthObserver
* observer
) {
722 if (g_network_change_notifier
) {
723 g_network_change_notifier
->max_bandwidth_observer_list_
->AddObserver(
728 void NetworkChangeNotifier::RemoveIPAddressObserver(
729 IPAddressObserver
* observer
) {
730 if (g_network_change_notifier
) {
731 g_network_change_notifier
->ip_address_observer_list_
->RemoveObserver(
736 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
737 ConnectionTypeObserver
* observer
) {
738 if (g_network_change_notifier
) {
739 g_network_change_notifier
->connection_type_observer_list_
->RemoveObserver(
744 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver
* observer
) {
745 if (g_network_change_notifier
) {
746 g_network_change_notifier
->resolver_state_observer_list_
->RemoveObserver(
751 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
752 NetworkChangeObserver
* observer
) {
753 if (g_network_change_notifier
) {
754 g_network_change_notifier
->network_change_observer_list_
->RemoveObserver(
759 void NetworkChangeNotifier::RemoveMaxBandwidthObserver(
760 MaxBandwidthObserver
* observer
) {
761 if (g_network_change_notifier
) {
762 g_network_change_notifier
->max_bandwidth_observer_list_
->RemoveObserver(
768 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
769 if (g_network_change_notifier
)
770 g_network_change_notifier
->NotifyObserversOfIPAddressChangeImpl();
774 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
775 ConnectionType type
) {
776 if (g_network_change_notifier
)
777 g_network_change_notifier
->NotifyObserversOfConnectionTypeChangeImpl(type
);
781 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
782 ConnectionType type
) {
783 if (g_network_change_notifier
)
784 g_network_change_notifier
->NotifyObserversOfNetworkChangeImpl(type
);
788 void NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigReadForTests() {
789 if (g_network_change_notifier
)
790 g_network_change_notifier
->NotifyObserversOfInitialDNSConfigReadImpl();
794 void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only
) {
795 DCHECK(!g_network_change_notifier
);
796 NetworkChangeNotifier::test_notifications_only_
= test_only
;
799 NetworkChangeNotifier::NetworkChangeNotifier(
800 const NetworkChangeCalculatorParams
& params
801 /*= NetworkChangeCalculatorParams()*/)
802 : ip_address_observer_list_(
803 new base::ObserverListThreadSafe
<IPAddressObserver
>(
804 base::ObserverListBase
<IPAddressObserver
>::NOTIFY_EXISTING_ONLY
)),
805 connection_type_observer_list_(
806 new base::ObserverListThreadSafe
<ConnectionTypeObserver
>(
807 base::ObserverListBase
<
808 ConnectionTypeObserver
>::NOTIFY_EXISTING_ONLY
)),
809 resolver_state_observer_list_(
810 new base::ObserverListThreadSafe
<DNSObserver
>(
811 base::ObserverListBase
<DNSObserver
>::NOTIFY_EXISTING_ONLY
)),
812 network_change_observer_list_(new base::ObserverListThreadSafe
<
813 NetworkChangeObserver
>(
814 base::ObserverListBase
<NetworkChangeObserver
>::NOTIFY_EXISTING_ONLY
)),
815 max_bandwidth_observer_list_(new base::ObserverListThreadSafe
<
816 MaxBandwidthObserver
>(
817 base::ObserverListBase
<MaxBandwidthObserver
>::NOTIFY_EXISTING_ONLY
)),
818 network_state_(new NetworkState()),
819 network_change_calculator_(new NetworkChangeCalculator(params
)) {
820 DCHECK(!g_network_change_notifier
);
821 g_network_change_notifier
= this;
822 network_change_calculator_
->Init();
825 #if defined(OS_LINUX)
826 const internal::AddressTrackerLinux
*
827 NetworkChangeNotifier::GetAddressTrackerInternal() const {
832 double NetworkChangeNotifier::GetCurrentMaxBandwidth() const {
833 // This default implementation conforms to the NetInfo V3 specification but
834 // should be overridden to provide specific bandwidth data based on the
836 if (GetCurrentConnectionType() == CONNECTION_NONE
)
838 return std::numeric_limits
<double>::infinity();
842 double NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype(
843 ConnectionSubtype subtype
) {
859 case SUBTYPE_EVDO_REV_0
:
861 case SUBTYPE_EVDO_REV_A
:
865 case SUBTYPE_EVDO_REV_B
:
877 case SUBTYPE_LTE_ADVANCED
:
879 case SUBTYPE_BLUETOOTH_1_2
:
881 case SUBTYPE_BLUETOOTH_2_1
:
883 case SUBTYPE_BLUETOOTH_3_0
:
885 case SUBTYPE_BLUETOOTH_4_0
:
887 case SUBTYPE_ETHERNET
:
889 case SUBTYPE_FAST_ETHERNET
:
891 case SUBTYPE_GIGABIT_ETHERNET
:
893 case SUBTYPE_10_GIGABIT_ETHERNET
:
901 case SUBTYPE_WIFI_AC
:
903 case SUBTYPE_WIFI_AD
:
905 case SUBTYPE_UNKNOWN
:
906 return std::numeric_limits
<double>::infinity();
910 return std::numeric_limits
<double>::infinity();
913 return std::numeric_limits
<double>::infinity();
917 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
918 if (g_network_change_notifier
&&
919 !NetworkChangeNotifier::test_notifications_only_
) {
920 g_network_change_notifier
->NotifyObserversOfIPAddressChangeImpl();
925 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
926 if (g_network_change_notifier
&&
927 !NetworkChangeNotifier::test_notifications_only_
) {
928 g_network_change_notifier
->NotifyObserversOfConnectionTypeChangeImpl(
929 GetConnectionType());
934 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
935 ConnectionType type
) {
936 if (g_network_change_notifier
&&
937 !NetworkChangeNotifier::test_notifications_only_
) {
938 g_network_change_notifier
->NotifyObserversOfNetworkChangeImpl(type
);
943 void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange(
944 double max_bandwidth_mbps
) {
945 if (g_network_change_notifier
&&
946 !NetworkChangeNotifier::test_notifications_only_
) {
947 g_network_change_notifier
->NotifyObserversOfMaxBandwidthChangeImpl(
953 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
954 if (g_network_change_notifier
&&
955 !NetworkChangeNotifier::test_notifications_only_
) {
956 g_network_change_notifier
->NotifyObserversOfDNSChangeImpl();
961 void NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigRead() {
962 if (g_network_change_notifier
&&
963 !NetworkChangeNotifier::test_notifications_only_
) {
964 g_network_change_notifier
->NotifyObserversOfInitialDNSConfigReadImpl();
969 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig
& config
) {
970 if (!g_network_change_notifier
)
972 g_network_change_notifier
->network_state_
->SetDnsConfig(config
);
973 NotifyObserversOfDNSChange();
977 void NetworkChangeNotifier::SetInitialDnsConfig(const DnsConfig
& config
) {
978 if (!g_network_change_notifier
)
981 // Verify we've never received a valid DnsConfig previously.
982 DnsConfig old_config
;
983 g_network_change_notifier
->network_state_
->GetDnsConfig(&old_config
);
984 DCHECK(!old_config
.IsValid());
986 g_network_change_notifier
->network_state_
->SetDnsConfig(config
);
987 NotifyObserversOfInitialDNSConfigRead();
990 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
991 ip_address_observer_list_
->Notify(FROM_HERE
,
992 &IPAddressObserver::OnIPAddressChanged
);
995 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
996 ConnectionType type
) {
997 connection_type_observer_list_
->Notify(
998 FROM_HERE
, &ConnectionTypeObserver::OnConnectionTypeChanged
, type
);
1001 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
1002 ConnectionType type
) {
1003 network_change_observer_list_
->Notify(
1004 FROM_HERE
, &NetworkChangeObserver::OnNetworkChanged
, type
);
1007 void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
1008 resolver_state_observer_list_
->Notify(FROM_HERE
, &DNSObserver::OnDNSChanged
);
1011 void NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigReadImpl() {
1012 resolver_state_observer_list_
->Notify(FROM_HERE
,
1013 &DNSObserver::OnInitialDNSConfigRead
);
1016 void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeImpl(
1017 double max_bandwidth_mbps
) {
1018 max_bandwidth_observer_list_
->Notify(
1019 FROM_HERE
, &MaxBandwidthObserver::OnMaxBandwidthChanged
,
1020 max_bandwidth_mbps
);
1023 NetworkChangeNotifier::DisableForTest::DisableForTest()
1024 : network_change_notifier_(g_network_change_notifier
) {
1025 DCHECK(g_network_change_notifier
);
1026 g_network_change_notifier
= NULL
;
1029 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
1030 DCHECK(!g_network_change_notifier
);
1031 g_network_change_notifier
= network_change_notifier_
;
1034 void NetworkChangeNotifier::DNSObserver::OnInitialDNSConfigRead() {