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.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"
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"
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"
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
41 NetworkChangeNotifier
* g_network_change_notifier
= NULL
;
43 // Class factory singleton.
44 NetworkChangeNotifierFactory
* g_network_change_notifier_factory
= NULL
;
46 class MockNetworkChangeNotifier
: public NetworkChangeNotifier
{
48 ConnectionType
GetCurrentConnectionType() const override
{
49 return CONNECTION_UNKNOWN
;
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
{
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.
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_
);
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_
);
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_
);
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_
);
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_
);
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_
);
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_
);
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_
);
169 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
170 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
171 peak_kbps_since_last_connection_change_
);
173 case NetworkChangeNotifier::CONNECTION_WIFI
:
174 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
175 peak_kbps_since_last_connection_change_
);
177 case NetworkChangeNotifier::CONNECTION_2G
:
178 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
179 peak_kbps_since_last_connection_change_
);
181 case NetworkChangeNotifier::CONNECTION_3G
:
182 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
183 peak_kbps_since_last_connection_change_
);
185 case NetworkChangeNotifier::CONNECTION_4G
:
186 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
187 peak_kbps_since_last_connection_change_
);
189 case NetworkChangeNotifier::CONNECTION_NONE
:
190 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
191 peak_kbps_since_last_connection_change_
);
193 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
194 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnBluetooth",
195 peak_kbps_since_last_connection_change_
);
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
);
204 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
205 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration
);
206 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read
);
208 case NetworkChangeNotifier::CONNECTION_WIFI
:
209 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration
);
210 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read
);
212 case NetworkChangeNotifier::CONNECTION_2G
:
213 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration
);
214 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read
);
216 case NetworkChangeNotifier::CONNECTION_3G
:
217 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration
);
218 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read
);
220 case NetworkChangeNotifier::CONNECTION_4G
:
221 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration
);
222 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read
);
224 case NetworkChangeNotifier::CONNECTION_NONE
:
225 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration
);
226 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read
);
228 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
229 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnBluetooth", state_duration
);
230 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnBluetooth", kilobytes_read
);
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_
);
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_
));
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()) {
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
)
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_
);
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
;
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
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
{
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
;
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
{
414 NetworkChangeCalculator(const NetworkChangeCalculatorParams
& params
)
416 have_announced_(false),
417 last_announced_connection_type_(CONNECTION_NONE
),
418 pending_connection_type_(CONNECTION_NONE
) {}
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
);
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
)) {
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
;
496 void NetworkChangeNotifier::SetFactory(
497 NetworkChangeNotifierFactory
* factory
) {
498 CHECK(!g_network_change_notifier_factory
);
499 g_network_change_notifier_factory
= factory
;
503 NetworkChangeNotifier
* NetworkChangeNotifier::Create() {
504 if (g_network_change_notifier_factory
)
505 return g_network_change_notifier_factory
->CreateInstance();
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.
521 #elif defined(OS_LINUX)
522 return NetworkChangeNotifierLinux::Create();
523 #elif defined(OS_MACOSX)
524 return new NetworkChangeNotifierMac();
532 NetworkChangeNotifier::ConnectionType
533 NetworkChangeNotifier::GetConnectionType() {
534 return g_network_change_notifier
?
535 g_network_change_notifier
->GetCurrentConnectionType() :
540 double NetworkChangeNotifier::GetMaxBandwidth() {
541 return g_network_change_notifier
?
542 g_network_change_notifier
->GetCurrentMaxBandwidth() :
543 std::numeric_limits
<double>::infinity();
547 void NetworkChangeNotifier::GetDnsConfig(DnsConfig
* config
) {
548 if (!g_network_change_notifier
) {
549 *config
= DnsConfig();
551 g_network_change_notifier
->network_state_
->GetDnsConfig(config
);
556 const char* NetworkChangeNotifier::ConnectionTypeToString(
557 ConnectionType type
) {
558 static const char* const kConnectionTypeNames
[] = {
559 "CONNECTION_UNKNOWN",
560 "CONNECTION_ETHERNET",
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
) {
573 return "CONNECTION_INVALID";
575 return kConnectionTypeNames
[type
];
579 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest
& request
,
581 if (!g_network_change_notifier
||
582 !g_network_change_notifier
->histogram_watcher_
) {
585 g_network_change_notifier
->histogram_watcher_
->NotifyDataReceived(request
,
590 void NetworkChangeNotifier::InitHistogramWatcher() {
591 if (!g_network_change_notifier
)
593 g_network_change_notifier
->histogram_watcher_
.reset(new HistogramWatcher());
594 g_network_change_notifier
->histogram_watcher_
->Init();
598 void NetworkChangeNotifier::ShutdownHistogramWatcher() {
599 if (!g_network_change_notifier
)
601 g_network_change_notifier
->histogram_watcher_
.reset();
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
)) {
619 UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc
);
623 #if defined(OS_LINUX)
625 const internal::AddressTrackerLinux
*
626 NetworkChangeNotifier::GetAddressTracker() {
627 return g_network_change_notifier
?
628 g_network_change_notifier
->GetAddressTrackerInternal() : NULL
;
633 bool NetworkChangeNotifier::IsOffline() {
634 return GetConnectionType() == CONNECTION_NONE
;
638 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type
) {
639 bool is_cellular
= false;
646 case CONNECTION_UNKNOWN
:
647 case CONNECTION_ETHERNET
:
648 case CONNECTION_WIFI
:
649 case CONNECTION_NONE
:
650 case CONNECTION_BLUETOOTH
:
658 NetworkChangeNotifier::ConnectionType
659 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(
660 const NetworkInterfaceList
& interfaces
) {
662 ConnectionType result
= CONNECTION_NONE
;
663 for (size_t i
= 0; i
< interfaces
.size(); ++i
) {
665 if (interfaces
[i
].friendly_name
== "Teredo Tunneling Pseudo-Interface")
670 result
= interfaces
[i
].type
;
671 } else if (result
!= interfaces
[i
].type
) {
672 return CONNECTION_UNKNOWN
;
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(
696 void NetworkChangeNotifier::AddDNSObserver(DNSObserver
* observer
) {
697 if (g_network_change_notifier
) {
698 g_network_change_notifier
->resolver_state_observer_list_
->AddObserver(
703 void NetworkChangeNotifier::AddNetworkChangeObserver(
704 NetworkChangeObserver
* observer
) {
705 if (g_network_change_notifier
) {
706 g_network_change_notifier
->network_change_observer_list_
->AddObserver(
711 void NetworkChangeNotifier::AddMaxBandwidthObserver(
712 MaxBandwidthObserver
* observer
) {
713 if (g_network_change_notifier
) {
714 g_network_change_notifier
->max_bandwidth_observer_list_
->AddObserver(
719 void NetworkChangeNotifier::RemoveIPAddressObserver(
720 IPAddressObserver
* observer
) {
721 if (g_network_change_notifier
) {
722 g_network_change_notifier
->ip_address_observer_list_
->RemoveObserver(
727 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
728 ConnectionTypeObserver
* observer
) {
729 if (g_network_change_notifier
) {
730 g_network_change_notifier
->connection_type_observer_list_
->RemoveObserver(
735 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver
* observer
) {
736 if (g_network_change_notifier
) {
737 g_network_change_notifier
->resolver_state_observer_list_
->RemoveObserver(
742 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
743 NetworkChangeObserver
* observer
) {
744 if (g_network_change_notifier
) {
745 g_network_change_notifier
->network_change_observer_list_
->RemoveObserver(
750 void NetworkChangeNotifier::RemoveMaxBandwidthObserver(
751 MaxBandwidthObserver
* observer
) {
752 if (g_network_change_notifier
) {
753 g_network_change_notifier
->max_bandwidth_observer_list_
->RemoveObserver(
759 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
760 if (g_network_change_notifier
)
761 g_network_change_notifier
->NotifyObserversOfIPAddressChangeImpl();
765 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
766 ConnectionType type
) {
767 if (g_network_change_notifier
)
768 g_network_change_notifier
->NotifyObserversOfConnectionTypeChangeImpl(type
);
772 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
773 ConnectionType type
) {
774 if (g_network_change_notifier
)
775 g_network_change_notifier
->NotifyObserversOfNetworkChangeImpl(type
);
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 {
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
819 if (GetCurrentConnectionType() == CONNECTION_NONE
)
821 return std::numeric_limits
<double>::infinity();
825 double NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype(
826 ConnectionSubtype subtype
) {
842 case SUBTYPE_EVDO_REV_0
:
844 case SUBTYPE_EVDO_REV_A
:
848 case SUBTYPE_EVDO_REV_B
:
860 case SUBTYPE_LTE_ADVANCED
:
862 case SUBTYPE_BLUETOOTH_1_2
:
864 case SUBTYPE_BLUETOOTH_2_1
:
866 case SUBTYPE_BLUETOOTH_3_0
:
868 case SUBTYPE_BLUETOOTH_4_0
:
870 case SUBTYPE_ETHERNET
:
872 case SUBTYPE_FAST_ETHERNET
:
874 case SUBTYPE_GIGABIT_ETHERNET
:
876 case SUBTYPE_10_GIGABIT_ETHERNET
:
884 case SUBTYPE_WIFI_AC
:
886 case SUBTYPE_WIFI_AD
:
888 case SUBTYPE_UNKNOWN
:
889 return std::numeric_limits
<double>::infinity();
893 return std::numeric_limits
<double>::infinity();
896 return std::numeric_limits
<double>::infinity();
900 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
901 if (g_network_change_notifier
&&
902 !g_network_change_notifier
->test_notifications_only_
) {
903 g_network_change_notifier
->NotifyObserversOfIPAddressChangeImpl();
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());
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
);
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(
936 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
937 if (g_network_change_notifier
&&
938 !g_network_change_notifier
->test_notifications_only_
) {
939 g_network_change_notifier
->NotifyObserversOfDNSChangeImpl();
944 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig
& config
) {
945 if (!g_network_change_notifier
)
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
,
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_
;