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
31namespace net {
32
33namespace {
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.)
39NetworkChangeNotifier* g_network_change_notifier = NULL;
40
41// Class factory singleton.
42NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL;
43
44class 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.
54class 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.
383class 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
403NetworkChangeNotifier::NetworkChangeCalculatorParams::
404    NetworkChangeCalculatorParams() {
405}
406
407// Calculates NetworkChange signal from IPAddress and ConnectionType signals.
408class 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
487NetworkChangeNotifier::~NetworkChangeNotifier() {
488  network_change_calculator_.reset();
489  DCHECK_EQ(this, g_network_change_notifier);
490  g_network_change_notifier = NULL;
491}
492
493// static
494void NetworkChangeNotifier::SetFactory(
495    NetworkChangeNotifierFactory* factory) {
496  CHECK(!g_network_change_notifier_factory);
497  g_network_change_notifier_factory = factory;
498}
499
500// static
501NetworkChangeNotifier* 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
530NetworkChangeNotifier::ConnectionType
531NetworkChangeNotifier::GetConnectionType() {
532  return g_network_change_notifier ?
533      g_network_change_notifier->GetCurrentConnectionType() :
534      CONNECTION_UNKNOWN;
535}
536
537// static
538void 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
547const 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
571void 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
582void 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
590void NetworkChangeNotifier::ShutdownHistogramWatcher() {
591  if (!g_network_change_notifier)
592    return;
593  g_network_change_notifier->histogram_watcher_.reset();
594}
595
596// static
597void 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
617const internal::AddressTrackerLinux*
618NetworkChangeNotifier::GetAddressTracker() {
619  return g_network_change_notifier ?
620        g_network_change_notifier->GetAddressTrackerInternal() : NULL;
621}
622#endif
623
624// static
625bool NetworkChangeNotifier::IsOffline() {
626   return GetConnectionType() == CONNECTION_NONE;
627}
628
629// static
630bool 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
650NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
651  return new MockNetworkChangeNotifier();
652}
653
654void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
655  if (g_network_change_notifier)
656    g_network_change_notifier->ip_address_observer_list_->AddObserver(observer);
657}
658
659void 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
667void 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
674void 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
682void 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
690void 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
698void 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
705void 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
714void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
715  if (g_network_change_notifier)
716    g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
717}
718
719// static
720void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
721    ConnectionType type) {
722  if (g_network_change_notifier)
723    g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type);
724}
725
726// static
727void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
728    ConnectionType type) {
729  if (g_network_change_notifier)
730    g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
731}
732
733// static
734void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only) {
735  if (g_network_change_notifier)
736    g_network_change_notifier->test_notifications_only_ = test_only;
737}
738
739NetworkChangeNotifier::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)
763const internal::AddressTrackerLinux*
764NetworkChangeNotifier::GetAddressTrackerInternal() const {
765  return NULL;
766}
767#endif
768
769// static
770void 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
778void 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
787void 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
796void 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
804void 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
811void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
812  ip_address_observer_list_->Notify(&IPAddressObserver::OnIPAddressChanged);
813}
814
815void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
816    ConnectionType type) {
817  connection_type_observer_list_->Notify(
818      &ConnectionTypeObserver::OnConnectionTypeChanged, type);
819}
820
821void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
822    ConnectionType type) {
823  network_change_observer_list_->Notify(
824      &NetworkChangeObserver::OnNetworkChanged, type);
825}
826
827void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
828  resolver_state_observer_list_->Notify(&DNSObserver::OnDNSChanged);
829}
830
831NetworkChangeNotifier::DisableForTest::DisableForTest()
832    : network_change_notifier_(g_network_change_notifier) {
833  DCHECK(g_network_change_notifier);
834  g_network_change_notifier = NULL;
835}
836
837NetworkChangeNotifier::DisableForTest::~DisableForTest() {
838  DCHECK(!g_network_change_notifier);
839  g_network_change_notifier = network_change_notifier_;
840}
841
842}  // namespace net
843