• 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 "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"
15  #include "url/gurl.h"
16  
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"
21  #endif
22  
23  #if defined(OS_WIN)
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"
29  #endif
30  
31  namespace net {
32  
33  namespace {
34  
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
38  // anyway.)
39  NetworkChangeNotifier* g_network_change_notifier = NULL;
40  
41  // Class factory singleton.
42  NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL;
43  
44  class MockNetworkChangeNotifier : public NetworkChangeNotifier {
45   public:
GetCurrentConnectionType() const46    virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
47      return CONNECTION_UNKNOWN;
48    }
49  };
50  
51  }  // namespace
52  
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 {
59   public:
HistogramWatcher()60    HistogramWatcher()
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) {}
69  
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.
Init()75    void Init() {
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);
82    }
83  
~HistogramWatcher()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);
91    }
92  
93    // NetworkChangeNotifier::IPAddressObserver implementation.
OnIPAddressChanged()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_);
101    }
102  
103    // NetworkChangeNotifier::ConnectionTypeObserver implementation.
OnConnectionTypeChanged(NetworkChangeNotifier::ConnectionType type)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_);
117            break;
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_);
123            break;
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_);
129            break;
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_);
135            break;
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_);
141            break;
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_);
147            break;
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_);
153            break;
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_);
159        }
160      }
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_);
166            break;
167          case NetworkChangeNotifier::CONNECTION_ETHERNET:
168            UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
169                                 peak_kbps_since_last_connection_change_);
170            break;
171          case NetworkChangeNotifier::CONNECTION_WIFI:
172            UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
173                                 peak_kbps_since_last_connection_change_);
174            break;
175          case NetworkChangeNotifier::CONNECTION_2G:
176            UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
177                                 peak_kbps_since_last_connection_change_);
178            break;
179          case NetworkChangeNotifier::CONNECTION_3G:
180            UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
181                                 peak_kbps_since_last_connection_change_);
182            break;
183          case NetworkChangeNotifier::CONNECTION_4G:
184            UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
185                                 peak_kbps_since_last_connection_change_);
186            break;
187          case NetworkChangeNotifier::CONNECTION_NONE:
188            UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
189                                 peak_kbps_since_last_connection_change_);
190            break;
191          case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
192            UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnBluetooth",
193                                 peak_kbps_since_last_connection_change_);
194            break;
195        }
196      }
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);
201          break;
202        case NetworkChangeNotifier::CONNECTION_ETHERNET:
203          UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration);
204          UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read);
205          break;
206        case NetworkChangeNotifier::CONNECTION_WIFI:
207          UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration);
208          UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read);
209          break;
210        case NetworkChangeNotifier::CONNECTION_2G:
211          UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration);
212          UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read);
213          break;
214        case NetworkChangeNotifier::CONNECTION_3G:
215          UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration);
216          UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read);
217          break;
218        case NetworkChangeNotifier::CONNECTION_4G:
219          UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration);
220          UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read);
221          break;
222        case NetworkChangeNotifier::CONNECTION_NONE:
223          UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration);
224          UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read);
225          break;
226        case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
227          UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnBluetooth", state_duration);
228          UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnBluetooth", kilobytes_read);
229          break;
230      }
231  
232      if (type != NetworkChangeNotifier::CONNECTION_NONE) {
233        UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration);
234  
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_);
242          }
243  
244          UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
245                                     now - last_offline_packet_received_);
246        }
247      } else {
248        UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration);
249      }
250  
251      NetworkChangeNotifier::LogOperatorCodeHistogram(type);
252  
253      UMA_HISTOGRAM_MEDIUM_TIMES(
254          "NCN.IPAddressChangeToConnectionTypeChange",
255          now - last_ip_address_change_);
256  
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);
262    }
263  
264    // NetworkChangeNotifier::DNSObserver implementation.
OnDNSChanged()265    virtual void OnDNSChanged() OVERRIDE {
266      DCHECK(thread_checker_.CalledOnValidThread());
267      UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
268                                 SinceLast(&last_dns_change_));
269    }
270  
271    // NetworkChangeNotifier::NetworkChangeObserver implementation.
OnNetworkChanged(NetworkChangeNotifier::ConnectionType type)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_));
278      } else {
279        UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
280                                   SinceLast(&last_network_change_));
281      }
282    }
283  
284    // Record histogram data whenever we receive a packet. Should only be called
285    // from the network thread.
NotifyDataReceived(const URLRequest & request,int bytes_read)286    void NotifyDataReceived(const URLRequest& request, int bytes_read) {
287      DCHECK(thread_checker_.CalledOnValidThread());
288      if (IsLocalhost(request.url().host()) ||
289          !request.url().SchemeIsHTTPOrHTTPS()) {
290        return;
291      }
292  
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;
298      }
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;
310      }
311  
312      if (last_connection_type_ != NetworkChangeNotifier::CONNECTION_NONE)
313        return;
314  
315      UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
316                                 now - last_connection_change_);
317      offline_packets_received_++;
318      last_offline_packet_received_ = now;
319  
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();
325      }
326      if (last_polled_connection_type_ ==
327          NetworkChangeNotifier::CONNECTION_NONE) {
328        UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
329                                   now - last_connection_change_);
330      }
331    }
332  
333   private:
SinceLast(base::TimeTicks * last_time)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;
338      return delta;
339    }
340  
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
351    // state.
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_;
376  
377    base::ThreadChecker thread_checker_;
378  
379    DISALLOW_COPY_AND_ASSIGN(HistogramWatcher);
380  };
381  
382  // NetworkState is thread safe.
383  class NetworkChangeNotifier::NetworkState {
384   public:
NetworkState()385    NetworkState() {}
~NetworkState()386    ~NetworkState() {}
387  
GetDnsConfig(DnsConfig * config) const388    void GetDnsConfig(DnsConfig* config) const {
389      base::AutoLock lock(lock_);
390      *config = dns_config_;
391    }
392  
SetDnsConfig(const DnsConfig & dns_config)393    void SetDnsConfig(const DnsConfig& dns_config) {
394      base::AutoLock lock(lock_);
395      dns_config_ = dns_config;
396    }
397  
398   private:
399    mutable base::Lock lock_;
400    DnsConfig dns_config_;
401  };
402  
403  NetworkChangeNotifier::NetworkChangeCalculatorParams::
NetworkChangeCalculatorParams()404      NetworkChangeCalculatorParams() {
405  }
406  
407  // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
408  class NetworkChangeNotifier::NetworkChangeCalculator
409      : public ConnectionTypeObserver,
410        public IPAddressObserver {
411   public:
NetworkChangeCalculator(const NetworkChangeCalculatorParams & params)412    NetworkChangeCalculator(const NetworkChangeCalculatorParams& params)
413        : params_(params),
414          have_announced_(false),
415          last_announced_connection_type_(CONNECTION_NONE),
416          pending_connection_type_(CONNECTION_NONE) {}
417  
Init()418    void Init() {
419      DCHECK(thread_checker_.CalledOnValidThread());
420      DCHECK(g_network_change_notifier);
421      AddConnectionTypeObserver(this);
422      AddIPAddressObserver(this);
423    }
424  
~NetworkChangeCalculator()425    virtual ~NetworkChangeCalculator() {
426      DCHECK(thread_checker_.CalledOnValidThread());
427      DCHECK(g_network_change_notifier);
428      RemoveConnectionTypeObserver(this);
429      RemoveIPAddressObserver(this);
430    }
431  
432    // NetworkChangeNotifier::IPAddressObserver implementation.
OnIPAddressChanged()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);
439    }
440  
441    // NetworkChangeNotifier::ConnectionTypeObserver implementation.
OnConnectionTypeChanged(ConnectionType type)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);
450    }
451  
452   private:
Notify()453    void 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)) {
459        return;
460      }
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_);
469    }
470  
471    const NetworkChangeCalculatorParams params_;
472  
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_;
481  
482    base::ThreadChecker thread_checker_;
483  
484    DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator);
485  };
486  
~NetworkChangeNotifier()487  NetworkChangeNotifier::~NetworkChangeNotifier() {
488    network_change_calculator_.reset();
489    DCHECK_EQ(this, g_network_change_notifier);
490    g_network_change_notifier = NULL;
491  }
492  
493  // static
SetFactory(NetworkChangeNotifierFactory * factory)494  void NetworkChangeNotifier::SetFactory(
495      NetworkChangeNotifierFactory* factory) {
496    CHECK(!g_network_change_notifier_factory);
497    g_network_change_notifier_factory = factory;
498  }
499  
500  // static
Create()501  NetworkChangeNotifier* NetworkChangeNotifier::Create() {
502    if (g_network_change_notifier_factory)
503      return g_network_change_notifier_factory->CreateInstance();
504  
505  #if defined(OS_WIN)
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.
516    CHECK(false);
517  #endif
518    return NULL;
519  #elif defined(OS_LINUX)
520    return NetworkChangeNotifierLinux::Create();
521  #elif defined(OS_MACOSX)
522    return new NetworkChangeNotifierMac();
523  #else
524    NOTIMPLEMENTED();
525    return NULL;
526  #endif
527  }
528  
529  // static
530  NetworkChangeNotifier::ConnectionType
GetConnectionType()531  NetworkChangeNotifier::GetConnectionType() {
532    return g_network_change_notifier ?
533        g_network_change_notifier->GetCurrentConnectionType() :
534        CONNECTION_UNKNOWN;
535  }
536  
537  // static
GetDnsConfig(DnsConfig * config)538  void NetworkChangeNotifier::GetDnsConfig(DnsConfig* config) {
539    if (!g_network_change_notifier) {
540      *config = DnsConfig();
541    } else {
542      g_network_change_notifier->network_state_->GetDnsConfig(config);
543    }
544  }
545  
546  // static
ConnectionTypeToString(ConnectionType type)547  const char* NetworkChangeNotifier::ConnectionTypeToString(
548      ConnectionType type) {
549    static const char* kConnectionTypeNames[] = {
550      "CONNECTION_UNKNOWN",
551      "CONNECTION_ETHERNET",
552      "CONNECTION_WIFI",
553      "CONNECTION_2G",
554      "CONNECTION_3G",
555      "CONNECTION_4G",
556      "CONNECTION_NONE",
557      "CONNECTION_BLUETOOTH"
558    };
559    COMPILE_ASSERT(
560        arraysize(kConnectionTypeNames) ==
561            NetworkChangeNotifier::CONNECTION_LAST + 1,
562        ConnectionType_name_count_mismatch);
563    if (type < CONNECTION_UNKNOWN || type > CONNECTION_LAST) {
564      NOTREACHED();
565      return "CONNECTION_INVALID";
566    }
567    return kConnectionTypeNames[type];
568  }
569  
570  // static
NotifyDataReceived(const URLRequest & request,int bytes_read)571  void NetworkChangeNotifier::NotifyDataReceived(const URLRequest& request,
572                                                 int bytes_read) {
573    if (!g_network_change_notifier ||
574        !g_network_change_notifier->histogram_watcher_) {
575      return;
576    }
577    g_network_change_notifier->histogram_watcher_->NotifyDataReceived(request,
578                                                                      bytes_read);
579  }
580  
581  // static
InitHistogramWatcher()582  void NetworkChangeNotifier::InitHistogramWatcher() {
583    if (!g_network_change_notifier)
584      return;
585    g_network_change_notifier->histogram_watcher_.reset(new HistogramWatcher());
586    g_network_change_notifier->histogram_watcher_->Init();
587  }
588  
589  // static
ShutdownHistogramWatcher()590  void NetworkChangeNotifier::ShutdownHistogramWatcher() {
591    if (!g_network_change_notifier)
592      return;
593    g_network_change_notifier->histogram_watcher_.reset();
594  }
595  
596  // static
LogOperatorCodeHistogram(ConnectionType type)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)) {
608        mcc_mnc = 0;
609      }
610    }
611    UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc);
612  #endif
613  }
614  
615  #if defined(OS_LINUX)
616  // static
617  const internal::AddressTrackerLinux*
GetAddressTracker()618  NetworkChangeNotifier::GetAddressTracker() {
619    return g_network_change_notifier ?
620          g_network_change_notifier->GetAddressTrackerInternal() : NULL;
621  }
622  #endif
623  
624  // static
IsOffline()625  bool NetworkChangeNotifier::IsOffline() {
626     return GetConnectionType() == CONNECTION_NONE;
627  }
628  
629  // static
IsConnectionCellular(ConnectionType type)630  bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) {
631    bool is_cellular = false;
632    switch (type) {
633      case CONNECTION_2G:
634      case CONNECTION_3G:
635      case CONNECTION_4G:
636        is_cellular =  true;
637        break;
638      case CONNECTION_UNKNOWN:
639      case CONNECTION_ETHERNET:
640      case CONNECTION_WIFI:
641      case CONNECTION_NONE:
642      case CONNECTION_BLUETOOTH:
643        is_cellular = false;
644        break;
645    }
646    return is_cellular;
647  }
648  
649  // static
CreateMock()650  NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
651    return new MockNetworkChangeNotifier();
652  }
653  
AddIPAddressObserver(IPAddressObserver * observer)654  void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
655    if (g_network_change_notifier)
656      g_network_change_notifier->ip_address_observer_list_->AddObserver(observer);
657  }
658  
AddConnectionTypeObserver(ConnectionTypeObserver * observer)659  void NetworkChangeNotifier::AddConnectionTypeObserver(
660      ConnectionTypeObserver* observer) {
661    if (g_network_change_notifier) {
662      g_network_change_notifier->connection_type_observer_list_->AddObserver(
663          observer);
664    }
665  }
666  
AddDNSObserver(DNSObserver * observer)667  void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
668    if (g_network_change_notifier) {
669      g_network_change_notifier->resolver_state_observer_list_->AddObserver(
670          observer);
671    }
672  }
673  
AddNetworkChangeObserver(NetworkChangeObserver * observer)674  void NetworkChangeNotifier::AddNetworkChangeObserver(
675      NetworkChangeObserver* observer) {
676    if (g_network_change_notifier) {
677      g_network_change_notifier->network_change_observer_list_->AddObserver(
678          observer);
679    }
680  }
681  
RemoveIPAddressObserver(IPAddressObserver * observer)682  void NetworkChangeNotifier::RemoveIPAddressObserver(
683      IPAddressObserver* observer) {
684    if (g_network_change_notifier) {
685      g_network_change_notifier->ip_address_observer_list_->RemoveObserver(
686          observer);
687    }
688  }
689  
RemoveConnectionTypeObserver(ConnectionTypeObserver * observer)690  void NetworkChangeNotifier::RemoveConnectionTypeObserver(
691      ConnectionTypeObserver* observer) {
692    if (g_network_change_notifier) {
693      g_network_change_notifier->connection_type_observer_list_->RemoveObserver(
694          observer);
695    }
696  }
697  
RemoveDNSObserver(DNSObserver * observer)698  void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
699    if (g_network_change_notifier) {
700      g_network_change_notifier->resolver_state_observer_list_->RemoveObserver(
701          observer);
702    }
703  }
704  
RemoveNetworkChangeObserver(NetworkChangeObserver * observer)705  void NetworkChangeNotifier::RemoveNetworkChangeObserver(
706      NetworkChangeObserver* observer) {
707    if (g_network_change_notifier) {
708      g_network_change_notifier->network_change_observer_list_->RemoveObserver(
709          observer);
710    }
711  }
712  
713  // static
NotifyObserversOfIPAddressChangeForTests()714  void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
715    if (g_network_change_notifier)
716      g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
717  }
718  
719  // static
NotifyObserversOfConnectionTypeChangeForTests(ConnectionType type)720  void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
721      ConnectionType type) {
722    if (g_network_change_notifier)
723      g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type);
724  }
725  
726  // static
NotifyObserversOfNetworkChangeForTests(ConnectionType type)727  void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
728      ConnectionType type) {
729    if (g_network_change_notifier)
730      g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
731  }
732  
733  // static
SetTestNotificationsOnly(bool test_only)734  void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only) {
735    if (g_network_change_notifier)
736      g_network_change_notifier->test_notifications_only_ = test_only;
737  }
738  
NetworkChangeNotifier(const NetworkChangeCalculatorParams & params)739  NetworkChangeNotifier::NetworkChangeNotifier(
740      const NetworkChangeCalculatorParams& params
741          /*= NetworkChangeCalculatorParams()*/)
742      : ip_address_observer_list_(
743          new ObserverListThreadSafe<IPAddressObserver>(
744              ObserverListBase<IPAddressObserver>::NOTIFY_EXISTING_ONLY)),
745        connection_type_observer_list_(
746          new ObserverListThreadSafe<ConnectionTypeObserver>(
747              ObserverListBase<ConnectionTypeObserver>::NOTIFY_EXISTING_ONLY)),
748        resolver_state_observer_list_(
749          new ObserverListThreadSafe<DNSObserver>(
750              ObserverListBase<DNSObserver>::NOTIFY_EXISTING_ONLY)),
751        network_change_observer_list_(
752          new ObserverListThreadSafe<NetworkChangeObserver>(
753              ObserverListBase<NetworkChangeObserver>::NOTIFY_EXISTING_ONLY)),
754        network_state_(new NetworkState()),
755        network_change_calculator_(new NetworkChangeCalculator(params)),
756        test_notifications_only_(false) {
757    DCHECK(!g_network_change_notifier);
758    g_network_change_notifier = this;
759    network_change_calculator_->Init();
760  }
761  
762  #if defined(OS_LINUX)
763  const internal::AddressTrackerLinux*
GetAddressTrackerInternal() const764  NetworkChangeNotifier::GetAddressTrackerInternal() const {
765    return NULL;
766  }
767  #endif
768  
769  // static
NotifyObserversOfIPAddressChange()770  void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
771    if (g_network_change_notifier &&
772        !g_network_change_notifier->test_notifications_only_) {
773      g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
774    }
775  }
776  
777  // static
NotifyObserversOfConnectionTypeChange()778  void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
779    if (g_network_change_notifier &&
780        !g_network_change_notifier->test_notifications_only_) {
781      g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(
782          GetConnectionType());
783    }
784  }
785  
786  // static
NotifyObserversOfNetworkChange(ConnectionType type)787  void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
788      ConnectionType type) {
789    if (g_network_change_notifier &&
790        !g_network_change_notifier->test_notifications_only_) {
791      g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
792    }
793  }
794  
795  // static
NotifyObserversOfDNSChange()796  void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
797    if (g_network_change_notifier &&
798        !g_network_change_notifier->test_notifications_only_) {
799      g_network_change_notifier->NotifyObserversOfDNSChangeImpl();
800    }
801  }
802  
803  // static
SetDnsConfig(const DnsConfig & config)804  void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) {
805    if (!g_network_change_notifier)
806      return;
807    g_network_change_notifier->network_state_->SetDnsConfig(config);
808    NotifyObserversOfDNSChange();
809  }
810  
NotifyObserversOfIPAddressChangeImpl()811  void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
812    ip_address_observer_list_->Notify(&IPAddressObserver::OnIPAddressChanged);
813  }
814  
NotifyObserversOfConnectionTypeChangeImpl(ConnectionType type)815  void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
816      ConnectionType type) {
817    connection_type_observer_list_->Notify(
818        &ConnectionTypeObserver::OnConnectionTypeChanged, type);
819  }
820  
NotifyObserversOfNetworkChangeImpl(ConnectionType type)821  void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
822      ConnectionType type) {
823    network_change_observer_list_->Notify(
824        &NetworkChangeObserver::OnNetworkChanged, type);
825  }
826  
NotifyObserversOfDNSChangeImpl()827  void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
828    resolver_state_observer_list_->Notify(&DNSObserver::OnDNSChanged);
829  }
830  
DisableForTest()831  NetworkChangeNotifier::DisableForTest::DisableForTest()
832      : network_change_notifier_(g_network_change_notifier) {
833    DCHECK(g_network_change_notifier);
834    g_network_change_notifier = NULL;
835  }
836  
~DisableForTest()837  NetworkChangeNotifier::DisableForTest::~DisableForTest() {
838    DCHECK(!g_network_change_notifier);
839    g_network_change_notifier = network_change_notifier_;
840  }
841  
842  }  // namespace net
843