1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/base/network_change_notifier.h"
7 #include "base/metrics/histogram.h"
8 #include "base/synchronization/lock.h"
9 #include "base/threading/thread_checker.h"
10 #include "build/build_config.h"
11 #include "net/base/net_util.h"
12 #include "net/base/network_change_notifier_factory.h"
13 #include "net/dns/dns_config_service.h"
14 #include "net/url_request/url_request.h"
17 #if defined(OS_ANDROID)
18 #include "base/metrics/sparse_histogram.h"
19 #include "base/strings/string_number_conversions.h"
20 #include "net/android/network_library.h"
24 #include "net/base/network_change_notifier_win.h"
25 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
26 #include "net/base/network_change_notifier_linux.h"
27 #elif defined(OS_MACOSX)
28 #include "net/base/network_change_notifier_mac.h"
35 // The actual singleton notifier. The class contract forbids usage of the API
36 // in ways that would require us to place locks around access to this object.
37 // (The prohibition on global non-POD objects makes it tricky to do such a thing
39 NetworkChangeNotifier
* g_network_change_notifier
= NULL
;
41 // Class factory singleton.
42 NetworkChangeNotifierFactory
* g_network_change_notifier_factory
= NULL
;
44 class MockNetworkChangeNotifier
: public NetworkChangeNotifier
{
46 virtual ConnectionType
GetCurrentConnectionType() const OVERRIDE
{
47 return CONNECTION_UNKNOWN
;
53 // The main observer class that records UMAs for network events.
54 class HistogramWatcher
55 : public NetworkChangeNotifier::ConnectionTypeObserver
,
56 public NetworkChangeNotifier::IPAddressObserver
,
57 public NetworkChangeNotifier::DNSObserver
,
58 public NetworkChangeNotifier::NetworkChangeObserver
{
61 : last_ip_address_change_(base::TimeTicks::Now()),
62 last_connection_change_(base::TimeTicks::Now()),
63 last_dns_change_(base::TimeTicks::Now()),
64 last_network_change_(base::TimeTicks::Now()),
65 last_connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN
),
66 offline_packets_received_(0),
67 bytes_read_since_last_connection_change_(0),
68 peak_kbps_since_last_connection_change_(0) {}
70 // Registers our three Observer implementations. This is called from the
71 // network thread so that our Observer implementations are also called
72 // from the network thread. This avoids multi-threaded race conditions
73 // because the only other interface, |NotifyDataReceived| is also
74 // only called from the network thread.
76 DCHECK(thread_checker_
.CalledOnValidThread());
77 DCHECK(g_network_change_notifier
);
78 NetworkChangeNotifier::AddConnectionTypeObserver(this);
79 NetworkChangeNotifier::AddIPAddressObserver(this);
80 NetworkChangeNotifier::AddDNSObserver(this);
81 NetworkChangeNotifier::AddNetworkChangeObserver(this);
84 virtual ~HistogramWatcher() {
85 DCHECK(thread_checker_
.CalledOnValidThread());
86 DCHECK(g_network_change_notifier
);
87 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
88 NetworkChangeNotifier::RemoveIPAddressObserver(this);
89 NetworkChangeNotifier::RemoveDNSObserver(this);
90 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
93 // NetworkChangeNotifier::IPAddressObserver implementation.
94 virtual void OnIPAddressChanged() OVERRIDE
{
95 DCHECK(thread_checker_
.CalledOnValidThread());
96 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.IPAddressChange",
97 SinceLast(&last_ip_address_change_
));
98 UMA_HISTOGRAM_MEDIUM_TIMES(
99 "NCN.ConnectionTypeChangeToIPAddressChange",
100 last_ip_address_change_
- last_connection_change_
);
103 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
104 virtual void OnConnectionTypeChanged(
105 NetworkChangeNotifier::ConnectionType type
) OVERRIDE
{
106 DCHECK(thread_checker_
.CalledOnValidThread());
107 base::TimeTicks now
= base::TimeTicks::Now();
108 int32 kilobytes_read
= bytes_read_since_last_connection_change_
/ 1000;
109 base::TimeDelta state_duration
= SinceLast(&last_connection_change_
);
110 if (bytes_read_since_last_connection_change_
) {
111 switch (last_connection_type_
) {
112 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
113 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnUnknown",
114 first_byte_after_connection_change_
);
115 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnUnknown",
116 fastest_RTT_since_last_connection_change_
);
118 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
119 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnEthernet",
120 first_byte_after_connection_change_
);
121 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnEthernet",
122 fastest_RTT_since_last_connection_change_
);
124 case NetworkChangeNotifier::CONNECTION_WIFI
:
125 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnWifi",
126 first_byte_after_connection_change_
);
127 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnWifi",
128 fastest_RTT_since_last_connection_change_
);
130 case NetworkChangeNotifier::CONNECTION_2G
:
131 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn2G",
132 first_byte_after_connection_change_
);
133 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn2G",
134 fastest_RTT_since_last_connection_change_
);
136 case NetworkChangeNotifier::CONNECTION_3G
:
137 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn3G",
138 first_byte_after_connection_change_
);
139 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn3G",
140 fastest_RTT_since_last_connection_change_
);
142 case NetworkChangeNotifier::CONNECTION_4G
:
143 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn4G",
144 first_byte_after_connection_change_
);
145 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn4G",
146 fastest_RTT_since_last_connection_change_
);
148 case NetworkChangeNotifier::CONNECTION_NONE
:
149 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnNone",
150 first_byte_after_connection_change_
);
151 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnNone",
152 fastest_RTT_since_last_connection_change_
);
154 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
155 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnBluetooth",
156 first_byte_after_connection_change_
);
157 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnBluetooth",
158 fastest_RTT_since_last_connection_change_
);
161 if (peak_kbps_since_last_connection_change_
) {
162 switch (last_connection_type_
) {
163 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
164 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnUnknown",
165 peak_kbps_since_last_connection_change_
);
167 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
168 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
169 peak_kbps_since_last_connection_change_
);
171 case NetworkChangeNotifier::CONNECTION_WIFI
:
172 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
173 peak_kbps_since_last_connection_change_
);
175 case NetworkChangeNotifier::CONNECTION_2G
:
176 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
177 peak_kbps_since_last_connection_change_
);
179 case NetworkChangeNotifier::CONNECTION_3G
:
180 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
181 peak_kbps_since_last_connection_change_
);
183 case NetworkChangeNotifier::CONNECTION_4G
:
184 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
185 peak_kbps_since_last_connection_change_
);
187 case NetworkChangeNotifier::CONNECTION_NONE
:
188 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
189 peak_kbps_since_last_connection_change_
);
191 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
192 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnBluetooth",
193 peak_kbps_since_last_connection_change_
);
197 switch (last_connection_type_
) {
198 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
199 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnUnknown", state_duration
);
200 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnUnknown", kilobytes_read
);
202 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
203 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration
);
204 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read
);
206 case NetworkChangeNotifier::CONNECTION_WIFI
:
207 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration
);
208 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read
);
210 case NetworkChangeNotifier::CONNECTION_2G
:
211 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration
);
212 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read
);
214 case NetworkChangeNotifier::CONNECTION_3G
:
215 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration
);
216 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read
);
218 case NetworkChangeNotifier::CONNECTION_4G
:
219 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration
);
220 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read
);
222 case NetworkChangeNotifier::CONNECTION_NONE
:
223 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration
);
224 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read
);
226 case NetworkChangeNotifier::CONNECTION_BLUETOOTH
:
227 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnBluetooth", state_duration
);
228 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnBluetooth", kilobytes_read
);
232 if (type
!= NetworkChangeNotifier::CONNECTION_NONE
) {
233 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration
);
235 if (offline_packets_received_
) {
236 if ((now
- last_offline_packet_received_
) <
237 base::TimeDelta::FromSeconds(5)) {
238 // We can compare this sum with the sum of NCN.OfflineDataRecv.
239 UMA_HISTOGRAM_COUNTS_10000(
240 "NCN.OfflineDataRecvAny5sBeforeOnline",
241 offline_packets_received_
);
244 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
245 now
- last_offline_packet_received_
);
248 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration
);
251 NetworkChangeNotifier::LogOperatorCodeHistogram(type
);
253 UMA_HISTOGRAM_MEDIUM_TIMES(
254 "NCN.IPAddressChangeToConnectionTypeChange",
255 now
- last_ip_address_change_
);
257 offline_packets_received_
= 0;
258 bytes_read_since_last_connection_change_
= 0;
259 peak_kbps_since_last_connection_change_
= 0;
260 last_connection_type_
= type
;
261 polling_interval_
= base::TimeDelta::FromSeconds(1);
264 // NetworkChangeNotifier::DNSObserver implementation.
265 virtual void OnDNSChanged() OVERRIDE
{
266 DCHECK(thread_checker_
.CalledOnValidThread());
267 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
268 SinceLast(&last_dns_change_
));
271 // NetworkChangeNotifier::NetworkChangeObserver implementation.
272 virtual void OnNetworkChanged(
273 NetworkChangeNotifier::ConnectionType type
) OVERRIDE
{
274 DCHECK(thread_checker_
.CalledOnValidThread());
275 if (type
!= NetworkChangeNotifier::CONNECTION_NONE
) {
276 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOnlineChange",
277 SinceLast(&last_network_change_
));
279 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
280 SinceLast(&last_network_change_
));
284 // Record histogram data whenever we receive a packet. Should only be called
285 // from the network thread.
286 void NotifyDataReceived(const URLRequest
& request
, int bytes_read
) {
287 DCHECK(thread_checker_
.CalledOnValidThread());
288 if (IsLocalhost(request
.url().host()) ||
289 !request
.url().SchemeIsHTTPOrHTTPS()) {
293 base::TimeTicks now
= base::TimeTicks::Now();
294 base::TimeDelta request_duration
= now
- request
.creation_time();
295 if (bytes_read_since_last_connection_change_
== 0) {
296 first_byte_after_connection_change_
= now
- last_connection_change_
;
297 fastest_RTT_since_last_connection_change_
= request_duration
;
299 bytes_read_since_last_connection_change_
+= bytes_read
;
300 if (request_duration
< fastest_RTT_since_last_connection_change_
)
301 fastest_RTT_since_last_connection_change_
= request_duration
;
302 // Ignore tiny transfers which will not produce accurate rates.
303 // Ignore zero duration transfers which might cause divide by zero.
304 if (bytes_read
> 10000 &&
305 request_duration
> base::TimeDelta::FromMilliseconds(1) &&
306 request
.creation_time() > last_connection_change_
) {
307 int32 kbps
= bytes_read
* 8 / request_duration
.InMilliseconds();
308 if (kbps
> peak_kbps_since_last_connection_change_
)
309 peak_kbps_since_last_connection_change_
= kbps
;
312 if (last_connection_type_
!= NetworkChangeNotifier::CONNECTION_NONE
)
315 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
316 now
- last_connection_change_
);
317 offline_packets_received_
++;
318 last_offline_packet_received_
= now
;
320 if ((now
- last_polled_connection_
) > polling_interval_
) {
321 polling_interval_
*= 2;
322 last_polled_connection_
= now
;
323 last_polled_connection_type_
=
324 NetworkChangeNotifier::GetConnectionType();
326 if (last_polled_connection_type_
==
327 NetworkChangeNotifier::CONNECTION_NONE
) {
328 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
329 now
- last_connection_change_
);
334 static base::TimeDelta
SinceLast(base::TimeTicks
*last_time
) {
335 base::TimeTicks current_time
= base::TimeTicks::Now();
336 base::TimeDelta delta
= current_time
- *last_time
;
337 *last_time
= current_time
;
341 base::TimeTicks last_ip_address_change_
;
342 base::TimeTicks last_connection_change_
;
343 base::TimeTicks last_dns_change_
;
344 base::TimeTicks last_network_change_
;
345 base::TimeTicks last_offline_packet_received_
;
346 base::TimeTicks last_polled_connection_
;
347 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
348 // first transition to offline and on subsequent transitions. Once offline,
349 // |polling_interval_| doubles as offline data is received and we poll
350 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
352 base::TimeDelta polling_interval_
;
353 // |last_connection_type_| is the last value passed to
354 // |OnConnectionTypeChanged|.
355 NetworkChangeNotifier::ConnectionType last_connection_type_
;
356 // |last_polled_connection_type_| is last result from calling
357 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
358 NetworkChangeNotifier::ConnectionType last_polled_connection_type_
;
359 // Count of how many times NotifyDataReceived() has been called while the
360 // NetworkChangeNotifier thought network connection was offline.
361 int32 offline_packets_received_
;
362 // Number of bytes of network data received since last connectivity change.
363 int32 bytes_read_since_last_connection_change_
;
364 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
365 // from URLRequest creation until first byte received.
366 base::TimeDelta fastest_RTT_since_last_connection_change_
;
367 // Time between connectivity change and first network data byte received.
368 base::TimeDelta first_byte_after_connection_change_
;
369 // Rough measurement of peak KB/s witnessed since last connectivity change.
370 // The accuracy is decreased by ignoring these factors:
371 // 1) Multiple URLRequests can occur concurrently.
372 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest.
373 // 3) The transfer time includes at least one RTT while no bytes are read.
374 // Erring on the conservative side is hopefully offset by taking the maximum.
375 int32 peak_kbps_since_last_connection_change_
;
377 base::ThreadChecker thread_checker_
;
379 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher
);
382 // NetworkState is thread safe.
383 class NetworkChangeNotifier::NetworkState
{
388 void GetDnsConfig(DnsConfig
* config
) const {
389 base::AutoLock
lock(lock_
);
390 *config
= dns_config_
;
393 void SetDnsConfig(const DnsConfig
& dns_config
) {
394 base::AutoLock
lock(lock_
);
395 dns_config_
= dns_config
;
399 mutable base::Lock lock_
;
400 DnsConfig dns_config_
;
403 NetworkChangeNotifier::NetworkChangeCalculatorParams::
404 NetworkChangeCalculatorParams() {
407 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
408 class NetworkChangeNotifier::NetworkChangeCalculator
409 : public ConnectionTypeObserver
,
410 public IPAddressObserver
{
412 NetworkChangeCalculator(const NetworkChangeCalculatorParams
& params
)
414 have_announced_(false),
415 last_announced_connection_type_(CONNECTION_NONE
),
416 pending_connection_type_(CONNECTION_NONE
) {}
419 DCHECK(thread_checker_
.CalledOnValidThread());
420 DCHECK(g_network_change_notifier
);
421 AddConnectionTypeObserver(this);
422 AddIPAddressObserver(this);
425 virtual ~NetworkChangeCalculator() {
426 DCHECK(thread_checker_
.CalledOnValidThread());
427 DCHECK(g_network_change_notifier
);
428 RemoveConnectionTypeObserver(this);
429 RemoveIPAddressObserver(this);
432 // NetworkChangeNotifier::IPAddressObserver implementation.
433 virtual void OnIPAddressChanged() OVERRIDE
{
434 DCHECK(thread_checker_
.CalledOnValidThread());
435 base::TimeDelta delay
= last_announced_connection_type_
== CONNECTION_NONE
436 ? params_
.ip_address_offline_delay_
: params_
.ip_address_online_delay_
;
437 // Cancels any previous timer.
438 timer_
.Start(FROM_HERE
, delay
, this, &NetworkChangeCalculator::Notify
);
441 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
442 virtual void OnConnectionTypeChanged(ConnectionType type
) OVERRIDE
{
443 DCHECK(thread_checker_
.CalledOnValidThread());
444 pending_connection_type_
= type
;
445 base::TimeDelta delay
= last_announced_connection_type_
== CONNECTION_NONE
446 ? params_
.connection_type_offline_delay_
447 : params_
.connection_type_online_delay_
;
448 // Cancels any previous timer.
449 timer_
.Start(FROM_HERE
, delay
, this, &NetworkChangeCalculator::Notify
);
454 DCHECK(thread_checker_
.CalledOnValidThread());
455 // Don't bother signaling about dead connections.
456 if (have_announced_
&&
457 (last_announced_connection_type_
== CONNECTION_NONE
) &&
458 (pending_connection_type_
== CONNECTION_NONE
)) {
461 have_announced_
= true;
462 last_announced_connection_type_
= pending_connection_type_
;
463 // Immediately before sending out an online signal, send out an offline
464 // signal to perform any destructive actions before constructive actions.
465 if (pending_connection_type_
!= CONNECTION_NONE
)
466 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE
);
467 NetworkChangeNotifier::NotifyObserversOfNetworkChange(
468 pending_connection_type_
);
471 const NetworkChangeCalculatorParams params_
;
473 // Indicates if NotifyObserversOfNetworkChange has been called yet.
474 bool have_announced_
;
475 // Last value passed to NotifyObserversOfNetworkChange.
476 ConnectionType last_announced_connection_type_
;
477 // Value to pass to NotifyObserversOfNetworkChange when Notify is called.
478 ConnectionType pending_connection_type_
;
479 // Used to delay notifications so duplicates can be combined.
480 base::OneShotTimer
<NetworkChangeCalculator
> timer_
;
482 base::ThreadChecker thread_checker_
;
484 DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator
);
487 NetworkChangeNotifier::~NetworkChangeNotifier() {
488 network_change_calculator_
.reset();
489 DCHECK_EQ(this, g_network_change_notifier
);
490 g_network_change_notifier
= NULL
;
494 void NetworkChangeNotifier::SetFactory(
495 NetworkChangeNotifierFactory
* factory
) {
496 CHECK(!g_network_change_notifier_factory
);
497 g_network_change_notifier_factory
= factory
;
501 NetworkChangeNotifier
* NetworkChangeNotifier::Create() {
502 if (g_network_change_notifier_factory
)
503 return g_network_change_notifier_factory
->CreateInstance();
506 NetworkChangeNotifierWin
* network_change_notifier
=
507 new NetworkChangeNotifierWin();
508 network_change_notifier
->WatchForAddressChange();
509 return network_change_notifier
;
510 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
511 // ChromeOS and Android builds MUST use their own class factory.
512 #if !defined(OS_CHROMEOS)
513 // TODO(oshima): ash_shell do not have access to chromeos'es
514 // notifier yet. Re-enable this when chromeos'es notifier moved to
515 // chromeos root directory. crbug.com/119298.
519 #elif defined(OS_LINUX)
520 return NetworkChangeNotifierLinux::Create();
521 #elif defined(OS_MACOSX)
522 return new NetworkChangeNotifierMac();
530 NetworkChangeNotifier::ConnectionType
531 NetworkChangeNotifier::GetConnectionType() {
532 return g_network_change_notifier
?
533 g_network_change_notifier
->GetCurrentConnectionType() :
538 void NetworkChangeNotifier::GetDnsConfig(DnsConfig
* config
) {
539 if (!g_network_change_notifier
) {
540 *config
= DnsConfig();
542 g_network_change_notifier
->network_state_
->GetDnsConfig(config
);
547 const char* NetworkChangeNotifier::ConnectionTypeToString(
548 ConnectionType type
) {
549 static const char* kConnectionTypeNames
[] = {
550 "CONNECTION_UNKNOWN",
551 "CONNECTION_ETHERNET",
557 "CONNECTION_BLUETOOTH"
560 arraysize(kConnectionTypeNames
) ==
561 NetworkChangeNotifier::CONNECTION_LAST
+ 1,
562 ConnectionType_name_count_mismatch
);
563 if (type
< CONNECTION_UNKNOWN
|| type
> CONNECTION_LAST
) {
565 return "CONNECTION_INVALID";
567 return kConnectionTypeNames
[type
];
571 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest
& request
,
573 if (!g_network_change_notifier
||
574 !g_network_change_notifier
->histogram_watcher_
) {
577 g_network_change_notifier
->histogram_watcher_
->NotifyDataReceived(request
,
582 void NetworkChangeNotifier::InitHistogramWatcher() {
583 if (!g_network_change_notifier
)
585 g_network_change_notifier
->histogram_watcher_
.reset(new HistogramWatcher());
586 g_network_change_notifier
->histogram_watcher_
->Init();
590 void NetworkChangeNotifier::ShutdownHistogramWatcher() {
591 if (!g_network_change_notifier
)
593 g_network_change_notifier
->histogram_watcher_
.reset();
597 void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type
) {
598 #if defined(OS_ANDROID)
599 // On a connection type change to 2/3/4G, log the network operator MCC/MNC.
600 // Log zero in other cases.
601 unsigned mcc_mnc
= 0;
602 if (type
== NetworkChangeNotifier::CONNECTION_2G
||
603 type
== NetworkChangeNotifier::CONNECTION_3G
||
604 type
== NetworkChangeNotifier::CONNECTION_4G
) {
605 // Log zero if not perfectly converted.
606 if (!base::StringToUint(
607 net::android::GetTelephonyNetworkOperator(), &mcc_mnc
)) {
611 UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc
);
615 #if defined(OS_LINUX)
617 const internal::AddressTrackerLinux
*
618 NetworkChangeNotifier::GetAddressTracker() {
619 return g_network_change_notifier
?
620 g_network_change_notifier
->GetAddressTrackerInternal() : NULL
;
625 bool NetworkChangeNotifier::IsOffline() {
626 return GetConnectionType() == CONNECTION_NONE
;
630 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type
) {
631 bool is_cellular
= false;
638 case CONNECTION_UNKNOWN
:
639 case CONNECTION_ETHERNET
:
640 case CONNECTION_WIFI
:
641 case CONNECTION_NONE
:
642 case CONNECTION_BLUETOOTH
:
650 NetworkChangeNotifier
* NetworkChangeNotifier::CreateMock() {
651 return new MockNetworkChangeNotifier();
654 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver
* observer
) {
655 if (g_network_change_notifier
)
656 g_network_change_notifier
->ip_address_observer_list_
->AddObserver(observer
);
659 void NetworkChangeNotifier::AddConnectionTypeObserver(
660 ConnectionTypeObserver
* observer
) {
661 if (g_network_change_notifier
) {
662 g_network_change_notifier
->connection_type_observer_list_
->AddObserver(
667 void NetworkChangeNotifier::AddDNSObserver(DNSObserver
* observer
) {
668 if (g_network_change_notifier
) {
669 g_network_change_notifier
->resolver_state_observer_list_
->AddObserver(
674 void NetworkChangeNotifier::AddNetworkChangeObserver(
675 NetworkChangeObserver
* observer
) {
676 if (g_network_change_notifier
) {
677 g_network_change_notifier
->network_change_observer_list_
->AddObserver(
682 void NetworkChangeNotifier::RemoveIPAddressObserver(
683 IPAddressObserver
* observer
) {
684 if (g_network_change_notifier
) {
685 g_network_change_notifier
->ip_address_observer_list_
->RemoveObserver(
690 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
691 ConnectionTypeObserver
* observer
) {
692 if (g_network_change_notifier
) {
693 g_network_change_notifier
->connection_type_observer_list_
->RemoveObserver(
698 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver
* observer
) {
699 if (g_network_change_notifier
) {
700 g_network_change_notifier
->resolver_state_observer_list_
->RemoveObserver(
705 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
706 NetworkChangeObserver
* observer
) {
707 if (g_network_change_notifier
) {
708 g_network_change_notifier
->network_change_observer_list_
->RemoveObserver(
714 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
715 if (g_network_change_notifier
)
716 g_network_change_notifier
->NotifyObserversOfIPAddressChangeImpl();
720 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
721 ConnectionType type
) {
722 if (g_network_change_notifier
)
723 g_network_change_notifier
->NotifyObserversOfConnectionTypeChangeImpl(type
);
727 void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only
) {
728 if (g_network_change_notifier
)
729 g_network_change_notifier
->test_notifications_only_
= test_only
;
732 NetworkChangeNotifier::NetworkChangeNotifier(
733 const NetworkChangeCalculatorParams
& params
734 /*= NetworkChangeCalculatorParams()*/)
735 : ip_address_observer_list_(
736 new ObserverListThreadSafe
<IPAddressObserver
>(
737 ObserverListBase
<IPAddressObserver
>::NOTIFY_EXISTING_ONLY
)),
738 connection_type_observer_list_(
739 new ObserverListThreadSafe
<ConnectionTypeObserver
>(
740 ObserverListBase
<ConnectionTypeObserver
>::NOTIFY_EXISTING_ONLY
)),
741 resolver_state_observer_list_(
742 new ObserverListThreadSafe
<DNSObserver
>(
743 ObserverListBase
<DNSObserver
>::NOTIFY_EXISTING_ONLY
)),
744 network_change_observer_list_(
745 new ObserverListThreadSafe
<NetworkChangeObserver
>(
746 ObserverListBase
<NetworkChangeObserver
>::NOTIFY_EXISTING_ONLY
)),
747 network_state_(new NetworkState()),
748 network_change_calculator_(new NetworkChangeCalculator(params
)),
749 test_notifications_only_(false) {
750 DCHECK(!g_network_change_notifier
);
751 g_network_change_notifier
= this;
752 network_change_calculator_
->Init();
755 #if defined(OS_LINUX)
756 const internal::AddressTrackerLinux
*
757 NetworkChangeNotifier::GetAddressTrackerInternal() const {
763 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
764 if (g_network_change_notifier
&&
765 !g_network_change_notifier
->test_notifications_only_
) {
766 g_network_change_notifier
->NotifyObserversOfIPAddressChangeImpl();
771 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
772 if (g_network_change_notifier
&&
773 !g_network_change_notifier
->test_notifications_only_
) {
774 g_network_change_notifier
->NotifyObserversOfConnectionTypeChangeImpl(
775 GetConnectionType());
780 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
781 ConnectionType type
) {
782 if (g_network_change_notifier
&&
783 !g_network_change_notifier
->test_notifications_only_
) {
784 g_network_change_notifier
->NotifyObserversOfNetworkChangeImpl(type
);
789 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
790 if (g_network_change_notifier
&&
791 !g_network_change_notifier
->test_notifications_only_
) {
792 g_network_change_notifier
->NotifyObserversOfDNSChangeImpl();
797 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig
& config
) {
798 if (!g_network_change_notifier
)
800 g_network_change_notifier
->network_state_
->SetDnsConfig(config
);
801 NotifyObserversOfDNSChange();
804 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
805 ip_address_observer_list_
->Notify(&IPAddressObserver::OnIPAddressChanged
);
808 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
809 ConnectionType type
) {
810 connection_type_observer_list_
->Notify(
811 &ConnectionTypeObserver::OnConnectionTypeChanged
, type
);
814 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
815 ConnectionType type
) {
816 network_change_observer_list_
->Notify(
817 &NetworkChangeObserver::OnNetworkChanged
, type
);
820 void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
821 resolver_state_observer_list_
->Notify(&DNSObserver::OnDNSChanged
);
824 NetworkChangeNotifier::DisableForTest::DisableForTest()
825 : network_change_notifier_(g_network_change_notifier
) {
826 DCHECK(g_network_change_notifier
);
827 g_network_change_notifier
= NULL
;
830 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
831 DCHECK(!g_network_change_notifier
);
832 g_network_change_notifier
= network_change_notifier_
;