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
= bytes_read
* 8 / request_duration
.InMilliseconds();
309 if (kbps
> peak_kbps_since_last_connection_change_
)
310 peak_kbps_since_last_connection_change_
= kbps
;
313 if (last_connection_type_
!= NetworkChangeNotifier::CONNECTION_NONE
)
316 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
317 now
- last_connection_change_
);
318 offline_packets_received_
++;
319 last_offline_packet_received_
= now
;
321 if ((now
- last_polled_connection_
) > polling_interval_
) {
322 polling_interval_
*= 2;
323 last_polled_connection_
= now
;
324 last_polled_connection_type_
=
325 NetworkChangeNotifier::GetConnectionType();
327 if (last_polled_connection_type_
==
328 NetworkChangeNotifier::CONNECTION_NONE
) {
329 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
330 now
- last_connection_change_
);
335 static base::TimeDelta
SinceLast(base::TimeTicks
*last_time
) {
336 base::TimeTicks current_time
= base::TimeTicks::Now();
337 base::TimeDelta delta
= current_time
- *last_time
;
338 *last_time
= current_time
;
342 base::TimeTicks last_ip_address_change_
;
343 base::TimeTicks last_connection_change_
;
344 base::TimeTicks last_dns_change_
;
345 base::TimeTicks last_network_change_
;
346 base::TimeTicks last_offline_packet_received_
;
347 base::TimeTicks last_polled_connection_
;
348 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
349 // first transition to offline and on subsequent transitions. Once offline,
350 // |polling_interval_| doubles as offline data is received and we poll
351 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
353 base::TimeDelta polling_interval_
;
354 // |last_connection_type_| is the last value passed to
355 // |OnConnectionTypeChanged|.
356 NetworkChangeNotifier::ConnectionType last_connection_type_
;
357 // |last_polled_connection_type_| is last result from calling
358 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
359 NetworkChangeNotifier::ConnectionType last_polled_connection_type_
;
360 // Count of how many times NotifyDataReceived() has been called while the
361 // NetworkChangeNotifier thought network connection was offline.
362 int32 offline_packets_received_
;
363 // Number of bytes of network data received since last connectivity change.
364 int32 bytes_read_since_last_connection_change_
;
365 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
366 // from URLRequest creation until first byte received.
367 base::TimeDelta fastest_RTT_since_last_connection_change_
;
368 // Time between connectivity change and first network data byte received.
369 base::TimeDelta first_byte_after_connection_change_
;
370 // Rough measurement of peak KB/s witnessed since last connectivity change.
371 // The accuracy is decreased by ignoring these factors:
372 // 1) Multiple URLRequests can occur concurrently.
373 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest.
374 // 3) The transfer time includes at least one RTT while no bytes are read.
375 // Erring on the conservative side is hopefully offset by taking the maximum.
376 int32 peak_kbps_since_last_connection_change_
;
378 base::ThreadChecker thread_checker_
;
380 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher
);
383 // NetworkState is thread safe.
384 class NetworkChangeNotifier::NetworkState
{
389 void GetDnsConfig(DnsConfig
* config
) const {
390 base::AutoLock
lock(lock_
);
391 *config
= dns_config_
;
394 void SetDnsConfig(const DnsConfig
& dns_config
) {
395 base::AutoLock
lock(lock_
);
396 dns_config_
= dns_config
;
400 mutable base::Lock lock_
;
401 DnsConfig dns_config_
;
404 NetworkChangeNotifier::NetworkChangeCalculatorParams::
405 NetworkChangeCalculatorParams() {
408 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
409 class NetworkChangeNotifier::NetworkChangeCalculator
410 : public ConnectionTypeObserver
,
411 public IPAddressObserver
{
413 NetworkChangeCalculator(const NetworkChangeCalculatorParams
& params
)
415 have_announced_(false),
416 last_announced_connection_type_(CONNECTION_NONE
),
417 pending_connection_type_(CONNECTION_NONE
) {}
420 DCHECK(thread_checker_
.CalledOnValidThread());
421 DCHECK(g_network_change_notifier
);
422 AddConnectionTypeObserver(this);
423 AddIPAddressObserver(this);
426 ~NetworkChangeCalculator() override
{
427 DCHECK(thread_checker_
.CalledOnValidThread());
428 DCHECK(g_network_change_notifier
);
429 RemoveConnectionTypeObserver(this);
430 RemoveIPAddressObserver(this);
433 // NetworkChangeNotifier::IPAddressObserver implementation.
434 void OnIPAddressChanged() override
{
435 DCHECK(thread_checker_
.CalledOnValidThread());
436 base::TimeDelta delay
= last_announced_connection_type_
== CONNECTION_NONE
437 ? params_
.ip_address_offline_delay_
: params_
.ip_address_online_delay_
;
438 // Cancels any previous timer.
439 timer_
.Start(FROM_HERE
, delay
, this, &NetworkChangeCalculator::Notify
);
442 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
443 void OnConnectionTypeChanged(ConnectionType type
) override
{
444 DCHECK(thread_checker_
.CalledOnValidThread());
445 pending_connection_type_
= type
;
446 base::TimeDelta delay
= last_announced_connection_type_
== CONNECTION_NONE
447 ? params_
.connection_type_offline_delay_
448 : params_
.connection_type_online_delay_
;
449 // Cancels any previous timer.
450 timer_
.Start(FROM_HERE
, delay
, this, &NetworkChangeCalculator::Notify
);
455 DCHECK(thread_checker_
.CalledOnValidThread());
456 // Don't bother signaling about dead connections.
457 if (have_announced_
&&
458 (last_announced_connection_type_
== CONNECTION_NONE
) &&
459 (pending_connection_type_
== CONNECTION_NONE
)) {
462 have_announced_
= true;
463 last_announced_connection_type_
= pending_connection_type_
;
464 // Immediately before sending out an online signal, send out an offline
465 // signal to perform any destructive actions before constructive actions.
466 if (pending_connection_type_
!= CONNECTION_NONE
)
467 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE
);
468 NetworkChangeNotifier::NotifyObserversOfNetworkChange(
469 pending_connection_type_
);
472 const NetworkChangeCalculatorParams params_
;
474 // Indicates if NotifyObserversOfNetworkChange has been called yet.
475 bool have_announced_
;
476 // Last value passed to NotifyObserversOfNetworkChange.
477 ConnectionType last_announced_connection_type_
;
478 // Value to pass to NotifyObserversOfNetworkChange when Notify is called.
479 ConnectionType pending_connection_type_
;
480 // Used to delay notifications so duplicates can be combined.
481 base::OneShotTimer
<NetworkChangeCalculator
> timer_
;
483 base::ThreadChecker thread_checker_
;
485 DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator
);
488 NetworkChangeNotifier::~NetworkChangeNotifier() {
489 network_change_calculator_
.reset();
490 DCHECK_EQ(this, g_network_change_notifier
);
491 g_network_change_notifier
= NULL
;
495 void NetworkChangeNotifier::SetFactory(
496 NetworkChangeNotifierFactory
* factory
) {
497 CHECK(!g_network_change_notifier_factory
);
498 g_network_change_notifier_factory
= factory
;
502 NetworkChangeNotifier
* NetworkChangeNotifier::Create() {
503 if (g_network_change_notifier_factory
)
504 return g_network_change_notifier_factory
->CreateInstance();
507 NetworkChangeNotifierWin
* network_change_notifier
=
508 new NetworkChangeNotifierWin();
509 network_change_notifier
->WatchForAddressChange();
510 return network_change_notifier
;
511 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
512 // ChromeOS and Android builds MUST use their own class factory.
513 #if !defined(OS_CHROMEOS)
514 // TODO(oshima): ash_shell do not have access to chromeos'es
515 // notifier yet. Re-enable this when chromeos'es notifier moved to
516 // chromeos root directory. crbug.com/119298.
520 #elif defined(OS_LINUX)
521 return NetworkChangeNotifierLinux::Create();
522 #elif defined(OS_MACOSX)
523 return new NetworkChangeNotifierMac();
531 NetworkChangeNotifier::ConnectionType
532 NetworkChangeNotifier::GetConnectionType() {
533 return g_network_change_notifier
?
534 g_network_change_notifier
->GetCurrentConnectionType() :
539 double NetworkChangeNotifier::GetMaxBandwidth() {
540 return g_network_change_notifier
?
541 g_network_change_notifier
->GetCurrentMaxBandwidth() :
542 std::numeric_limits
<double>::infinity();
546 void NetworkChangeNotifier::GetDnsConfig(DnsConfig
* config
) {
547 if (!g_network_change_notifier
) {
548 *config
= DnsConfig();
550 g_network_change_notifier
->network_state_
->GetDnsConfig(config
);
555 const char* NetworkChangeNotifier::ConnectionTypeToString(
556 ConnectionType type
) {
557 static const char* kConnectionTypeNames
[] = {
558 "CONNECTION_UNKNOWN",
559 "CONNECTION_ETHERNET",
565 "CONNECTION_BLUETOOTH"
568 arraysize(kConnectionTypeNames
) ==
569 NetworkChangeNotifier::CONNECTION_LAST
+ 1,
570 ConnectionType_name_count_mismatch
);
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
* NetworkChangeNotifier::CreateMock() {
659 return new MockNetworkChangeNotifier();
662 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver
* observer
) {
663 if (g_network_change_notifier
)
664 g_network_change_notifier
->ip_address_observer_list_
->AddObserver(observer
);
667 void NetworkChangeNotifier::AddConnectionTypeObserver(
668 ConnectionTypeObserver
* observer
) {
669 if (g_network_change_notifier
) {
670 g_network_change_notifier
->connection_type_observer_list_
->AddObserver(
675 void NetworkChangeNotifier::AddDNSObserver(DNSObserver
* observer
) {
676 if (g_network_change_notifier
) {
677 g_network_change_notifier
->resolver_state_observer_list_
->AddObserver(
682 void NetworkChangeNotifier::AddNetworkChangeObserver(
683 NetworkChangeObserver
* observer
) {
684 if (g_network_change_notifier
) {
685 g_network_change_notifier
->network_change_observer_list_
->AddObserver(
690 void NetworkChangeNotifier::RemoveIPAddressObserver(
691 IPAddressObserver
* observer
) {
692 if (g_network_change_notifier
) {
693 g_network_change_notifier
->ip_address_observer_list_
->RemoveObserver(
698 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
699 ConnectionTypeObserver
* observer
) {
700 if (g_network_change_notifier
) {
701 g_network_change_notifier
->connection_type_observer_list_
->RemoveObserver(
706 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver
* observer
) {
707 if (g_network_change_notifier
) {
708 g_network_change_notifier
->resolver_state_observer_list_
->RemoveObserver(
713 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
714 NetworkChangeObserver
* observer
) {
715 if (g_network_change_notifier
) {
716 g_network_change_notifier
->network_change_observer_list_
->RemoveObserver(
722 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
723 if (g_network_change_notifier
)
724 g_network_change_notifier
->NotifyObserversOfIPAddressChangeImpl();
728 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
729 ConnectionType type
) {
730 if (g_network_change_notifier
)
731 g_network_change_notifier
->NotifyObserversOfConnectionTypeChangeImpl(type
);
735 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
736 ConnectionType type
) {
737 if (g_network_change_notifier
)
738 g_network_change_notifier
->NotifyObserversOfNetworkChangeImpl(type
);
742 void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only
) {
743 if (g_network_change_notifier
)
744 g_network_change_notifier
->test_notifications_only_
= test_only
;
747 NetworkChangeNotifier::NetworkChangeNotifier(
748 const NetworkChangeCalculatorParams
& params
749 /*= NetworkChangeCalculatorParams()*/)
750 : ip_address_observer_list_(
751 new ObserverListThreadSafe
<IPAddressObserver
>(
752 ObserverListBase
<IPAddressObserver
>::NOTIFY_EXISTING_ONLY
)),
753 connection_type_observer_list_(
754 new ObserverListThreadSafe
<ConnectionTypeObserver
>(
755 ObserverListBase
<ConnectionTypeObserver
>::NOTIFY_EXISTING_ONLY
)),
756 resolver_state_observer_list_(
757 new ObserverListThreadSafe
<DNSObserver
>(
758 ObserverListBase
<DNSObserver
>::NOTIFY_EXISTING_ONLY
)),
759 network_change_observer_list_(
760 new ObserverListThreadSafe
<NetworkChangeObserver
>(
761 ObserverListBase
<NetworkChangeObserver
>::NOTIFY_EXISTING_ONLY
)),
762 network_state_(new NetworkState()),
763 network_change_calculator_(new NetworkChangeCalculator(params
)),
764 test_notifications_only_(false) {
765 DCHECK(!g_network_change_notifier
);
766 g_network_change_notifier
= this;
767 network_change_calculator_
->Init();
770 #if defined(OS_LINUX)
771 const internal::AddressTrackerLinux
*
772 NetworkChangeNotifier::GetAddressTrackerInternal() const {
777 double NetworkChangeNotifier::GetCurrentMaxBandwidth() const {
778 // This default implementation conforms to the NetInfo V3 specification but
779 // should be overridden to provide specific bandwidth data based on the
781 if (GetCurrentConnectionType() == CONNECTION_NONE
)
783 return std::numeric_limits
<double>::infinity();
787 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
788 if (g_network_change_notifier
&&
789 !g_network_change_notifier
->test_notifications_only_
) {
790 g_network_change_notifier
->NotifyObserversOfIPAddressChangeImpl();
795 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
796 if (g_network_change_notifier
&&
797 !g_network_change_notifier
->test_notifications_only_
) {
798 g_network_change_notifier
->NotifyObserversOfConnectionTypeChangeImpl(
799 GetConnectionType());
804 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
805 ConnectionType type
) {
806 if (g_network_change_notifier
&&
807 !g_network_change_notifier
->test_notifications_only_
) {
808 g_network_change_notifier
->NotifyObserversOfNetworkChangeImpl(type
);
813 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
814 if (g_network_change_notifier
&&
815 !g_network_change_notifier
->test_notifications_only_
) {
816 g_network_change_notifier
->NotifyObserversOfDNSChangeImpl();
821 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig
& config
) {
822 if (!g_network_change_notifier
)
824 g_network_change_notifier
->network_state_
->SetDnsConfig(config
);
825 NotifyObserversOfDNSChange();
828 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
829 ip_address_observer_list_
->Notify(&IPAddressObserver::OnIPAddressChanged
);
832 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
833 ConnectionType type
) {
834 connection_type_observer_list_
->Notify(
835 &ConnectionTypeObserver::OnConnectionTypeChanged
, type
);
838 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
839 ConnectionType type
) {
840 network_change_observer_list_
->Notify(
841 &NetworkChangeObserver::OnNetworkChanged
, type
);
844 void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
845 resolver_state_observer_list_
->Notify(&DNSObserver::OnDNSChanged
);
848 NetworkChangeNotifier::DisableForTest::DisableForTest()
849 : network_change_notifier_(g_network_change_notifier
) {
850 DCHECK(g_network_change_notifier
);
851 g_network_change_notifier
= NULL
;
854 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
855 DCHECK(!g_network_change_notifier
);
856 g_network_change_notifier
= network_change_notifier_
;