GoogleURLTrackerInfoBarDelegate: Initialize uninitialized member in constructor.
[chromium-blink-merge.git] / net / base / network_change_notifier.cc
blobaef83563ffc08fb44f03a696efb9232cab9e59bb
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.
5 #include "net/base/network_change_notifier.h"
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"
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
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
31 namespace net {
33 namespace {
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;
41 // Class factory singleton.
42 NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL;
44 class MockNetworkChangeNotifier : public NetworkChangeNotifier {
45 public:
46 virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
47 return CONNECTION_UNKNOWN;
51 } // namespace
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) {}
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);
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);
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_);
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;
156 if (peak_kbps_since_last_connection_change_) {
157 switch (last_connection_type_) {
158 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
159 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnUnknown",
160 peak_kbps_since_last_connection_change_);
161 break;
162 case NetworkChangeNotifier::CONNECTION_ETHERNET:
163 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
164 peak_kbps_since_last_connection_change_);
165 break;
166 case NetworkChangeNotifier::CONNECTION_WIFI:
167 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
168 peak_kbps_since_last_connection_change_);
169 break;
170 case NetworkChangeNotifier::CONNECTION_2G:
171 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
172 peak_kbps_since_last_connection_change_);
173 break;
174 case NetworkChangeNotifier::CONNECTION_3G:
175 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
176 peak_kbps_since_last_connection_change_);
177 break;
178 case NetworkChangeNotifier::CONNECTION_4G:
179 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
180 peak_kbps_since_last_connection_change_);
181 break;
182 case NetworkChangeNotifier::CONNECTION_NONE:
183 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
184 peak_kbps_since_last_connection_change_);
185 break;
188 switch (last_connection_type_) {
189 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
190 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnUnknown", state_duration);
191 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnUnknown", kilobytes_read);
192 break;
193 case NetworkChangeNotifier::CONNECTION_ETHERNET:
194 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration);
195 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read);
196 break;
197 case NetworkChangeNotifier::CONNECTION_WIFI:
198 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration);
199 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read);
200 break;
201 case NetworkChangeNotifier::CONNECTION_2G:
202 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration);
203 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read);
204 break;
205 case NetworkChangeNotifier::CONNECTION_3G:
206 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration);
207 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read);
208 break;
209 case NetworkChangeNotifier::CONNECTION_4G:
210 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration);
211 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read);
212 break;
213 case NetworkChangeNotifier::CONNECTION_NONE:
214 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration);
215 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read);
216 break;
219 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
220 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration);
222 if (offline_packets_received_) {
223 if ((now - last_offline_packet_received_) <
224 base::TimeDelta::FromSeconds(5)) {
225 // We can compare this sum with the sum of NCN.OfflineDataRecv.
226 UMA_HISTOGRAM_COUNTS_10000(
227 "NCN.OfflineDataRecvAny5sBeforeOnline",
228 offline_packets_received_);
231 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
232 now - last_offline_packet_received_);
234 } else {
235 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration);
238 NetworkChangeNotifier::LogOperatorCodeHistogram(type);
240 UMA_HISTOGRAM_MEDIUM_TIMES(
241 "NCN.IPAddressChangeToConnectionTypeChange",
242 now - last_ip_address_change_);
244 offline_packets_received_ = 0;
245 bytes_read_since_last_connection_change_ = 0;
246 peak_kbps_since_last_connection_change_ = 0;
247 last_connection_type_ = type;
248 polling_interval_ = base::TimeDelta::FromSeconds(1);
251 // NetworkChangeNotifier::DNSObserver implementation.
252 virtual void OnDNSChanged() OVERRIDE {
253 DCHECK(thread_checker_.CalledOnValidThread());
254 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
255 SinceLast(&last_dns_change_));
258 // NetworkChangeNotifier::NetworkChangeObserver implementation.
259 virtual void OnNetworkChanged(
260 NetworkChangeNotifier::ConnectionType type) OVERRIDE {
261 DCHECK(thread_checker_.CalledOnValidThread());
262 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
263 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOnlineChange",
264 SinceLast(&last_network_change_));
265 } else {
266 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
267 SinceLast(&last_network_change_));
271 // Record histogram data whenever we receive a packet. Should only be called
272 // from the network thread.
273 void NotifyDataReceived(const URLRequest& request, int bytes_read) {
274 DCHECK(thread_checker_.CalledOnValidThread());
275 if (IsLocalhost(request.url().host()) ||
276 !request.url().SchemeIsHTTPOrHTTPS()) {
277 return;
280 base::TimeTicks now = base::TimeTicks::Now();
281 base::TimeDelta request_duration = now - request.creation_time();
282 if (bytes_read_since_last_connection_change_ == 0) {
283 first_byte_after_connection_change_ = now - last_connection_change_;
284 fastest_RTT_since_last_connection_change_ = request_duration;
286 bytes_read_since_last_connection_change_ += bytes_read;
287 if (request_duration < fastest_RTT_since_last_connection_change_)
288 fastest_RTT_since_last_connection_change_ = request_duration;
289 // Ignore tiny transfers which will not produce accurate rates.
290 // Ignore zero duration transfers which might cause divide by zero.
291 if (bytes_read > 10000 &&
292 request_duration > base::TimeDelta::FromMilliseconds(1) &&
293 request.creation_time() > last_connection_change_) {
294 int32 kbps = bytes_read * 8 / request_duration.InMilliseconds();
295 if (kbps > peak_kbps_since_last_connection_change_)
296 peak_kbps_since_last_connection_change_ = kbps;
299 if (last_connection_type_ != NetworkChangeNotifier::CONNECTION_NONE)
300 return;
302 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
303 now - last_connection_change_);
304 offline_packets_received_++;
305 last_offline_packet_received_ = now;
307 if ((now - last_polled_connection_) > polling_interval_) {
308 polling_interval_ *= 2;
309 last_polled_connection_ = now;
310 last_polled_connection_type_ =
311 NetworkChangeNotifier::GetConnectionType();
313 if (last_polled_connection_type_ ==
314 NetworkChangeNotifier::CONNECTION_NONE) {
315 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
316 now - last_connection_change_);
320 private:
321 static base::TimeDelta SinceLast(base::TimeTicks *last_time) {
322 base::TimeTicks current_time = base::TimeTicks::Now();
323 base::TimeDelta delta = current_time - *last_time;
324 *last_time = current_time;
325 return delta;
328 base::TimeTicks last_ip_address_change_;
329 base::TimeTicks last_connection_change_;
330 base::TimeTicks last_dns_change_;
331 base::TimeTicks last_network_change_;
332 base::TimeTicks last_offline_packet_received_;
333 base::TimeTicks last_polled_connection_;
334 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
335 // first transition to offline and on subsequent transitions. Once offline,
336 // |polling_interval_| doubles as offline data is received and we poll
337 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
338 // state.
339 base::TimeDelta polling_interval_;
340 // |last_connection_type_| is the last value passed to
341 // |OnConnectionTypeChanged|.
342 NetworkChangeNotifier::ConnectionType last_connection_type_;
343 // |last_polled_connection_type_| is last result from calling
344 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
345 NetworkChangeNotifier::ConnectionType last_polled_connection_type_;
346 // Count of how many times NotifyDataReceived() has been called while the
347 // NetworkChangeNotifier thought network connection was offline.
348 int32 offline_packets_received_;
349 // Number of bytes of network data received since last connectivity change.
350 int32 bytes_read_since_last_connection_change_;
351 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
352 // from URLRequest creation until first byte received.
353 base::TimeDelta fastest_RTT_since_last_connection_change_;
354 // Time between connectivity change and first network data byte received.
355 base::TimeDelta first_byte_after_connection_change_;
356 // Rough measurement of peak KB/s witnessed since last connectivity change.
357 // The accuracy is decreased by ignoring these factors:
358 // 1) Multiple URLRequests can occur concurrently.
359 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest.
360 // 3) The transfer time includes at least one RTT while no bytes are read.
361 // Erring on the conservative side is hopefully offset by taking the maximum.
362 int32 peak_kbps_since_last_connection_change_;
364 base::ThreadChecker thread_checker_;
366 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher);
369 // NetworkState is thread safe.
370 class NetworkChangeNotifier::NetworkState {
371 public:
372 NetworkState() {}
373 ~NetworkState() {}
375 void GetDnsConfig(DnsConfig* config) const {
376 base::AutoLock lock(lock_);
377 *config = dns_config_;
380 void SetDnsConfig(const DnsConfig& dns_config) {
381 base::AutoLock lock(lock_);
382 dns_config_ = dns_config;
385 private:
386 mutable base::Lock lock_;
387 DnsConfig dns_config_;
390 NetworkChangeNotifier::NetworkChangeCalculatorParams::
391 NetworkChangeCalculatorParams() {
394 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
395 class NetworkChangeNotifier::NetworkChangeCalculator
396 : public ConnectionTypeObserver,
397 public IPAddressObserver {
398 public:
399 NetworkChangeCalculator(const NetworkChangeCalculatorParams& params)
400 : params_(params),
401 have_announced_(false),
402 last_announced_connection_type_(CONNECTION_NONE),
403 pending_connection_type_(CONNECTION_NONE) {}
405 void Init() {
406 DCHECK(thread_checker_.CalledOnValidThread());
407 DCHECK(g_network_change_notifier);
408 AddConnectionTypeObserver(this);
409 AddIPAddressObserver(this);
412 virtual ~NetworkChangeCalculator() {
413 DCHECK(thread_checker_.CalledOnValidThread());
414 DCHECK(g_network_change_notifier);
415 RemoveConnectionTypeObserver(this);
416 RemoveIPAddressObserver(this);
419 // NetworkChangeNotifier::IPAddressObserver implementation.
420 virtual void OnIPAddressChanged() OVERRIDE {
421 DCHECK(thread_checker_.CalledOnValidThread());
422 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
423 ? params_.ip_address_offline_delay_ : params_.ip_address_online_delay_;
424 // Cancels any previous timer.
425 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
428 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
429 virtual void OnConnectionTypeChanged(ConnectionType type) OVERRIDE {
430 DCHECK(thread_checker_.CalledOnValidThread());
431 pending_connection_type_ = type;
432 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
433 ? params_.connection_type_offline_delay_
434 : params_.connection_type_online_delay_;
435 // Cancels any previous timer.
436 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
439 private:
440 void Notify() {
441 DCHECK(thread_checker_.CalledOnValidThread());
442 // Don't bother signaling about dead connections.
443 if (have_announced_ &&
444 (last_announced_connection_type_ == CONNECTION_NONE) &&
445 (pending_connection_type_ == CONNECTION_NONE)) {
446 return;
448 have_announced_ = true;
449 last_announced_connection_type_ = pending_connection_type_;
450 // Immediately before sending out an online signal, send out an offline
451 // signal to perform any destructive actions before constructive actions.
452 if (pending_connection_type_ != CONNECTION_NONE)
453 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE);
454 NetworkChangeNotifier::NotifyObserversOfNetworkChange(
455 pending_connection_type_);
458 const NetworkChangeCalculatorParams params_;
460 // Indicates if NotifyObserversOfNetworkChange has been called yet.
461 bool have_announced_;
462 // Last value passed to NotifyObserversOfNetworkChange.
463 ConnectionType last_announced_connection_type_;
464 // Value to pass to NotifyObserversOfNetworkChange when Notify is called.
465 ConnectionType pending_connection_type_;
466 // Used to delay notifications so duplicates can be combined.
467 base::OneShotTimer<NetworkChangeCalculator> timer_;
469 base::ThreadChecker thread_checker_;
471 DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator);
474 NetworkChangeNotifier::~NetworkChangeNotifier() {
475 network_change_calculator_.reset();
476 DCHECK_EQ(this, g_network_change_notifier);
477 g_network_change_notifier = NULL;
480 // static
481 void NetworkChangeNotifier::SetFactory(
482 NetworkChangeNotifierFactory* factory) {
483 CHECK(!g_network_change_notifier_factory);
484 g_network_change_notifier_factory = factory;
487 // static
488 NetworkChangeNotifier* NetworkChangeNotifier::Create() {
489 if (g_network_change_notifier_factory)
490 return g_network_change_notifier_factory->CreateInstance();
492 #if defined(OS_WIN)
493 NetworkChangeNotifierWin* network_change_notifier =
494 new NetworkChangeNotifierWin();
495 network_change_notifier->WatchForAddressChange();
496 return network_change_notifier;
497 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
498 // ChromeOS and Android builds MUST use their own class factory.
499 #if !defined(OS_CHROMEOS)
500 // TODO(oshima): ash_shell do not have access to chromeos'es
501 // notifier yet. Re-enable this when chromeos'es notifier moved to
502 // chromeos root directory. crbug.com/119298.
503 CHECK(false);
504 #endif
505 return NULL;
506 #elif defined(OS_LINUX)
507 return NetworkChangeNotifierLinux::Create();
508 #elif defined(OS_MACOSX)
509 return new NetworkChangeNotifierMac();
510 #else
511 NOTIMPLEMENTED();
512 return NULL;
513 #endif
516 // static
517 NetworkChangeNotifier::ConnectionType
518 NetworkChangeNotifier::GetConnectionType() {
519 return g_network_change_notifier ?
520 g_network_change_notifier->GetCurrentConnectionType() :
521 CONNECTION_UNKNOWN;
524 // static
525 void NetworkChangeNotifier::GetDnsConfig(DnsConfig* config) {
526 if (!g_network_change_notifier) {
527 *config = DnsConfig();
528 } else {
529 g_network_change_notifier->network_state_->GetDnsConfig(config);
533 // static
534 const char* NetworkChangeNotifier::ConnectionTypeToString(
535 ConnectionType type) {
536 static const char* kConnectionTypeNames[] = {
537 "CONNECTION_UNKNOWN",
538 "CONNECTION_ETHERNET",
539 "CONNECTION_WIFI",
540 "CONNECTION_2G",
541 "CONNECTION_3G",
542 "CONNECTION_4G",
543 "CONNECTION_NONE"
545 COMPILE_ASSERT(
546 arraysize(kConnectionTypeNames) ==
547 NetworkChangeNotifier::CONNECTION_NONE + 1,
548 ConnectionType_name_count_mismatch);
549 if (type < CONNECTION_UNKNOWN || type > CONNECTION_NONE) {
550 NOTREACHED();
551 return "CONNECTION_INVALID";
553 return kConnectionTypeNames[type];
556 // static
557 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest& request,
558 int bytes_read) {
559 if (!g_network_change_notifier ||
560 !g_network_change_notifier->histogram_watcher_) {
561 return;
563 g_network_change_notifier->histogram_watcher_->NotifyDataReceived(request,
564 bytes_read);
567 // static
568 void NetworkChangeNotifier::InitHistogramWatcher() {
569 if (!g_network_change_notifier)
570 return;
571 g_network_change_notifier->histogram_watcher_.reset(new HistogramWatcher());
572 g_network_change_notifier->histogram_watcher_->Init();
575 // static
576 void NetworkChangeNotifier::ShutdownHistogramWatcher() {
577 if (!g_network_change_notifier)
578 return;
579 g_network_change_notifier->histogram_watcher_.reset();
582 // static
583 void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type) {
584 #if defined(OS_ANDROID)
585 // On a connection type change to 2/3/4G, log the network operator MCC/MNC.
586 // Log zero in other cases.
587 unsigned mcc_mnc = 0;
588 if (type == NetworkChangeNotifier::CONNECTION_2G ||
589 type == NetworkChangeNotifier::CONNECTION_3G ||
590 type == NetworkChangeNotifier::CONNECTION_4G) {
591 // Log zero if not perfectly converted.
592 if (!base::StringToUint(
593 net::android::GetTelephonyNetworkOperator(), &mcc_mnc)) {
594 mcc_mnc = 0;
597 UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc);
598 #endif
601 #if defined(OS_LINUX)
602 // static
603 const internal::AddressTrackerLinux*
604 NetworkChangeNotifier::GetAddressTracker() {
605 return g_network_change_notifier ?
606 g_network_change_notifier->GetAddressTrackerInternal() : NULL;
608 #endif
610 // static
611 bool NetworkChangeNotifier::IsOffline() {
612 return GetConnectionType() == CONNECTION_NONE;
615 // static
616 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) {
617 bool is_cellular = false;
618 switch (type) {
619 case CONNECTION_2G:
620 case CONNECTION_3G:
621 case CONNECTION_4G:
622 is_cellular = true;
623 break;
624 case CONNECTION_UNKNOWN:
625 case CONNECTION_ETHERNET:
626 case CONNECTION_WIFI:
627 case CONNECTION_NONE:
628 is_cellular = false;
629 break;
631 return is_cellular;
634 // static
635 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
636 return new MockNetworkChangeNotifier();
639 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
640 if (g_network_change_notifier)
641 g_network_change_notifier->ip_address_observer_list_->AddObserver(observer);
644 void NetworkChangeNotifier::AddConnectionTypeObserver(
645 ConnectionTypeObserver* observer) {
646 if (g_network_change_notifier) {
647 g_network_change_notifier->connection_type_observer_list_->AddObserver(
648 observer);
652 void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
653 if (g_network_change_notifier) {
654 g_network_change_notifier->resolver_state_observer_list_->AddObserver(
655 observer);
659 void NetworkChangeNotifier::AddNetworkChangeObserver(
660 NetworkChangeObserver* observer) {
661 if (g_network_change_notifier) {
662 g_network_change_notifier->network_change_observer_list_->AddObserver(
663 observer);
667 void NetworkChangeNotifier::RemoveIPAddressObserver(
668 IPAddressObserver* observer) {
669 if (g_network_change_notifier) {
670 g_network_change_notifier->ip_address_observer_list_->RemoveObserver(
671 observer);
675 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
676 ConnectionTypeObserver* observer) {
677 if (g_network_change_notifier) {
678 g_network_change_notifier->connection_type_observer_list_->RemoveObserver(
679 observer);
683 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
684 if (g_network_change_notifier) {
685 g_network_change_notifier->resolver_state_observer_list_->RemoveObserver(
686 observer);
690 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
691 NetworkChangeObserver* observer) {
692 if (g_network_change_notifier) {
693 g_network_change_notifier->network_change_observer_list_->RemoveObserver(
694 observer);
698 NetworkChangeNotifier::NetworkChangeNotifier(
699 const NetworkChangeCalculatorParams& params
700 /*= NetworkChangeCalculatorParams()*/)
701 : ip_address_observer_list_(
702 new ObserverListThreadSafe<IPAddressObserver>(
703 ObserverListBase<IPAddressObserver>::NOTIFY_EXISTING_ONLY)),
704 connection_type_observer_list_(
705 new ObserverListThreadSafe<ConnectionTypeObserver>(
706 ObserverListBase<ConnectionTypeObserver>::NOTIFY_EXISTING_ONLY)),
707 resolver_state_observer_list_(
708 new ObserverListThreadSafe<DNSObserver>(
709 ObserverListBase<DNSObserver>::NOTIFY_EXISTING_ONLY)),
710 network_change_observer_list_(
711 new ObserverListThreadSafe<NetworkChangeObserver>(
712 ObserverListBase<NetworkChangeObserver>::NOTIFY_EXISTING_ONLY)),
713 network_state_(new NetworkState()),
714 network_change_calculator_(new NetworkChangeCalculator(params)) {
715 DCHECK(!g_network_change_notifier);
716 g_network_change_notifier = this;
717 network_change_calculator_->Init();
720 #if defined(OS_LINUX)
721 const internal::AddressTrackerLinux*
722 NetworkChangeNotifier::GetAddressTrackerInternal() const {
723 return NULL;
725 #endif
727 // static
728 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
729 if (g_network_change_notifier) {
730 g_network_change_notifier->ip_address_observer_list_->Notify(
731 &IPAddressObserver::OnIPAddressChanged);
735 // static
736 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
737 if (g_network_change_notifier) {
738 g_network_change_notifier->resolver_state_observer_list_->Notify(
739 &DNSObserver::OnDNSChanged);
743 // static
744 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) {
745 if (!g_network_change_notifier)
746 return;
747 g_network_change_notifier->network_state_->SetDnsConfig(config);
748 NotifyObserversOfDNSChange();
751 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
752 if (g_network_change_notifier) {
753 g_network_change_notifier->connection_type_observer_list_->Notify(
754 &ConnectionTypeObserver::OnConnectionTypeChanged,
755 GetConnectionType());
759 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
760 ConnectionType type) {
761 if (g_network_change_notifier) {
762 g_network_change_notifier->network_change_observer_list_->Notify(
763 &NetworkChangeObserver::OnNetworkChanged,
764 type);
768 NetworkChangeNotifier::DisableForTest::DisableForTest()
769 : network_change_notifier_(g_network_change_notifier) {
770 DCHECK(g_network_change_notifier);
771 g_network_change_notifier = NULL;
774 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
775 DCHECK(!g_network_change_notifier);
776 g_network_change_notifier = network_change_notifier_;
779 } // namespace net