• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "net/base/network_change_notifier.h"
6 
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"
14 #include "url/gurl.h"
15 
16 #if defined(OS_WIN)
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"
22 #endif
23 
24 namespace net {
25 
26 namespace {
27 
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
31 // anyway.)
32 NetworkChangeNotifier* g_network_change_notifier = NULL;
33 
34 // Class factory singleton.
35 NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL;
36 
37 class MockNetworkChangeNotifier : public NetworkChangeNotifier {
38  public:
GetCurrentConnectionType() const39   virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
40     return CONNECTION_UNKNOWN;
41   }
42 };
43 
44 }  // namespace
45 
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 {
52  public:
HistogramWatcher()53   HistogramWatcher()
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) {}
62 
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.
Init()68   void Init() {
69     NetworkChangeNotifier::AddConnectionTypeObserver(this);
70     NetworkChangeNotifier::AddIPAddressObserver(this);
71     NetworkChangeNotifier::AddDNSObserver(this);
72     NetworkChangeNotifier::AddNetworkChangeObserver(this);
73   }
74 
~HistogramWatcher()75   virtual ~HistogramWatcher() {}
76 
77   // NetworkChangeNotifier::IPAddressObserver implementation.
OnIPAddressChanged()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_);
84   }
85 
86   // NetworkChangeNotifier::ConnectionTypeObserver implementation.
OnConnectionTypeChanged(NetworkChangeNotifier::ConnectionType type)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_);
99           break;
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_);
105           break;
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_);
111           break;
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_);
117           break;
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_);
123           break;
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_);
129           break;
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_);
135           break;
136       }
137     }
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_);
143           break;
144         case NetworkChangeNotifier::CONNECTION_ETHERNET:
145           UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
146                                peak_kbps_since_last_connection_change_);
147           break;
148         case NetworkChangeNotifier::CONNECTION_WIFI:
149           UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
150                                peak_kbps_since_last_connection_change_);
151           break;
152         case NetworkChangeNotifier::CONNECTION_2G:
153           UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
154                                peak_kbps_since_last_connection_change_);
155           break;
156         case NetworkChangeNotifier::CONNECTION_3G:
157           UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
158                                peak_kbps_since_last_connection_change_);
159           break;
160         case NetworkChangeNotifier::CONNECTION_4G:
161           UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
162                                peak_kbps_since_last_connection_change_);
163           break;
164         case NetworkChangeNotifier::CONNECTION_NONE:
165           UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
166                                peak_kbps_since_last_connection_change_);
167           break;
168       }
169     }
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);
174         break;
175       case NetworkChangeNotifier::CONNECTION_ETHERNET:
176         UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration);
177         UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read);
178         break;
179       case NetworkChangeNotifier::CONNECTION_WIFI:
180         UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration);
181         UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read);
182         break;
183       case NetworkChangeNotifier::CONNECTION_2G:
184         UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration);
185         UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read);
186         break;
187       case NetworkChangeNotifier::CONNECTION_3G:
188         UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration);
189         UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read);
190         break;
191       case NetworkChangeNotifier::CONNECTION_4G:
192         UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration);
193         UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read);
194         break;
195       case NetworkChangeNotifier::CONNECTION_NONE:
196         UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration);
197         UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read);
198         break;
199     }
200 
201     if (type != NetworkChangeNotifier::CONNECTION_NONE) {
202       UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration);
203 
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_);
211         }
212 
213         UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
214                                    now - last_offline_packet_received_);
215       }
216     } else {
217       UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration);
218     }
219     UMA_HISTOGRAM_MEDIUM_TIMES(
220         "NCN.IPAddressChangeToConnectionTypeChange",
221         now - last_ip_address_change_);
222 
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);
228   }
229 
230   // NetworkChangeNotifier::DNSObserver implementation.
OnDNSChanged()231   virtual void OnDNSChanged() OVERRIDE {
232     UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
233                                SinceLast(&last_dns_change_));
234   }
235 
236   // NetworkChangeNotifier::NetworkChangeObserver implementation.
OnNetworkChanged(NetworkChangeNotifier::ConnectionType type)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_));
242     } else {
243       UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
244                                  SinceLast(&last_network_change_));
245     }
246   }
247 
248   // Record histogram data whenever we receive a packet. Should only be called
249   // from the network thread.
NotifyDataReceived(const URLRequest & request,int bytes_read)250   void NotifyDataReceived(const URLRequest& request, int bytes_read) {
251     if (IsLocalhost(request.url().host()) ||
252         !request.url().SchemeIsHTTPOrHTTPS()) {
253       return;
254     }
255 
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;
261     }
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;
273     }
274 
275     if (last_connection_type_ != NetworkChangeNotifier::CONNECTION_NONE)
276       return;
277 
278     UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
279                                now - last_connection_change_);
280     offline_packets_received_++;
281     last_offline_packet_received_ = now;
282 
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();
288     }
289     if (last_polled_connection_type_ ==
290         NetworkChangeNotifier::CONNECTION_NONE) {
291       UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
292                                  now - last_connection_change_);
293     }
294   }
295 
296  private:
SinceLast(base::TimeTicks * last_time)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;
301     return delta;
302   }
303 
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
314   // state.
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_;
339 
340   DISALLOW_COPY_AND_ASSIGN(HistogramWatcher);
341 };
342 
343 // NetworkState is thread safe.
344 class NetworkChangeNotifier::NetworkState {
345  public:
NetworkState()346   NetworkState() {}
~NetworkState()347   ~NetworkState() {}
348 
GetDnsConfig(DnsConfig * config) const349   void GetDnsConfig(DnsConfig* config) const {
350     base::AutoLock lock(lock_);
351     *config = dns_config_;
352   }
353 
SetDnsConfig(const DnsConfig & dns_config)354   void SetDnsConfig(const DnsConfig& dns_config) {
355     base::AutoLock lock(lock_);
356     dns_config_ = dns_config;
357   }
358 
359  private:
360   mutable base::Lock lock_;
361   DnsConfig dns_config_;
362 };
363 
364 NetworkChangeNotifier::NetworkChangeCalculatorParams::
NetworkChangeCalculatorParams()365     NetworkChangeCalculatorParams() {
366 }
367 
368 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
369 class NetworkChangeNotifier::NetworkChangeCalculator
370     : public ConnectionTypeObserver,
371       public IPAddressObserver {
372  public:
NetworkChangeCalculator(const NetworkChangeCalculatorParams & params)373   NetworkChangeCalculator(const NetworkChangeCalculatorParams& params)
374       : params_(params),
375         have_announced_(false),
376         last_announced_connection_type_(CONNECTION_NONE),
377         pending_connection_type_(CONNECTION_NONE) {}
378 
Init()379   void Init() {
380     AddConnectionTypeObserver(this);
381     AddIPAddressObserver(this);
382   }
383 
~NetworkChangeCalculator()384   virtual ~NetworkChangeCalculator() {
385     RemoveConnectionTypeObserver(this);
386     RemoveIPAddressObserver(this);
387   }
388 
389   // NetworkChangeNotifier::IPAddressObserver implementation.
OnIPAddressChanged()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);
395   }
396 
397   // NetworkChangeNotifier::ConnectionTypeObserver implementation.
OnConnectionTypeChanged(ConnectionType type)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);
405   }
406 
407  private:
Notify()408   void 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)) {
413       return;
414     }
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_);
423   }
424 
425   const NetworkChangeCalculatorParams params_;
426 
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_;
435 };
436 
~NetworkChangeNotifier()437 NetworkChangeNotifier::~NetworkChangeNotifier() {
438   DCHECK_EQ(this, g_network_change_notifier);
439   g_network_change_notifier = NULL;
440 }
441 
442 // static
SetFactory(NetworkChangeNotifierFactory * factory)443 void NetworkChangeNotifier::SetFactory(
444     NetworkChangeNotifierFactory* factory) {
445   CHECK(!g_network_change_notifier_factory);
446   g_network_change_notifier_factory = factory;
447 }
448 
449 // static
Create()450 NetworkChangeNotifier* NetworkChangeNotifier::Create() {
451   if (g_network_change_notifier_factory)
452     return g_network_change_notifier_factory->CreateInstance();
453 
454 #if defined(OS_WIN)
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.
465   CHECK(false);
466 #endif
467   return NULL;
468 #elif defined(OS_LINUX)
469   return NetworkChangeNotifierLinux::Create();
470 #elif defined(OS_MACOSX)
471   return new NetworkChangeNotifierMac();
472 #else
473   NOTIMPLEMENTED();
474   return NULL;
475 #endif
476 }
477 
478 // static
479 NetworkChangeNotifier::ConnectionType
GetConnectionType()480 NetworkChangeNotifier::GetConnectionType() {
481   return g_network_change_notifier ?
482       g_network_change_notifier->GetCurrentConnectionType() :
483       CONNECTION_UNKNOWN;
484 }
485 
486 // static
GetDnsConfig(DnsConfig * config)487 void NetworkChangeNotifier::GetDnsConfig(DnsConfig* config) {
488   if (!g_network_change_notifier) {
489     *config = DnsConfig();
490   } else {
491     g_network_change_notifier->network_state_->GetDnsConfig(config);
492   }
493 }
494 
495 // static
ConnectionTypeToString(ConnectionType type)496 const char* NetworkChangeNotifier::ConnectionTypeToString(
497     ConnectionType type) {
498   static const char* kConnectionTypeNames[] = {
499     "CONNECTION_UNKNOWN",
500     "CONNECTION_ETHERNET",
501     "CONNECTION_WIFI",
502     "CONNECTION_2G",
503     "CONNECTION_3G",
504     "CONNECTION_4G",
505     "CONNECTION_NONE"
506   };
507   COMPILE_ASSERT(
508       arraysize(kConnectionTypeNames) ==
509           NetworkChangeNotifier::CONNECTION_NONE + 1,
510       ConnectionType_name_count_mismatch);
511   if (type < CONNECTION_UNKNOWN || type > CONNECTION_NONE) {
512     NOTREACHED();
513     return "CONNECTION_INVALID";
514   }
515   return kConnectionTypeNames[type];
516 }
517 
518 // static
NotifyDataReceived(const URLRequest & request,int bytes_read)519 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest& request,
520                                                int bytes_read) {
521   if (!g_network_change_notifier)
522     return;
523   g_network_change_notifier->histogram_watcher_->NotifyDataReceived(request,
524                                                                     bytes_read);
525 }
526 
527 // static
InitHistogramWatcher()528 void NetworkChangeNotifier::InitHistogramWatcher() {
529   if (!g_network_change_notifier)
530     return;
531   g_network_change_notifier->histogram_watcher_->Init();
532 }
533 
534 #if defined(OS_LINUX)
535 // static
536 const internal::AddressTrackerLinux*
GetAddressTracker()537 NetworkChangeNotifier::GetAddressTracker() {
538   return g_network_change_notifier ?
539         g_network_change_notifier->GetAddressTrackerInternal() : NULL;
540 }
541 #endif
542 
543 // static
IsOffline()544 bool NetworkChangeNotifier::IsOffline() {
545    return GetConnectionType() == CONNECTION_NONE;
546 }
547 
548 // static
IsConnectionCellular(ConnectionType type)549 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) {
550   bool is_cellular = false;
551   switch (type) {
552     case CONNECTION_2G:
553     case CONNECTION_3G:
554     case CONNECTION_4G:
555       is_cellular =  true;
556       break;
557     case CONNECTION_UNKNOWN:
558     case CONNECTION_ETHERNET:
559     case CONNECTION_WIFI:
560     case CONNECTION_NONE:
561       is_cellular = false;
562       break;
563   }
564   return is_cellular;
565 }
566 
567 // static
CreateMock()568 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
569   return new MockNetworkChangeNotifier();
570 }
571 
AddIPAddressObserver(IPAddressObserver * observer)572 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
573   if (g_network_change_notifier)
574     g_network_change_notifier->ip_address_observer_list_->AddObserver(observer);
575 }
576 
AddConnectionTypeObserver(ConnectionTypeObserver * observer)577 void NetworkChangeNotifier::AddConnectionTypeObserver(
578     ConnectionTypeObserver* observer) {
579   if (g_network_change_notifier) {
580     g_network_change_notifier->connection_type_observer_list_->AddObserver(
581         observer);
582   }
583 }
584 
AddDNSObserver(DNSObserver * observer)585 void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
586   if (g_network_change_notifier) {
587     g_network_change_notifier->resolver_state_observer_list_->AddObserver(
588         observer);
589   }
590 }
591 
AddNetworkChangeObserver(NetworkChangeObserver * observer)592 void NetworkChangeNotifier::AddNetworkChangeObserver(
593     NetworkChangeObserver* observer) {
594   if (g_network_change_notifier) {
595     g_network_change_notifier->network_change_observer_list_->AddObserver(
596         observer);
597   }
598 }
599 
RemoveIPAddressObserver(IPAddressObserver * observer)600 void NetworkChangeNotifier::RemoveIPAddressObserver(
601     IPAddressObserver* observer) {
602   if (g_network_change_notifier) {
603     g_network_change_notifier->ip_address_observer_list_->RemoveObserver(
604         observer);
605   }
606 }
607 
RemoveConnectionTypeObserver(ConnectionTypeObserver * observer)608 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
609     ConnectionTypeObserver* observer) {
610   if (g_network_change_notifier) {
611     g_network_change_notifier->connection_type_observer_list_->RemoveObserver(
612         observer);
613   }
614 }
615 
RemoveDNSObserver(DNSObserver * observer)616 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
617   if (g_network_change_notifier) {
618     g_network_change_notifier->resolver_state_observer_list_->RemoveObserver(
619         observer);
620   }
621 }
622 
RemoveNetworkChangeObserver(NetworkChangeObserver * observer)623 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
624     NetworkChangeObserver* observer) {
625   if (g_network_change_notifier) {
626     g_network_change_notifier->network_change_observer_list_->RemoveObserver(
627         observer);
628   }
629 }
630 
NetworkChangeNotifier(const NetworkChangeCalculatorParams & params)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();
652 }
653 
654 #if defined(OS_LINUX)
655 const internal::AddressTrackerLinux*
GetAddressTrackerInternal() const656 NetworkChangeNotifier::GetAddressTrackerInternal() const {
657   return NULL;
658 }
659 #endif
660 
661 // static
NotifyObserversOfIPAddressChange()662 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
663   if (g_network_change_notifier) {
664     g_network_change_notifier->ip_address_observer_list_->Notify(
665         &IPAddressObserver::OnIPAddressChanged);
666   }
667 }
668 
669 // static
NotifyObserversOfDNSChange()670 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
671   if (g_network_change_notifier) {
672     g_network_change_notifier->resolver_state_observer_list_->Notify(
673         &DNSObserver::OnDNSChanged);
674   }
675 }
676 
677 // static
SetDnsConfig(const DnsConfig & config)678 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) {
679   if (!g_network_change_notifier)
680     return;
681   g_network_change_notifier->network_state_->SetDnsConfig(config);
682   NotifyObserversOfDNSChange();
683 }
684 
NotifyObserversOfConnectionTypeChange()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());
690   }
691 }
692 
NotifyObserversOfNetworkChange(ConnectionType type)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,
698         type);
699   }
700 }
701 
DisableForTest()702 NetworkChangeNotifier::DisableForTest::DisableForTest()
703     : network_change_notifier_(g_network_change_notifier) {
704   DCHECK(g_network_change_notifier);
705   g_network_change_notifier = NULL;
706 }
707 
~DisableForTest()708 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
709   DCHECK(!g_network_change_notifier);
710   g_network_change_notifier = network_change_notifier_;
711 }
712 
713 }  // namespace net
714