Home | History | Annotate | Download | only in base
      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:
     46   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:
     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.
     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 
     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.
     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.
    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.
    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.
    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.
    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:
    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:
    385   NetworkState() {}
    386   ~NetworkState() {}
    387 
    388   void GetDnsConfig(DnsConfig* config) const {
    389     base::AutoLock lock(lock_);
    390     *config = dns_config_;
    391   }
    392 
    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::
    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:
    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 
    418   void Init() {
    419     DCHECK(thread_checker_.CalledOnValidThread());
    420     DCHECK(g_network_change_notifier);
    421     AddConnectionTypeObserver(this);
    422     AddIPAddressObserver(this);
    423   }
    424 
    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.
    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.
    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:
    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 
    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
    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
    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
    531 NetworkChangeNotifier::GetConnectionType() {
    532   return g_network_change_notifier ?
    533       g_network_change_notifier->GetCurrentConnectionType() :
    534       CONNECTION_UNKNOWN;
    535 }
    536 
    537 // static
    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
    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
    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
    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
    590 void NetworkChangeNotifier::ShutdownHistogramWatcher() {
    591   if (!g_network_change_notifier)
    592     return;
    593   g_network_change_notifier->histogram_watcher_.reset();
    594 }
    595 
    596 // static
    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*
    618 NetworkChangeNotifier::GetAddressTracker() {
    619   return g_network_change_notifier ?
    620         g_network_change_notifier->GetAddressTrackerInternal() : NULL;
    621 }
    622 #endif
    623 
    624 // static
    625 bool NetworkChangeNotifier::IsOffline() {
    626    return GetConnectionType() == CONNECTION_NONE;
    627 }
    628 
    629 // static
    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
    650 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
    651   return new MockNetworkChangeNotifier();
    652 }
    653 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    714 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
    715   if (g_network_change_notifier)
    716     g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
    717 }
    718 
    719 // static
    720 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
    721     ConnectionType type) {
    722   if (g_network_change_notifier)
    723     g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type);
    724 }
    725 
    726 // static
    727 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
    728     ConnectionType type) {
    729   if (g_network_change_notifier)
    730     g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
    731 }
    732 
    733 // static
    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 
    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*
    764 NetworkChangeNotifier::GetAddressTrackerInternal() const {
    765   return NULL;
    766 }
    767 #endif
    768 
    769 // static
    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
    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
    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
    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
    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 
    811 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
    812   ip_address_observer_list_->Notify(&IPAddressObserver::OnIPAddressChanged);
    813 }
    814 
    815 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
    816     ConnectionType type) {
    817   connection_type_observer_list_->Notify(
    818       &ConnectionTypeObserver::OnConnectionTypeChanged, type);
    819 }
    820 
    821 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
    822     ConnectionType type) {
    823   network_change_observer_list_->Notify(
    824       &NetworkChangeObserver::OnNetworkChanged, type);
    825 }
    826 
    827 void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
    828   resolver_state_observer_list_->Notify(&DNSObserver::OnDNSChanged);
    829 }
    830 
    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 
    837 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
    838   DCHECK(!g_network_change_notifier);
    839   g_network_change_notifier = network_change_notifier_;
    840 }
    841 
    842 }  // namespace net
    843