• 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 
NetworkChangeNotifier(const NetworkChangeCalculatorParams & params)713 NetworkChangeNotifier::NetworkChangeNotifier(
714     const NetworkChangeCalculatorParams& params
715         /*= NetworkChangeCalculatorParams()*/)
716     : ip_address_observer_list_(
717         new ObserverListThreadSafe<IPAddressObserver>(
718             ObserverListBase<IPAddressObserver>::NOTIFY_EXISTING_ONLY)),
719       connection_type_observer_list_(
720         new ObserverListThreadSafe<ConnectionTypeObserver>(
721             ObserverListBase<ConnectionTypeObserver>::NOTIFY_EXISTING_ONLY)),
722       resolver_state_observer_list_(
723         new ObserverListThreadSafe<DNSObserver>(
724             ObserverListBase<DNSObserver>::NOTIFY_EXISTING_ONLY)),
725       network_change_observer_list_(
726         new ObserverListThreadSafe<NetworkChangeObserver>(
727             ObserverListBase<NetworkChangeObserver>::NOTIFY_EXISTING_ONLY)),
728       network_state_(new NetworkState()),
729       network_change_calculator_(new NetworkChangeCalculator(params)) {
730   DCHECK(!g_network_change_notifier);
731   g_network_change_notifier = this;
732   network_change_calculator_->Init();
733 }
734 
735 #if defined(OS_LINUX)
736 const internal::AddressTrackerLinux*
GetAddressTrackerInternal() const737 NetworkChangeNotifier::GetAddressTrackerInternal() const {
738   return NULL;
739 }
740 #endif
741 
742 // static
NotifyObserversOfIPAddressChange()743 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
744   if (g_network_change_notifier) {
745     g_network_change_notifier->ip_address_observer_list_->Notify(
746         &IPAddressObserver::OnIPAddressChanged);
747   }
748 }
749 
750 // static
NotifyObserversOfDNSChange()751 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
752   if (g_network_change_notifier) {
753     g_network_change_notifier->resolver_state_observer_list_->Notify(
754         &DNSObserver::OnDNSChanged);
755   }
756 }
757 
758 // static
SetDnsConfig(const DnsConfig & config)759 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) {
760   if (!g_network_change_notifier)
761     return;
762   g_network_change_notifier->network_state_->SetDnsConfig(config);
763   NotifyObserversOfDNSChange();
764 }
765 
NotifyObserversOfConnectionTypeChange()766 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
767   if (g_network_change_notifier) {
768     g_network_change_notifier->connection_type_observer_list_->Notify(
769         &ConnectionTypeObserver::OnConnectionTypeChanged,
770         GetConnectionType());
771   }
772 }
773 
NotifyObserversOfNetworkChange(ConnectionType type)774 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
775     ConnectionType type) {
776   if (g_network_change_notifier) {
777     g_network_change_notifier->network_change_observer_list_->Notify(
778         &NetworkChangeObserver::OnNetworkChanged,
779         type);
780   }
781 }
782 
DisableForTest()783 NetworkChangeNotifier::DisableForTest::DisableForTest()
784     : network_change_notifier_(g_network_change_notifier) {
785   DCHECK(g_network_change_notifier);
786   g_network_change_notifier = NULL;
787 }
788 
~DisableForTest()789 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
790   DCHECK(!g_network_change_notifier);
791   g_network_change_notifier = network_change_notifier_;
792 }
793 
794 }  // namespace net
795