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 "build/build_config.h"
10 #include "net/base/net_util.h"
11 #include "net/base/network_change_notifier_factory.h"
12 #include "net/dns/dns_config_service.h"
13 #include "net/url_request/url_request.h"
17 #include "net/base/network_change_notifier_win.h"
18 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
19 #include "net/base/network_change_notifier_linux.h"
20 #elif defined(OS_MACOSX)
21 #include "net/base/network_change_notifier_mac.h"
28 // The actual singleton notifier. The class contract forbids usage of the API
29 // in ways that would require us to place locks around access to this object.
30 // (The prohibition on global non-POD objects makes it tricky to do such a thing
32 NetworkChangeNotifier
* g_network_change_notifier
= NULL
;
34 // Class factory singleton.
35 NetworkChangeNotifierFactory
* g_network_change_notifier_factory
= NULL
;
37 class MockNetworkChangeNotifier
: public NetworkChangeNotifier
{
39 virtual ConnectionType
GetCurrentConnectionType() const OVERRIDE
{
40 return CONNECTION_UNKNOWN
;
46 // The main observer class that records UMAs for network events.
47 class HistogramWatcher
48 : public NetworkChangeNotifier::ConnectionTypeObserver
,
49 public NetworkChangeNotifier::IPAddressObserver
,
50 public NetworkChangeNotifier::DNSObserver
,
51 public NetworkChangeNotifier::NetworkChangeObserver
{
54 : last_ip_address_change_(base::TimeTicks::Now()),
55 last_connection_change_(base::TimeTicks::Now()),
56 last_dns_change_(base::TimeTicks::Now()),
57 last_network_change_(base::TimeTicks::Now()),
58 last_connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN
),
59 offline_packets_received_(0),
60 bytes_read_since_last_connection_change_(0),
61 peak_kbps_since_last_connection_change_(0) {}
63 // Registers our three Observer implementations. This is called from the
64 // network thread so that our Observer implementations are also called
65 // from the network thread. This avoids multi-threaded race conditions
66 // because the only other interface, |NotifyDataReceived| is also
67 // only called from the network thread.
69 NetworkChangeNotifier::AddConnectionTypeObserver(this);
70 NetworkChangeNotifier::AddIPAddressObserver(this);
71 NetworkChangeNotifier::AddDNSObserver(this);
72 NetworkChangeNotifier::AddNetworkChangeObserver(this);
75 virtual ~HistogramWatcher() {}
77 // NetworkChangeNotifier::IPAddressObserver implementation.
78 virtual void OnIPAddressChanged() OVERRIDE
{
79 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.IPAddressChange",
80 SinceLast(&last_ip_address_change_
));
81 UMA_HISTOGRAM_MEDIUM_TIMES(
82 "NCN.ConnectionTypeChangeToIPAddressChange",
83 last_ip_address_change_
- last_connection_change_
);
86 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
87 virtual void OnConnectionTypeChanged(
88 NetworkChangeNotifier::ConnectionType type
) OVERRIDE
{
89 base::TimeTicks now
= base::TimeTicks::Now();
90 int32 kilobytes_read
= bytes_read_since_last_connection_change_
/ 1000;
91 base::TimeDelta state_duration
= SinceLast(&last_connection_change_
);
92 if (bytes_read_since_last_connection_change_
) {
93 switch (last_connection_type_
) {
94 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
95 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnUnknown",
96 first_byte_after_connection_change_
);
97 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnUnknown",
98 fastest_RTT_since_last_connection_change_
);
100 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
101 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnEthernet",
102 first_byte_after_connection_change_
);
103 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnEthernet",
104 fastest_RTT_since_last_connection_change_
);
106 case NetworkChangeNotifier::CONNECTION_WIFI
:
107 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnWifi",
108 first_byte_after_connection_change_
);
109 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnWifi",
110 fastest_RTT_since_last_connection_change_
);
112 case NetworkChangeNotifier::CONNECTION_2G
:
113 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn2G",
114 first_byte_after_connection_change_
);
115 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn2G",
116 fastest_RTT_since_last_connection_change_
);
118 case NetworkChangeNotifier::CONNECTION_3G
:
119 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn3G",
120 first_byte_after_connection_change_
);
121 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn3G",
122 fastest_RTT_since_last_connection_change_
);
124 case NetworkChangeNotifier::CONNECTION_4G
:
125 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn4G",
126 first_byte_after_connection_change_
);
127 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn4G",
128 fastest_RTT_since_last_connection_change_
);
130 case NetworkChangeNotifier::CONNECTION_NONE
:
131 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnNone",
132 first_byte_after_connection_change_
);
133 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnNone",
134 fastest_RTT_since_last_connection_change_
);
138 if (peak_kbps_since_last_connection_change_
) {
139 switch (last_connection_type_
) {
140 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
141 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnUnknown",
142 peak_kbps_since_last_connection_change_
);
144 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
145 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
146 peak_kbps_since_last_connection_change_
);
148 case NetworkChangeNotifier::CONNECTION_WIFI
:
149 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
150 peak_kbps_since_last_connection_change_
);
152 case NetworkChangeNotifier::CONNECTION_2G
:
153 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
154 peak_kbps_since_last_connection_change_
);
156 case NetworkChangeNotifier::CONNECTION_3G
:
157 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
158 peak_kbps_since_last_connection_change_
);
160 case NetworkChangeNotifier::CONNECTION_4G
:
161 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
162 peak_kbps_since_last_connection_change_
);
164 case NetworkChangeNotifier::CONNECTION_NONE
:
165 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
166 peak_kbps_since_last_connection_change_
);
170 switch (last_connection_type_
) {
171 case NetworkChangeNotifier::CONNECTION_UNKNOWN
:
172 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnUnknown", state_duration
);
173 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnUnknown", kilobytes_read
);
175 case NetworkChangeNotifier::CONNECTION_ETHERNET
:
176 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration
);
177 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read
);
179 case NetworkChangeNotifier::CONNECTION_WIFI
:
180 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration
);
181 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read
);
183 case NetworkChangeNotifier::CONNECTION_2G
:
184 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration
);
185 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read
);
187 case NetworkChangeNotifier::CONNECTION_3G
:
188 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration
);
189 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read
);
191 case NetworkChangeNotifier::CONNECTION_4G
:
192 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration
);
193 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read
);
195 case NetworkChangeNotifier::CONNECTION_NONE
:
196 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration
);
197 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read
);
201 if (type
!= NetworkChangeNotifier::CONNECTION_NONE
) {
202 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration
);
204 if (offline_packets_received_
) {
205 if ((now
- last_offline_packet_received_
) <
206 base::TimeDelta::FromSeconds(5)) {
207 // We can compare this sum with the sum of NCN.OfflineDataRecv.
208 UMA_HISTOGRAM_COUNTS_10000(
209 "NCN.OfflineDataRecvAny5sBeforeOnline",
210 offline_packets_received_
);
213 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
214 now
- last_offline_packet_received_
);
217 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration
);
219 UMA_HISTOGRAM_MEDIUM_TIMES(
220 "NCN.IPAddressChangeToConnectionTypeChange",
221 now
- last_ip_address_change_
);
223 offline_packets_received_
= 0;
224 bytes_read_since_last_connection_change_
= 0;
225 peak_kbps_since_last_connection_change_
= 0;
226 last_connection_type_
= type
;
227 polling_interval_
= base::TimeDelta::FromSeconds(1);
230 // NetworkChangeNotifier::DNSObserver implementation.
231 virtual void OnDNSChanged() OVERRIDE
{
232 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
233 SinceLast(&last_dns_change_
));
236 // NetworkChangeNotifier::NetworkChangeObserver implementation.
237 virtual void OnNetworkChanged(
238 NetworkChangeNotifier::ConnectionType type
) OVERRIDE
{
239 if (type
!= NetworkChangeNotifier::CONNECTION_NONE
) {
240 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOnlineChange",
241 SinceLast(&last_network_change_
));
243 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
244 SinceLast(&last_network_change_
));
248 // Record histogram data whenever we receive a packet. Should only be called
249 // from the network thread.
250 void NotifyDataReceived(const URLRequest
& request
, int bytes_read
) {
251 if (IsLocalhost(request
.url().host()) ||
252 !request
.url().SchemeIsHTTPOrHTTPS()) {
256 base::TimeTicks now
= base::TimeTicks::Now();
257 base::TimeDelta request_duration
= now
- request
.creation_time();
258 if (bytes_read_since_last_connection_change_
== 0) {
259 first_byte_after_connection_change_
= now
- last_connection_change_
;
260 fastest_RTT_since_last_connection_change_
= request_duration
;
262 bytes_read_since_last_connection_change_
+= bytes_read
;
263 if (request_duration
< fastest_RTT_since_last_connection_change_
)
264 fastest_RTT_since_last_connection_change_
= request_duration
;
265 // Ignore tiny transfers which will not produce accurate rates.
266 // Ignore zero duration transfers which might cause divide by zero.
267 if (bytes_read
> 10000 &&
268 request_duration
> base::TimeDelta::FromMilliseconds(1) &&
269 request
.creation_time() > last_connection_change_
) {
270 int32 kbps
= bytes_read
* 8 / request_duration
.InMilliseconds();
271 if (kbps
> peak_kbps_since_last_connection_change_
)
272 peak_kbps_since_last_connection_change_
= kbps
;
275 if (last_connection_type_
!= NetworkChangeNotifier::CONNECTION_NONE
)
278 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
279 now
- last_connection_change_
);
280 offline_packets_received_
++;
281 last_offline_packet_received_
= now
;
283 if ((now
- last_polled_connection_
) > polling_interval_
) {
284 polling_interval_
*= 2;
285 last_polled_connection_
= now
;
286 last_polled_connection_type_
=
287 NetworkChangeNotifier::GetConnectionType();
289 if (last_polled_connection_type_
==
290 NetworkChangeNotifier::CONNECTION_NONE
) {
291 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
292 now
- last_connection_change_
);
297 static base::TimeDelta
SinceLast(base::TimeTicks
*last_time
) {
298 base::TimeTicks current_time
= base::TimeTicks::Now();
299 base::TimeDelta delta
= current_time
- *last_time
;
300 *last_time
= current_time
;
304 base::TimeTicks last_ip_address_change_
;
305 base::TimeTicks last_connection_change_
;
306 base::TimeTicks last_dns_change_
;
307 base::TimeTicks last_network_change_
;
308 base::TimeTicks last_offline_packet_received_
;
309 base::TimeTicks last_polled_connection_
;
310 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
311 // first transition to offline and on subsequent transitions. Once offline,
312 // |polling_interval_| doubles as offline data is received and we poll
313 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
315 base::TimeDelta polling_interval_
;
316 // |last_connection_type_| is the last value passed to
317 // |OnConnectionTypeChanged|.
318 NetworkChangeNotifier::ConnectionType last_connection_type_
;
319 // |last_polled_connection_type_| is last result from calling
320 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
321 NetworkChangeNotifier::ConnectionType last_polled_connection_type_
;
322 // Count of how many times NotifyDataReceived() has been called while the
323 // NetworkChangeNotifier thought network connection was offline.
324 int32 offline_packets_received_
;
325 // Number of bytes of network data received since last connectivity change.
326 int32 bytes_read_since_last_connection_change_
;
327 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
328 // from URLRequest creation until first byte received.
329 base::TimeDelta fastest_RTT_since_last_connection_change_
;
330 // Time between connectivity change and first network data byte received.
331 base::TimeDelta first_byte_after_connection_change_
;
332 // Rough measurement of peak KB/s witnessed since last connectivity change.
333 // The accuracy is decreased by ignoring these factors:
334 // 1) Multiple URLRequests can occur concurrently.
335 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest.
336 // 3) The transfer time includes at least one RTT while no bytes are read.
337 // Erring on the conservative side is hopefully offset by taking the maximum.
338 int32 peak_kbps_since_last_connection_change_
;
340 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher
);
343 // NetworkState is thread safe.
344 class NetworkChangeNotifier::NetworkState
{
349 void GetDnsConfig(DnsConfig
* config
) const {
350 base::AutoLock
lock(lock_
);
351 *config
= dns_config_
;
354 void SetDnsConfig(const DnsConfig
& dns_config
) {
355 base::AutoLock
lock(lock_
);
356 dns_config_
= dns_config
;
360 mutable base::Lock lock_
;
361 DnsConfig dns_config_
;
364 NetworkChangeNotifier::NetworkChangeCalculatorParams::
365 NetworkChangeCalculatorParams() {
368 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
369 class NetworkChangeNotifier::NetworkChangeCalculator
370 : public ConnectionTypeObserver
,
371 public IPAddressObserver
{
373 NetworkChangeCalculator(const NetworkChangeCalculatorParams
& params
)
375 have_announced_(false),
376 last_announced_connection_type_(CONNECTION_NONE
),
377 pending_connection_type_(CONNECTION_NONE
) {}
380 AddConnectionTypeObserver(this);
381 AddIPAddressObserver(this);
384 virtual ~NetworkChangeCalculator() {
385 RemoveConnectionTypeObserver(this);
386 RemoveIPAddressObserver(this);
389 // NetworkChangeNotifier::IPAddressObserver implementation.
390 virtual void OnIPAddressChanged() OVERRIDE
{
391 base::TimeDelta delay
= last_announced_connection_type_
== CONNECTION_NONE
392 ? params_
.ip_address_offline_delay_
: params_
.ip_address_online_delay_
;
393 // Cancels any previous timer.
394 timer_
.Start(FROM_HERE
, delay
, this, &NetworkChangeCalculator::Notify
);
397 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
398 virtual void OnConnectionTypeChanged(ConnectionType type
) OVERRIDE
{
399 pending_connection_type_
= type
;
400 base::TimeDelta delay
= last_announced_connection_type_
== CONNECTION_NONE
401 ? params_
.connection_type_offline_delay_
402 : params_
.connection_type_online_delay_
;
403 // Cancels any previous timer.
404 timer_
.Start(FROM_HERE
, delay
, this, &NetworkChangeCalculator::Notify
);
409 // Don't bother signaling about dead connections.
410 if (have_announced_
&&
411 (last_announced_connection_type_
== CONNECTION_NONE
) &&
412 (pending_connection_type_
== CONNECTION_NONE
)) {
415 have_announced_
= true;
416 last_announced_connection_type_
= pending_connection_type_
;
417 // Immediately before sending out an online signal, send out an offline
418 // signal to perform any destructive actions before constructive actions.
419 if (pending_connection_type_
!= CONNECTION_NONE
)
420 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE
);
421 NetworkChangeNotifier::NotifyObserversOfNetworkChange(
422 pending_connection_type_
);
425 const NetworkChangeCalculatorParams params_
;
427 // Indicates if NotifyObserversOfNetworkChange has been called yet.
428 bool have_announced_
;
429 // Last value passed to NotifyObserversOfNetworkChange.
430 ConnectionType last_announced_connection_type_
;
431 // Value to pass to NotifyObserversOfNetworkChange when Notify is called.
432 ConnectionType pending_connection_type_
;
433 // Used to delay notifications so duplicates can be combined.
434 base::OneShotTimer
<NetworkChangeCalculator
> timer_
;
437 NetworkChangeNotifier::~NetworkChangeNotifier() {
438 DCHECK_EQ(this, g_network_change_notifier
);
439 g_network_change_notifier
= NULL
;
443 void NetworkChangeNotifier::SetFactory(
444 NetworkChangeNotifierFactory
* factory
) {
445 CHECK(!g_network_change_notifier_factory
);
446 g_network_change_notifier_factory
= factory
;
450 NetworkChangeNotifier
* NetworkChangeNotifier::Create() {
451 if (g_network_change_notifier_factory
)
452 return g_network_change_notifier_factory
->CreateInstance();
455 NetworkChangeNotifierWin
* network_change_notifier
=
456 new NetworkChangeNotifierWin();
457 network_change_notifier
->WatchForAddressChange();
458 return network_change_notifier
;
459 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
460 // ChromeOS and Android builds MUST use their own class factory.
461 #if !defined(OS_CHROMEOS)
462 // TODO(oshima): ash_shell do not have access to chromeos'es
463 // notifier yet. Re-enable this when chromeos'es notifier moved to
464 // chromeos root directory. crbug.com/119298.
468 #elif defined(OS_LINUX)
469 return NetworkChangeNotifierLinux::Create();
470 #elif defined(OS_MACOSX)
471 return new NetworkChangeNotifierMac();
479 NetworkChangeNotifier::ConnectionType
480 NetworkChangeNotifier::GetConnectionType() {
481 return g_network_change_notifier
?
482 g_network_change_notifier
->GetCurrentConnectionType() :
487 void NetworkChangeNotifier::GetDnsConfig(DnsConfig
* config
) {
488 if (!g_network_change_notifier
) {
489 *config
= DnsConfig();
491 g_network_change_notifier
->network_state_
->GetDnsConfig(config
);
496 const char* NetworkChangeNotifier::ConnectionTypeToString(
497 ConnectionType type
) {
498 static const char* kConnectionTypeNames
[] = {
499 "CONNECTION_UNKNOWN",
500 "CONNECTION_ETHERNET",
508 arraysize(kConnectionTypeNames
) ==
509 NetworkChangeNotifier::CONNECTION_NONE
+ 1,
510 ConnectionType_name_count_mismatch
);
511 if (type
< CONNECTION_UNKNOWN
|| type
> CONNECTION_NONE
) {
513 return "CONNECTION_INVALID";
515 return kConnectionTypeNames
[type
];
519 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest
& request
,
521 if (!g_network_change_notifier
)
523 g_network_change_notifier
->histogram_watcher_
->NotifyDataReceived(request
,
528 void NetworkChangeNotifier::InitHistogramWatcher() {
529 if (!g_network_change_notifier
)
531 g_network_change_notifier
->histogram_watcher_
->Init();
534 #if defined(OS_LINUX)
536 const internal::AddressTrackerLinux
*
537 NetworkChangeNotifier::GetAddressTracker() {
538 return g_network_change_notifier
?
539 g_network_change_notifier
->GetAddressTrackerInternal() : NULL
;
544 bool NetworkChangeNotifier::IsOffline() {
545 return GetConnectionType() == CONNECTION_NONE
;
549 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type
) {
550 bool is_cellular
= false;
557 case CONNECTION_UNKNOWN
:
558 case CONNECTION_ETHERNET
:
559 case CONNECTION_WIFI
:
560 case CONNECTION_NONE
:
568 NetworkChangeNotifier
* NetworkChangeNotifier::CreateMock() {
569 return new MockNetworkChangeNotifier();
572 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver
* observer
) {
573 if (g_network_change_notifier
)
574 g_network_change_notifier
->ip_address_observer_list_
->AddObserver(observer
);
577 void NetworkChangeNotifier::AddConnectionTypeObserver(
578 ConnectionTypeObserver
* observer
) {
579 if (g_network_change_notifier
) {
580 g_network_change_notifier
->connection_type_observer_list_
->AddObserver(
585 void NetworkChangeNotifier::AddDNSObserver(DNSObserver
* observer
) {
586 if (g_network_change_notifier
) {
587 g_network_change_notifier
->resolver_state_observer_list_
->AddObserver(
592 void NetworkChangeNotifier::AddNetworkChangeObserver(
593 NetworkChangeObserver
* observer
) {
594 if (g_network_change_notifier
) {
595 g_network_change_notifier
->network_change_observer_list_
->AddObserver(
600 void NetworkChangeNotifier::RemoveIPAddressObserver(
601 IPAddressObserver
* observer
) {
602 if (g_network_change_notifier
) {
603 g_network_change_notifier
->ip_address_observer_list_
->RemoveObserver(
608 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
609 ConnectionTypeObserver
* observer
) {
610 if (g_network_change_notifier
) {
611 g_network_change_notifier
->connection_type_observer_list_
->RemoveObserver(
616 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver
* observer
) {
617 if (g_network_change_notifier
) {
618 g_network_change_notifier
->resolver_state_observer_list_
->RemoveObserver(
623 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
624 NetworkChangeObserver
* observer
) {
625 if (g_network_change_notifier
) {
626 g_network_change_notifier
->network_change_observer_list_
->RemoveObserver(
631 NetworkChangeNotifier::NetworkChangeNotifier(
632 const NetworkChangeCalculatorParams
& params
633 /*= NetworkChangeCalculatorParams()*/)
634 : ip_address_observer_list_(
635 new ObserverListThreadSafe
<IPAddressObserver
>(
636 ObserverListBase
<IPAddressObserver
>::NOTIFY_EXISTING_ONLY
)),
637 connection_type_observer_list_(
638 new ObserverListThreadSafe
<ConnectionTypeObserver
>(
639 ObserverListBase
<ConnectionTypeObserver
>::NOTIFY_EXISTING_ONLY
)),
640 resolver_state_observer_list_(
641 new ObserverListThreadSafe
<DNSObserver
>(
642 ObserverListBase
<DNSObserver
>::NOTIFY_EXISTING_ONLY
)),
643 network_change_observer_list_(
644 new ObserverListThreadSafe
<NetworkChangeObserver
>(
645 ObserverListBase
<NetworkChangeObserver
>::NOTIFY_EXISTING_ONLY
)),
646 network_state_(new NetworkState()),
647 histogram_watcher_(new HistogramWatcher()),
648 network_change_calculator_(new NetworkChangeCalculator(params
)) {
649 DCHECK(!g_network_change_notifier
);
650 g_network_change_notifier
= this;
651 network_change_calculator_
->Init();
654 #if defined(OS_LINUX)
655 const internal::AddressTrackerLinux
*
656 NetworkChangeNotifier::GetAddressTrackerInternal() const {
662 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
663 if (g_network_change_notifier
) {
664 g_network_change_notifier
->ip_address_observer_list_
->Notify(
665 &IPAddressObserver::OnIPAddressChanged
);
670 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
671 if (g_network_change_notifier
) {
672 g_network_change_notifier
->resolver_state_observer_list_
->Notify(
673 &DNSObserver::OnDNSChanged
);
678 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig
& config
) {
679 if (!g_network_change_notifier
)
681 g_network_change_notifier
->network_state_
->SetDnsConfig(config
);
682 NotifyObserversOfDNSChange();
685 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
686 if (g_network_change_notifier
) {
687 g_network_change_notifier
->connection_type_observer_list_
->Notify(
688 &ConnectionTypeObserver::OnConnectionTypeChanged
,
689 GetConnectionType());
693 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
694 ConnectionType type
) {
695 if (g_network_change_notifier
) {
696 g_network_change_notifier
->network_change_observer_list_
->Notify(
697 &NetworkChangeObserver::OnNetworkChanged
,
702 NetworkChangeNotifier::DisableForTest::DisableForTest()
703 : network_change_notifier_(g_network_change_notifier
) {
704 DCHECK(g_network_change_notifier
);
705 g_network_change_notifier
= NULL
;
708 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
709 DCHECK(!g_network_change_notifier
);
710 g_network_change_notifier
= network_change_notifier_
;