Explicitly add python-numpy dependency to install-build-deps.
[chromium-blink-merge.git] / net / base / network_change_notifier.cc
blobafd6b23d4fa2a0646ef30086ddfea1a86a0c5117
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 <limits>
9 #include "base/metrics/histogram.h"
10 #include "base/synchronization/lock.h"
11 #include "base/threading/thread_checker.h"
12 #include "build/build_config.h"
13 #include "net/base/net_util.h"
14 #include "net/base/network_change_notifier_factory.h"
15 #include "net/dns/dns_config_service.h"
16 #include "net/url_request/url_request.h"
17 #include "url/gurl.h"
19 #if defined(OS_ANDROID)
20 #include "base/metrics/sparse_histogram.h"
21 #include "base/strings/string_number_conversions.h"
22 #include "net/android/network_library.h"
23 #endif
25 #if defined(OS_WIN)
26 #include "net/base/network_change_notifier_win.h"
27 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
28 #include "net/base/network_change_notifier_linux.h"
29 #elif defined(OS_MACOSX)
30 #include "net/base/network_change_notifier_mac.h"
31 #endif
33 namespace net {
35 namespace {
37 // The actual singleton notifier. The class contract forbids usage of the API
38 // in ways that would require us to place locks around access to this object.
39 // (The prohibition on global non-POD objects makes it tricky to do such a thing
40 // anyway.)
41 NetworkChangeNotifier* g_network_change_notifier = NULL;
43 // Class factory singleton.
44 NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL;
46 class MockNetworkChangeNotifier : public NetworkChangeNotifier {
47 public:
48 ConnectionType GetCurrentConnectionType() const override {
49 return CONNECTION_UNKNOWN;
53 } // namespace
55 // The main observer class that records UMAs for network events.
56 class HistogramWatcher
57 : public NetworkChangeNotifier::ConnectionTypeObserver,
58 public NetworkChangeNotifier::IPAddressObserver,
59 public NetworkChangeNotifier::DNSObserver,
60 public NetworkChangeNotifier::NetworkChangeObserver {
61 public:
62 HistogramWatcher()
63 : last_ip_address_change_(base::TimeTicks::Now()),
64 last_connection_change_(base::TimeTicks::Now()),
65 last_dns_change_(base::TimeTicks::Now()),
66 last_network_change_(base::TimeTicks::Now()),
67 last_connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
68 offline_packets_received_(0),
69 bytes_read_since_last_connection_change_(0),
70 peak_kbps_since_last_connection_change_(0) {}
72 // Registers our three Observer implementations. This is called from the
73 // network thread so that our Observer implementations are also called
74 // from the network thread. This avoids multi-threaded race conditions
75 // because the only other interface, |NotifyDataReceived| is also
76 // only called from the network thread.
77 void Init() {
78 DCHECK(thread_checker_.CalledOnValidThread());
79 DCHECK(g_network_change_notifier);
80 NetworkChangeNotifier::AddConnectionTypeObserver(this);
81 NetworkChangeNotifier::AddIPAddressObserver(this);
82 NetworkChangeNotifier::AddDNSObserver(this);
83 NetworkChangeNotifier::AddNetworkChangeObserver(this);
86 ~HistogramWatcher() override {
87 DCHECK(thread_checker_.CalledOnValidThread());
88 DCHECK(g_network_change_notifier);
89 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
90 NetworkChangeNotifier::RemoveIPAddressObserver(this);
91 NetworkChangeNotifier::RemoveDNSObserver(this);
92 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
95 // NetworkChangeNotifier::IPAddressObserver implementation.
96 void OnIPAddressChanged() override {
97 DCHECK(thread_checker_.CalledOnValidThread());
98 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.IPAddressChange",
99 SinceLast(&last_ip_address_change_));
100 UMA_HISTOGRAM_MEDIUM_TIMES(
101 "NCN.ConnectionTypeChangeToIPAddressChange",
102 last_ip_address_change_ - last_connection_change_);
105 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
106 void OnConnectionTypeChanged(
107 NetworkChangeNotifier::ConnectionType type) override {
108 DCHECK(thread_checker_.CalledOnValidThread());
109 base::TimeTicks now = base::TimeTicks::Now();
110 int32 kilobytes_read = bytes_read_since_last_connection_change_ / 1000;
111 base::TimeDelta state_duration = SinceLast(&last_connection_change_);
112 if (bytes_read_since_last_connection_change_) {
113 switch (last_connection_type_) {
114 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
115 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnUnknown",
116 first_byte_after_connection_change_);
117 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnUnknown",
118 fastest_RTT_since_last_connection_change_);
119 break;
120 case NetworkChangeNotifier::CONNECTION_ETHERNET:
121 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnEthernet",
122 first_byte_after_connection_change_);
123 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnEthernet",
124 fastest_RTT_since_last_connection_change_);
125 break;
126 case NetworkChangeNotifier::CONNECTION_WIFI:
127 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnWifi",
128 first_byte_after_connection_change_);
129 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnWifi",
130 fastest_RTT_since_last_connection_change_);
131 break;
132 case NetworkChangeNotifier::CONNECTION_2G:
133 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn2G",
134 first_byte_after_connection_change_);
135 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn2G",
136 fastest_RTT_since_last_connection_change_);
137 break;
138 case NetworkChangeNotifier::CONNECTION_3G:
139 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn3G",
140 first_byte_after_connection_change_);
141 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn3G",
142 fastest_RTT_since_last_connection_change_);
143 break;
144 case NetworkChangeNotifier::CONNECTION_4G:
145 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn4G",
146 first_byte_after_connection_change_);
147 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn4G",
148 fastest_RTT_since_last_connection_change_);
149 break;
150 case NetworkChangeNotifier::CONNECTION_NONE:
151 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnNone",
152 first_byte_after_connection_change_);
153 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnNone",
154 fastest_RTT_since_last_connection_change_);
155 break;
156 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
157 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnBluetooth",
158 first_byte_after_connection_change_);
159 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnBluetooth",
160 fastest_RTT_since_last_connection_change_);
163 if (peak_kbps_since_last_connection_change_) {
164 switch (last_connection_type_) {
165 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
166 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnUnknown",
167 peak_kbps_since_last_connection_change_);
168 break;
169 case NetworkChangeNotifier::CONNECTION_ETHERNET:
170 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
171 peak_kbps_since_last_connection_change_);
172 break;
173 case NetworkChangeNotifier::CONNECTION_WIFI:
174 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
175 peak_kbps_since_last_connection_change_);
176 break;
177 case NetworkChangeNotifier::CONNECTION_2G:
178 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
179 peak_kbps_since_last_connection_change_);
180 break;
181 case NetworkChangeNotifier::CONNECTION_3G:
182 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
183 peak_kbps_since_last_connection_change_);
184 break;
185 case NetworkChangeNotifier::CONNECTION_4G:
186 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
187 peak_kbps_since_last_connection_change_);
188 break;
189 case NetworkChangeNotifier::CONNECTION_NONE:
190 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
191 peak_kbps_since_last_connection_change_);
192 break;
193 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
194 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnBluetooth",
195 peak_kbps_since_last_connection_change_);
196 break;
199 switch (last_connection_type_) {
200 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
201 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnUnknown", state_duration);
202 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnUnknown", kilobytes_read);
203 break;
204 case NetworkChangeNotifier::CONNECTION_ETHERNET:
205 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration);
206 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read);
207 break;
208 case NetworkChangeNotifier::CONNECTION_WIFI:
209 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration);
210 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read);
211 break;
212 case NetworkChangeNotifier::CONNECTION_2G:
213 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration);
214 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read);
215 break;
216 case NetworkChangeNotifier::CONNECTION_3G:
217 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration);
218 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read);
219 break;
220 case NetworkChangeNotifier::CONNECTION_4G:
221 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration);
222 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read);
223 break;
224 case NetworkChangeNotifier::CONNECTION_NONE:
225 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration);
226 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read);
227 break;
228 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
229 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnBluetooth", state_duration);
230 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnBluetooth", kilobytes_read);
231 break;
234 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
235 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration);
237 if (offline_packets_received_) {
238 if ((now - last_offline_packet_received_) <
239 base::TimeDelta::FromSeconds(5)) {
240 // We can compare this sum with the sum of NCN.OfflineDataRecv.
241 UMA_HISTOGRAM_COUNTS_10000(
242 "NCN.OfflineDataRecvAny5sBeforeOnline",
243 offline_packets_received_);
246 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
247 now - last_offline_packet_received_);
249 } else {
250 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration);
253 NetworkChangeNotifier::LogOperatorCodeHistogram(type);
255 UMA_HISTOGRAM_MEDIUM_TIMES(
256 "NCN.IPAddressChangeToConnectionTypeChange",
257 now - last_ip_address_change_);
259 offline_packets_received_ = 0;
260 bytes_read_since_last_connection_change_ = 0;
261 peak_kbps_since_last_connection_change_ = 0;
262 last_connection_type_ = type;
263 polling_interval_ = base::TimeDelta::FromSeconds(1);
266 // NetworkChangeNotifier::DNSObserver implementation.
267 void OnDNSChanged() override {
268 DCHECK(thread_checker_.CalledOnValidThread());
269 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
270 SinceLast(&last_dns_change_));
273 // NetworkChangeNotifier::NetworkChangeObserver implementation.
274 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override {
275 DCHECK(thread_checker_.CalledOnValidThread());
276 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
277 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOnlineChange",
278 SinceLast(&last_network_change_));
279 } else {
280 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
281 SinceLast(&last_network_change_));
285 // Record histogram data whenever we receive a packet. Should only be called
286 // from the network thread.
287 void NotifyDataReceived(const URLRequest& request, int bytes_read) {
288 DCHECK(thread_checker_.CalledOnValidThread());
289 if (IsLocalhost(request.url().host()) ||
290 !request.url().SchemeIsHTTPOrHTTPS()) {
291 return;
294 base::TimeTicks now = base::TimeTicks::Now();
295 base::TimeDelta request_duration = now - request.creation_time();
296 if (bytes_read_since_last_connection_change_ == 0) {
297 first_byte_after_connection_change_ = now - last_connection_change_;
298 fastest_RTT_since_last_connection_change_ = request_duration;
300 bytes_read_since_last_connection_change_ += bytes_read;
301 if (request_duration < fastest_RTT_since_last_connection_change_)
302 fastest_RTT_since_last_connection_change_ = request_duration;
303 // Ignore tiny transfers which will not produce accurate rates.
304 // Ignore zero duration transfers which might cause divide by zero.
305 if (bytes_read > 10000 &&
306 request_duration > base::TimeDelta::FromMilliseconds(1) &&
307 request.creation_time() > last_connection_change_) {
308 int32 kbps = bytes_read * 8 / request_duration.InMilliseconds();
309 if (kbps > peak_kbps_since_last_connection_change_)
310 peak_kbps_since_last_connection_change_ = kbps;
313 if (last_connection_type_ != NetworkChangeNotifier::CONNECTION_NONE)
314 return;
316 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
317 now - last_connection_change_);
318 offline_packets_received_++;
319 last_offline_packet_received_ = now;
321 if ((now - last_polled_connection_) > polling_interval_) {
322 polling_interval_ *= 2;
323 last_polled_connection_ = now;
324 last_polled_connection_type_ =
325 NetworkChangeNotifier::GetConnectionType();
327 if (last_polled_connection_type_ ==
328 NetworkChangeNotifier::CONNECTION_NONE) {
329 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
330 now - last_connection_change_);
334 private:
335 static base::TimeDelta SinceLast(base::TimeTicks *last_time) {
336 base::TimeTicks current_time = base::TimeTicks::Now();
337 base::TimeDelta delta = current_time - *last_time;
338 *last_time = current_time;
339 return delta;
342 base::TimeTicks last_ip_address_change_;
343 base::TimeTicks last_connection_change_;
344 base::TimeTicks last_dns_change_;
345 base::TimeTicks last_network_change_;
346 base::TimeTicks last_offline_packet_received_;
347 base::TimeTicks last_polled_connection_;
348 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
349 // first transition to offline and on subsequent transitions. Once offline,
350 // |polling_interval_| doubles as offline data is received and we poll
351 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
352 // state.
353 base::TimeDelta polling_interval_;
354 // |last_connection_type_| is the last value passed to
355 // |OnConnectionTypeChanged|.
356 NetworkChangeNotifier::ConnectionType last_connection_type_;
357 // |last_polled_connection_type_| is last result from calling
358 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
359 NetworkChangeNotifier::ConnectionType last_polled_connection_type_;
360 // Count of how many times NotifyDataReceived() has been called while the
361 // NetworkChangeNotifier thought network connection was offline.
362 int32 offline_packets_received_;
363 // Number of bytes of network data received since last connectivity change.
364 int32 bytes_read_since_last_connection_change_;
365 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
366 // from URLRequest creation until first byte received.
367 base::TimeDelta fastest_RTT_since_last_connection_change_;
368 // Time between connectivity change and first network data byte received.
369 base::TimeDelta first_byte_after_connection_change_;
370 // Rough measurement of peak KB/s witnessed since last connectivity change.
371 // The accuracy is decreased by ignoring these factors:
372 // 1) Multiple URLRequests can occur concurrently.
373 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest.
374 // 3) The transfer time includes at least one RTT while no bytes are read.
375 // Erring on the conservative side is hopefully offset by taking the maximum.
376 int32 peak_kbps_since_last_connection_change_;
378 base::ThreadChecker thread_checker_;
380 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher);
383 // NetworkState is thread safe.
384 class NetworkChangeNotifier::NetworkState {
385 public:
386 NetworkState() {}
387 ~NetworkState() {}
389 void GetDnsConfig(DnsConfig* config) const {
390 base::AutoLock lock(lock_);
391 *config = dns_config_;
394 void SetDnsConfig(const DnsConfig& dns_config) {
395 base::AutoLock lock(lock_);
396 dns_config_ = dns_config;
399 private:
400 mutable base::Lock lock_;
401 DnsConfig dns_config_;
404 NetworkChangeNotifier::NetworkChangeCalculatorParams::
405 NetworkChangeCalculatorParams() {
408 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
409 class NetworkChangeNotifier::NetworkChangeCalculator
410 : public ConnectionTypeObserver,
411 public IPAddressObserver {
412 public:
413 NetworkChangeCalculator(const NetworkChangeCalculatorParams& params)
414 : params_(params),
415 have_announced_(false),
416 last_announced_connection_type_(CONNECTION_NONE),
417 pending_connection_type_(CONNECTION_NONE) {}
419 void Init() {
420 DCHECK(thread_checker_.CalledOnValidThread());
421 DCHECK(g_network_change_notifier);
422 AddConnectionTypeObserver(this);
423 AddIPAddressObserver(this);
426 ~NetworkChangeCalculator() override {
427 DCHECK(thread_checker_.CalledOnValidThread());
428 DCHECK(g_network_change_notifier);
429 RemoveConnectionTypeObserver(this);
430 RemoveIPAddressObserver(this);
433 // NetworkChangeNotifier::IPAddressObserver implementation.
434 void OnIPAddressChanged() override {
435 DCHECK(thread_checker_.CalledOnValidThread());
436 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
437 ? params_.ip_address_offline_delay_ : params_.ip_address_online_delay_;
438 // Cancels any previous timer.
439 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
442 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
443 void OnConnectionTypeChanged(ConnectionType type) override {
444 DCHECK(thread_checker_.CalledOnValidThread());
445 pending_connection_type_ = type;
446 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
447 ? params_.connection_type_offline_delay_
448 : params_.connection_type_online_delay_;
449 // Cancels any previous timer.
450 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
453 private:
454 void Notify() {
455 DCHECK(thread_checker_.CalledOnValidThread());
456 // Don't bother signaling about dead connections.
457 if (have_announced_ &&
458 (last_announced_connection_type_ == CONNECTION_NONE) &&
459 (pending_connection_type_ == CONNECTION_NONE)) {
460 return;
462 have_announced_ = true;
463 last_announced_connection_type_ = pending_connection_type_;
464 // Immediately before sending out an online signal, send out an offline
465 // signal to perform any destructive actions before constructive actions.
466 if (pending_connection_type_ != CONNECTION_NONE)
467 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE);
468 NetworkChangeNotifier::NotifyObserversOfNetworkChange(
469 pending_connection_type_);
472 const NetworkChangeCalculatorParams params_;
474 // Indicates if NotifyObserversOfNetworkChange has been called yet.
475 bool have_announced_;
476 // Last value passed to NotifyObserversOfNetworkChange.
477 ConnectionType last_announced_connection_type_;
478 // Value to pass to NotifyObserversOfNetworkChange when Notify is called.
479 ConnectionType pending_connection_type_;
480 // Used to delay notifications so duplicates can be combined.
481 base::OneShotTimer<NetworkChangeCalculator> timer_;
483 base::ThreadChecker thread_checker_;
485 DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator);
488 NetworkChangeNotifier::~NetworkChangeNotifier() {
489 network_change_calculator_.reset();
490 DCHECK_EQ(this, g_network_change_notifier);
491 g_network_change_notifier = NULL;
494 // static
495 void NetworkChangeNotifier::SetFactory(
496 NetworkChangeNotifierFactory* factory) {
497 CHECK(!g_network_change_notifier_factory);
498 g_network_change_notifier_factory = factory;
501 // static
502 NetworkChangeNotifier* NetworkChangeNotifier::Create() {
503 if (g_network_change_notifier_factory)
504 return g_network_change_notifier_factory->CreateInstance();
506 #if defined(OS_WIN)
507 NetworkChangeNotifierWin* network_change_notifier =
508 new NetworkChangeNotifierWin();
509 network_change_notifier->WatchForAddressChange();
510 return network_change_notifier;
511 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
512 // ChromeOS and Android builds MUST use their own class factory.
513 #if !defined(OS_CHROMEOS)
514 // TODO(oshima): ash_shell do not have access to chromeos'es
515 // notifier yet. Re-enable this when chromeos'es notifier moved to
516 // chromeos root directory. crbug.com/119298.
517 CHECK(false);
518 #endif
519 return NULL;
520 #elif defined(OS_LINUX)
521 return NetworkChangeNotifierLinux::Create();
522 #elif defined(OS_MACOSX)
523 return new NetworkChangeNotifierMac();
524 #else
525 NOTIMPLEMENTED();
526 return NULL;
527 #endif
530 // static
531 NetworkChangeNotifier::ConnectionType
532 NetworkChangeNotifier::GetConnectionType() {
533 return g_network_change_notifier ?
534 g_network_change_notifier->GetCurrentConnectionType() :
535 CONNECTION_UNKNOWN;
538 // static
539 double NetworkChangeNotifier::GetMaxBandwidth() {
540 return g_network_change_notifier ?
541 g_network_change_notifier->GetCurrentMaxBandwidth() :
542 std::numeric_limits<double>::infinity();
545 // static
546 void NetworkChangeNotifier::GetDnsConfig(DnsConfig* config) {
547 if (!g_network_change_notifier) {
548 *config = DnsConfig();
549 } else {
550 g_network_change_notifier->network_state_->GetDnsConfig(config);
554 // static
555 const char* NetworkChangeNotifier::ConnectionTypeToString(
556 ConnectionType type) {
557 static const char* kConnectionTypeNames[] = {
558 "CONNECTION_UNKNOWN",
559 "CONNECTION_ETHERNET",
560 "CONNECTION_WIFI",
561 "CONNECTION_2G",
562 "CONNECTION_3G",
563 "CONNECTION_4G",
564 "CONNECTION_NONE",
565 "CONNECTION_BLUETOOTH"
567 COMPILE_ASSERT(
568 arraysize(kConnectionTypeNames) ==
569 NetworkChangeNotifier::CONNECTION_LAST + 1,
570 ConnectionType_name_count_mismatch);
571 if (type < CONNECTION_UNKNOWN || type > CONNECTION_LAST) {
572 NOTREACHED();
573 return "CONNECTION_INVALID";
575 return kConnectionTypeNames[type];
578 // static
579 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest& request,
580 int bytes_read) {
581 if (!g_network_change_notifier ||
582 !g_network_change_notifier->histogram_watcher_) {
583 return;
585 g_network_change_notifier->histogram_watcher_->NotifyDataReceived(request,
586 bytes_read);
589 // static
590 void NetworkChangeNotifier::InitHistogramWatcher() {
591 if (!g_network_change_notifier)
592 return;
593 g_network_change_notifier->histogram_watcher_.reset(new HistogramWatcher());
594 g_network_change_notifier->histogram_watcher_->Init();
597 // static
598 void NetworkChangeNotifier::ShutdownHistogramWatcher() {
599 if (!g_network_change_notifier)
600 return;
601 g_network_change_notifier->histogram_watcher_.reset();
604 // static
605 void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type) {
606 #if defined(OS_ANDROID)
607 // On a connection type change to 2/3/4G, log the network operator MCC/MNC.
608 // Log zero in other cases.
609 unsigned mcc_mnc = 0;
610 if (type == NetworkChangeNotifier::CONNECTION_2G ||
611 type == NetworkChangeNotifier::CONNECTION_3G ||
612 type == NetworkChangeNotifier::CONNECTION_4G) {
613 // Log zero if not perfectly converted.
614 if (!base::StringToUint(
615 net::android::GetTelephonyNetworkOperator(), &mcc_mnc)) {
616 mcc_mnc = 0;
619 UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc);
620 #endif
623 #if defined(OS_LINUX)
624 // static
625 const internal::AddressTrackerLinux*
626 NetworkChangeNotifier::GetAddressTracker() {
627 return g_network_change_notifier ?
628 g_network_change_notifier->GetAddressTrackerInternal() : NULL;
630 #endif
632 // static
633 bool NetworkChangeNotifier::IsOffline() {
634 return GetConnectionType() == CONNECTION_NONE;
637 // static
638 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) {
639 bool is_cellular = false;
640 switch (type) {
641 case CONNECTION_2G:
642 case CONNECTION_3G:
643 case CONNECTION_4G:
644 is_cellular = true;
645 break;
646 case CONNECTION_UNKNOWN:
647 case CONNECTION_ETHERNET:
648 case CONNECTION_WIFI:
649 case CONNECTION_NONE:
650 case CONNECTION_BLUETOOTH:
651 is_cellular = false;
652 break;
654 return is_cellular;
657 // static
658 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
659 return new MockNetworkChangeNotifier();
662 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
663 if (g_network_change_notifier)
664 g_network_change_notifier->ip_address_observer_list_->AddObserver(observer);
667 void NetworkChangeNotifier::AddConnectionTypeObserver(
668 ConnectionTypeObserver* observer) {
669 if (g_network_change_notifier) {
670 g_network_change_notifier->connection_type_observer_list_->AddObserver(
671 observer);
675 void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
676 if (g_network_change_notifier) {
677 g_network_change_notifier->resolver_state_observer_list_->AddObserver(
678 observer);
682 void NetworkChangeNotifier::AddNetworkChangeObserver(
683 NetworkChangeObserver* observer) {
684 if (g_network_change_notifier) {
685 g_network_change_notifier->network_change_observer_list_->AddObserver(
686 observer);
690 void NetworkChangeNotifier::RemoveIPAddressObserver(
691 IPAddressObserver* observer) {
692 if (g_network_change_notifier) {
693 g_network_change_notifier->ip_address_observer_list_->RemoveObserver(
694 observer);
698 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
699 ConnectionTypeObserver* observer) {
700 if (g_network_change_notifier) {
701 g_network_change_notifier->connection_type_observer_list_->RemoveObserver(
702 observer);
706 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
707 if (g_network_change_notifier) {
708 g_network_change_notifier->resolver_state_observer_list_->RemoveObserver(
709 observer);
713 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
714 NetworkChangeObserver* observer) {
715 if (g_network_change_notifier) {
716 g_network_change_notifier->network_change_observer_list_->RemoveObserver(
717 observer);
721 // static
722 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
723 if (g_network_change_notifier)
724 g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
727 // static
728 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
729 ConnectionType type) {
730 if (g_network_change_notifier)
731 g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type);
734 // static
735 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
736 ConnectionType type) {
737 if (g_network_change_notifier)
738 g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
741 // static
742 void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only) {
743 if (g_network_change_notifier)
744 g_network_change_notifier->test_notifications_only_ = test_only;
747 NetworkChangeNotifier::NetworkChangeNotifier(
748 const NetworkChangeCalculatorParams& params
749 /*= NetworkChangeCalculatorParams()*/)
750 : ip_address_observer_list_(
751 new ObserverListThreadSafe<IPAddressObserver>(
752 ObserverListBase<IPAddressObserver>::NOTIFY_EXISTING_ONLY)),
753 connection_type_observer_list_(
754 new ObserverListThreadSafe<ConnectionTypeObserver>(
755 ObserverListBase<ConnectionTypeObserver>::NOTIFY_EXISTING_ONLY)),
756 resolver_state_observer_list_(
757 new ObserverListThreadSafe<DNSObserver>(
758 ObserverListBase<DNSObserver>::NOTIFY_EXISTING_ONLY)),
759 network_change_observer_list_(
760 new ObserverListThreadSafe<NetworkChangeObserver>(
761 ObserverListBase<NetworkChangeObserver>::NOTIFY_EXISTING_ONLY)),
762 network_state_(new NetworkState()),
763 network_change_calculator_(new NetworkChangeCalculator(params)),
764 test_notifications_only_(false) {
765 DCHECK(!g_network_change_notifier);
766 g_network_change_notifier = this;
767 network_change_calculator_->Init();
770 #if defined(OS_LINUX)
771 const internal::AddressTrackerLinux*
772 NetworkChangeNotifier::GetAddressTrackerInternal() const {
773 return NULL;
775 #endif
777 double NetworkChangeNotifier::GetCurrentMaxBandwidth() const {
778 // This default implementation conforms to the NetInfo V3 specification but
779 // should be overridden to provide specific bandwidth data based on the
780 // platform.
781 if (GetCurrentConnectionType() == CONNECTION_NONE)
782 return 0.0;
783 return std::numeric_limits<double>::infinity();
786 // static
787 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
788 if (g_network_change_notifier &&
789 !g_network_change_notifier->test_notifications_only_) {
790 g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
794 // static
795 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
796 if (g_network_change_notifier &&
797 !g_network_change_notifier->test_notifications_only_) {
798 g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(
799 GetConnectionType());
803 // static
804 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
805 ConnectionType type) {
806 if (g_network_change_notifier &&
807 !g_network_change_notifier->test_notifications_only_) {
808 g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
812 // static
813 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
814 if (g_network_change_notifier &&
815 !g_network_change_notifier->test_notifications_only_) {
816 g_network_change_notifier->NotifyObserversOfDNSChangeImpl();
820 // static
821 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) {
822 if (!g_network_change_notifier)
823 return;
824 g_network_change_notifier->network_state_->SetDnsConfig(config);
825 NotifyObserversOfDNSChange();
828 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
829 ip_address_observer_list_->Notify(&IPAddressObserver::OnIPAddressChanged);
832 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
833 ConnectionType type) {
834 connection_type_observer_list_->Notify(
835 &ConnectionTypeObserver::OnConnectionTypeChanged, type);
838 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
839 ConnectionType type) {
840 network_change_observer_list_->Notify(
841 &NetworkChangeObserver::OnNetworkChanged, type);
844 void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
845 resolver_state_observer_list_->Notify(&DNSObserver::OnDNSChanged);
848 NetworkChangeNotifier::DisableForTest::DisableForTest()
849 : network_change_notifier_(g_network_change_notifier) {
850 DCHECK(g_network_change_notifier);
851 g_network_change_notifier = NULL;
854 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
855 DCHECK(!g_network_change_notifier);
856 g_network_change_notifier = network_change_notifier_;
859 } // namespace net