Mac Partial Swap: Fix sub-layer rounding issue
[chromium-blink-merge.git] / net / base / network_change_notifier.cc
blob12a637757ce7fbb7b5cd839794fdb2586e869294
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_macros.h"
10 #include "base/strings/string_util.h"
11 #include "base/synchronization/lock.h"
12 #include "base/threading/thread_checker.h"
13 #include "build/build_config.h"
14 #include "net/base/net_util.h"
15 #include "net/base/network_change_notifier_factory.h"
16 #include "net/dns/dns_config_service.h"
17 #include "net/url_request/url_request.h"
18 #include "url/gurl.h"
20 #if defined(OS_ANDROID)
21 #include "base/metrics/sparse_histogram.h"
22 #include "base/strings/string_number_conversions.h"
23 #include "net/android/network_library.h"
24 #endif
26 #if defined(OS_WIN)
27 #include "net/base/network_change_notifier_win.h"
28 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
29 #include "net/base/network_change_notifier_linux.h"
30 #elif defined(OS_MACOSX)
31 #include "net/base/network_change_notifier_mac.h"
32 #endif
34 namespace net {
36 namespace {
38 // The actual singleton notifier. The class contract forbids usage of the API
39 // in ways that would require us to place locks around access to this object.
40 // (The prohibition on global non-POD objects makes it tricky to do such a thing
41 // anyway.)
42 NetworkChangeNotifier* g_network_change_notifier = NULL;
44 // Class factory singleton.
45 NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL;
47 class MockNetworkChangeNotifier : public NetworkChangeNotifier {
48 public:
49 ConnectionType GetCurrentConnectionType() const override {
50 return CONNECTION_UNKNOWN;
54 } // namespace
56 // static
57 bool NetworkChangeNotifier::test_notifications_only_ = false;
59 // The main observer class that records UMAs for network events.
60 class HistogramWatcher
61 : public NetworkChangeNotifier::ConnectionTypeObserver,
62 public NetworkChangeNotifier::IPAddressObserver,
63 public NetworkChangeNotifier::DNSObserver,
64 public NetworkChangeNotifier::NetworkChangeObserver {
65 public:
66 HistogramWatcher()
67 : last_ip_address_change_(base::TimeTicks::Now()),
68 last_connection_change_(base::TimeTicks::Now()),
69 last_dns_change_(base::TimeTicks::Now()),
70 last_network_change_(base::TimeTicks::Now()),
71 last_connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
72 offline_packets_received_(0),
73 bytes_read_since_last_connection_change_(0),
74 peak_kbps_since_last_connection_change_(0) {}
76 // Registers our three Observer implementations. This is called from the
77 // network thread so that our Observer implementations are also called
78 // from the network thread. This avoids multi-threaded race conditions
79 // because the only other interface, |NotifyDataReceived| is also
80 // only called from the network thread.
81 void Init() {
82 DCHECK(thread_checker_.CalledOnValidThread());
83 DCHECK(g_network_change_notifier);
84 NetworkChangeNotifier::AddConnectionTypeObserver(this);
85 NetworkChangeNotifier::AddIPAddressObserver(this);
86 NetworkChangeNotifier::AddDNSObserver(this);
87 NetworkChangeNotifier::AddNetworkChangeObserver(this);
90 ~HistogramWatcher() override {
91 DCHECK(thread_checker_.CalledOnValidThread());
92 DCHECK(g_network_change_notifier);
93 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
94 NetworkChangeNotifier::RemoveIPAddressObserver(this);
95 NetworkChangeNotifier::RemoveDNSObserver(this);
96 NetworkChangeNotifier::RemoveNetworkChangeObserver(this);
99 // NetworkChangeNotifier::IPAddressObserver implementation.
100 void OnIPAddressChanged() override {
101 DCHECK(thread_checker_.CalledOnValidThread());
102 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.IPAddressChange",
103 SinceLast(&last_ip_address_change_));
104 UMA_HISTOGRAM_MEDIUM_TIMES(
105 "NCN.ConnectionTypeChangeToIPAddressChange",
106 last_ip_address_change_ - last_connection_change_);
109 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
110 void OnConnectionTypeChanged(
111 NetworkChangeNotifier::ConnectionType type) override {
112 DCHECK(thread_checker_.CalledOnValidThread());
113 base::TimeTicks now = base::TimeTicks::Now();
114 int32_t kilobytes_read = bytes_read_since_last_connection_change_ / 1000;
115 base::TimeDelta state_duration = SinceLast(&last_connection_change_);
116 if (bytes_read_since_last_connection_change_) {
117 switch (last_connection_type_) {
118 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
119 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnUnknown",
120 first_byte_after_connection_change_);
121 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnUnknown",
122 fastest_RTT_since_last_connection_change_);
123 break;
124 case NetworkChangeNotifier::CONNECTION_ETHERNET:
125 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnEthernet",
126 first_byte_after_connection_change_);
127 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnEthernet",
128 fastest_RTT_since_last_connection_change_);
129 break;
130 case NetworkChangeNotifier::CONNECTION_WIFI:
131 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnWifi",
132 first_byte_after_connection_change_);
133 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnWifi",
134 fastest_RTT_since_last_connection_change_);
135 break;
136 case NetworkChangeNotifier::CONNECTION_2G:
137 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn2G",
138 first_byte_after_connection_change_);
139 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn2G",
140 fastest_RTT_since_last_connection_change_);
141 break;
142 case NetworkChangeNotifier::CONNECTION_3G:
143 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn3G",
144 first_byte_after_connection_change_);
145 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn3G",
146 fastest_RTT_since_last_connection_change_);
147 break;
148 case NetworkChangeNotifier::CONNECTION_4G:
149 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn4G",
150 first_byte_after_connection_change_);
151 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn4G",
152 fastest_RTT_since_last_connection_change_);
153 break;
154 case NetworkChangeNotifier::CONNECTION_NONE:
155 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnNone",
156 first_byte_after_connection_change_);
157 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnNone",
158 fastest_RTT_since_last_connection_change_);
159 break;
160 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
161 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnBluetooth",
162 first_byte_after_connection_change_);
163 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnBluetooth",
164 fastest_RTT_since_last_connection_change_);
167 if (peak_kbps_since_last_connection_change_) {
168 switch (last_connection_type_) {
169 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
170 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnUnknown",
171 peak_kbps_since_last_connection_change_);
172 break;
173 case NetworkChangeNotifier::CONNECTION_ETHERNET:
174 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet",
175 peak_kbps_since_last_connection_change_);
176 break;
177 case NetworkChangeNotifier::CONNECTION_WIFI:
178 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi",
179 peak_kbps_since_last_connection_change_);
180 break;
181 case NetworkChangeNotifier::CONNECTION_2G:
182 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G",
183 peak_kbps_since_last_connection_change_);
184 break;
185 case NetworkChangeNotifier::CONNECTION_3G:
186 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G",
187 peak_kbps_since_last_connection_change_);
188 break;
189 case NetworkChangeNotifier::CONNECTION_4G:
190 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G",
191 peak_kbps_since_last_connection_change_);
192 break;
193 case NetworkChangeNotifier::CONNECTION_NONE:
194 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone",
195 peak_kbps_since_last_connection_change_);
196 break;
197 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
198 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnBluetooth",
199 peak_kbps_since_last_connection_change_);
200 break;
203 switch (last_connection_type_) {
204 case NetworkChangeNotifier::CONNECTION_UNKNOWN:
205 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnUnknown", state_duration);
206 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnUnknown", kilobytes_read);
207 break;
208 case NetworkChangeNotifier::CONNECTION_ETHERNET:
209 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration);
210 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read);
211 break;
212 case NetworkChangeNotifier::CONNECTION_WIFI:
213 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration);
214 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read);
215 break;
216 case NetworkChangeNotifier::CONNECTION_2G:
217 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration);
218 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read);
219 break;
220 case NetworkChangeNotifier::CONNECTION_3G:
221 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration);
222 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read);
223 break;
224 case NetworkChangeNotifier::CONNECTION_4G:
225 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration);
226 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read);
227 break;
228 case NetworkChangeNotifier::CONNECTION_NONE:
229 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration);
230 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read);
231 break;
232 case NetworkChangeNotifier::CONNECTION_BLUETOOTH:
233 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnBluetooth", state_duration);
234 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnBluetooth", kilobytes_read);
235 break;
238 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
239 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration);
241 if (offline_packets_received_) {
242 if ((now - last_offline_packet_received_) <
243 base::TimeDelta::FromSeconds(5)) {
244 // We can compare this sum with the sum of NCN.OfflineDataRecv.
245 UMA_HISTOGRAM_COUNTS_10000(
246 "NCN.OfflineDataRecvAny5sBeforeOnline",
247 offline_packets_received_);
250 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
251 now - last_offline_packet_received_);
253 } else {
254 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration);
257 NetworkChangeNotifier::LogOperatorCodeHistogram(type);
259 UMA_HISTOGRAM_MEDIUM_TIMES(
260 "NCN.IPAddressChangeToConnectionTypeChange",
261 now - last_ip_address_change_);
263 offline_packets_received_ = 0;
264 bytes_read_since_last_connection_change_ = 0;
265 peak_kbps_since_last_connection_change_ = 0;
266 last_connection_type_ = type;
267 polling_interval_ = base::TimeDelta::FromSeconds(1);
270 // NetworkChangeNotifier::DNSObserver implementation.
271 void OnDNSChanged() override {
272 DCHECK(thread_checker_.CalledOnValidThread());
273 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
274 SinceLast(&last_dns_change_));
277 // NetworkChangeNotifier::NetworkChangeObserver implementation.
278 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override {
279 DCHECK(thread_checker_.CalledOnValidThread());
280 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
281 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOnlineChange",
282 SinceLast(&last_network_change_));
283 } else {
284 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange",
285 SinceLast(&last_network_change_));
289 // Record histogram data whenever we receive a packet. Should only be called
290 // from the network thread.
291 void NotifyDataReceived(const URLRequest& request, int bytes_read) {
292 DCHECK(thread_checker_.CalledOnValidThread());
293 if (IsLocalhost(request.url().host()) ||
294 !request.url().SchemeIsHTTPOrHTTPS()) {
295 return;
298 base::TimeTicks now = base::TimeTicks::Now();
299 base::TimeDelta request_duration = now - request.creation_time();
300 if (bytes_read_since_last_connection_change_ == 0) {
301 first_byte_after_connection_change_ = now - last_connection_change_;
302 fastest_RTT_since_last_connection_change_ = request_duration;
304 bytes_read_since_last_connection_change_ += bytes_read;
305 if (request_duration < fastest_RTT_since_last_connection_change_)
306 fastest_RTT_since_last_connection_change_ = request_duration;
307 // Ignore tiny transfers which will not produce accurate rates.
308 // Ignore zero duration transfers which might cause divide by zero.
309 if (bytes_read > 10000 &&
310 request_duration > base::TimeDelta::FromMilliseconds(1) &&
311 request.creation_time() > last_connection_change_) {
312 int32_t kbps = static_cast<int32_t>(bytes_read * 8 /
313 request_duration.InMilliseconds());
314 if (kbps > peak_kbps_since_last_connection_change_)
315 peak_kbps_since_last_connection_change_ = kbps;
318 if (last_connection_type_ != NetworkChangeNotifier::CONNECTION_NONE)
319 return;
321 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
322 now - last_connection_change_);
323 offline_packets_received_++;
324 last_offline_packet_received_ = now;
326 if ((now - last_polled_connection_) > polling_interval_) {
327 polling_interval_ *= 2;
328 last_polled_connection_ = now;
329 last_polled_connection_type_ =
330 NetworkChangeNotifier::GetConnectionType();
332 if (last_polled_connection_type_ ==
333 NetworkChangeNotifier::CONNECTION_NONE) {
334 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
335 now - last_connection_change_);
339 private:
340 static base::TimeDelta SinceLast(base::TimeTicks *last_time) {
341 base::TimeTicks current_time = base::TimeTicks::Now();
342 base::TimeDelta delta = current_time - *last_time;
343 *last_time = current_time;
344 return delta;
347 base::TimeTicks last_ip_address_change_;
348 base::TimeTicks last_connection_change_;
349 base::TimeTicks last_dns_change_;
350 base::TimeTicks last_network_change_;
351 base::TimeTicks last_offline_packet_received_;
352 base::TimeTicks last_polled_connection_;
353 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
354 // first transition to offline and on subsequent transitions. Once offline,
355 // |polling_interval_| doubles as offline data is received and we poll
356 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
357 // state.
358 base::TimeDelta polling_interval_;
359 // |last_connection_type_| is the last value passed to
360 // |OnConnectionTypeChanged|.
361 NetworkChangeNotifier::ConnectionType last_connection_type_;
362 // |last_polled_connection_type_| is last result from calling
363 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
364 NetworkChangeNotifier::ConnectionType last_polled_connection_type_;
365 // Count of how many times NotifyDataReceived() has been called while the
366 // NetworkChangeNotifier thought network connection was offline.
367 int32_t offline_packets_received_;
368 // Number of bytes of network data received since last connectivity change.
369 int32_t bytes_read_since_last_connection_change_;
370 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured
371 // from URLRequest creation until first byte received.
372 base::TimeDelta fastest_RTT_since_last_connection_change_;
373 // Time between connectivity change and first network data byte received.
374 base::TimeDelta first_byte_after_connection_change_;
375 // Rough measurement of peak KB/s witnessed since last connectivity change.
376 // The accuracy is decreased by ignoring these factors:
377 // 1) Multiple URLRequests can occur concurrently.
378 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest.
379 // 3) The transfer time includes at least one RTT while no bytes are read.
380 // Erring on the conservative side is hopefully offset by taking the maximum.
381 int32_t peak_kbps_since_last_connection_change_;
383 base::ThreadChecker thread_checker_;
385 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher);
388 // NetworkState is thread safe.
389 class NetworkChangeNotifier::NetworkState {
390 public:
391 NetworkState() {}
392 ~NetworkState() {}
394 void GetDnsConfig(DnsConfig* config) const {
395 base::AutoLock lock(lock_);
396 *config = dns_config_;
399 void SetDnsConfig(const DnsConfig& dns_config) {
400 base::AutoLock lock(lock_);
401 dns_config_ = dns_config;
404 private:
405 mutable base::Lock lock_;
406 DnsConfig dns_config_;
409 NetworkChangeNotifier::NetworkChangeCalculatorParams::
410 NetworkChangeCalculatorParams() {
413 // Calculates NetworkChange signal from IPAddress and ConnectionType signals.
414 class NetworkChangeNotifier::NetworkChangeCalculator
415 : public ConnectionTypeObserver,
416 public IPAddressObserver {
417 public:
418 NetworkChangeCalculator(const NetworkChangeCalculatorParams& params)
419 : params_(params),
420 have_announced_(false),
421 last_announced_connection_type_(CONNECTION_NONE),
422 pending_connection_type_(CONNECTION_NONE) {}
424 void Init() {
425 DCHECK(thread_checker_.CalledOnValidThread());
426 DCHECK(g_network_change_notifier);
427 AddConnectionTypeObserver(this);
428 AddIPAddressObserver(this);
431 ~NetworkChangeCalculator() override {
432 DCHECK(thread_checker_.CalledOnValidThread());
433 DCHECK(g_network_change_notifier);
434 RemoveConnectionTypeObserver(this);
435 RemoveIPAddressObserver(this);
438 // NetworkChangeNotifier::IPAddressObserver implementation.
439 void OnIPAddressChanged() override {
440 DCHECK(thread_checker_.CalledOnValidThread());
441 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
442 ? params_.ip_address_offline_delay_ : params_.ip_address_online_delay_;
443 // Cancels any previous timer.
444 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
447 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
448 void OnConnectionTypeChanged(ConnectionType type) override {
449 DCHECK(thread_checker_.CalledOnValidThread());
450 pending_connection_type_ = type;
451 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
452 ? params_.connection_type_offline_delay_
453 : params_.connection_type_online_delay_;
454 // Cancels any previous timer.
455 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
458 private:
459 void Notify() {
460 DCHECK(thread_checker_.CalledOnValidThread());
461 // Don't bother signaling about dead connections.
462 if (have_announced_ &&
463 (last_announced_connection_type_ == CONNECTION_NONE) &&
464 (pending_connection_type_ == CONNECTION_NONE)) {
465 return;
467 have_announced_ = true;
468 last_announced_connection_type_ = pending_connection_type_;
469 // Immediately before sending out an online signal, send out an offline
470 // signal to perform any destructive actions before constructive actions.
471 if (pending_connection_type_ != CONNECTION_NONE)
472 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE);
473 NetworkChangeNotifier::NotifyObserversOfNetworkChange(
474 pending_connection_type_);
477 const NetworkChangeCalculatorParams params_;
479 // Indicates if NotifyObserversOfNetworkChange has been called yet.
480 bool have_announced_;
481 // Last value passed to NotifyObserversOfNetworkChange.
482 ConnectionType last_announced_connection_type_;
483 // Value to pass to NotifyObserversOfNetworkChange when Notify is called.
484 ConnectionType pending_connection_type_;
485 // Used to delay notifications so duplicates can be combined.
486 base::OneShotTimer<NetworkChangeCalculator> timer_;
488 base::ThreadChecker thread_checker_;
490 DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator);
493 NetworkChangeNotifier::~NetworkChangeNotifier() {
494 network_change_calculator_.reset();
495 DCHECK_EQ(this, g_network_change_notifier);
496 g_network_change_notifier = NULL;
499 // static
500 void NetworkChangeNotifier::SetFactory(
501 NetworkChangeNotifierFactory* factory) {
502 CHECK(!g_network_change_notifier_factory);
503 g_network_change_notifier_factory = factory;
506 // static
507 NetworkChangeNotifier* NetworkChangeNotifier::Create() {
508 if (g_network_change_notifier_factory)
509 return g_network_change_notifier_factory->CreateInstance();
511 #if defined(OS_WIN)
512 NetworkChangeNotifierWin* network_change_notifier =
513 new NetworkChangeNotifierWin();
514 network_change_notifier->WatchForAddressChange();
515 return network_change_notifier;
516 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
517 // ChromeOS and Android builds MUST use their own class factory.
518 #if !defined(OS_CHROMEOS)
519 // TODO(oshima): ash_shell do not have access to chromeos'es
520 // notifier yet. Re-enable this when chromeos'es notifier moved to
521 // chromeos root directory. crbug.com/119298.
522 CHECK(false);
523 #endif
524 return NULL;
525 #elif defined(OS_LINUX)
526 return new NetworkChangeNotifierLinux(base::hash_set<std::string>());
527 #elif defined(OS_MACOSX)
528 return new NetworkChangeNotifierMac();
529 #else
530 NOTIMPLEMENTED();
531 return NULL;
532 #endif
535 // static
536 NetworkChangeNotifier::ConnectionType
537 NetworkChangeNotifier::GetConnectionType() {
538 return g_network_change_notifier ?
539 g_network_change_notifier->GetCurrentConnectionType() :
540 CONNECTION_UNKNOWN;
543 // static
544 double NetworkChangeNotifier::GetMaxBandwidth() {
545 return g_network_change_notifier ?
546 g_network_change_notifier->GetCurrentMaxBandwidth() :
547 std::numeric_limits<double>::infinity();
550 // static
551 void NetworkChangeNotifier::GetDnsConfig(DnsConfig* config) {
552 if (!g_network_change_notifier) {
553 *config = DnsConfig();
554 } else {
555 g_network_change_notifier->network_state_->GetDnsConfig(config);
559 // static
560 const char* NetworkChangeNotifier::ConnectionTypeToString(
561 ConnectionType type) {
562 static const char* const kConnectionTypeNames[] = {
563 "CONNECTION_UNKNOWN",
564 "CONNECTION_ETHERNET",
565 "CONNECTION_WIFI",
566 "CONNECTION_2G",
567 "CONNECTION_3G",
568 "CONNECTION_4G",
569 "CONNECTION_NONE",
570 "CONNECTION_BLUETOOTH"
572 static_assert(arraysize(kConnectionTypeNames) ==
573 NetworkChangeNotifier::CONNECTION_LAST + 1,
574 "ConnectionType name count should match");
575 if (type < CONNECTION_UNKNOWN || type > CONNECTION_LAST) {
576 NOTREACHED();
577 return "CONNECTION_INVALID";
579 return kConnectionTypeNames[type];
582 // static
583 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest& request,
584 int bytes_read) {
585 if (!g_network_change_notifier ||
586 !g_network_change_notifier->histogram_watcher_) {
587 return;
589 g_network_change_notifier->histogram_watcher_->NotifyDataReceived(request,
590 bytes_read);
593 // static
594 void NetworkChangeNotifier::InitHistogramWatcher() {
595 if (!g_network_change_notifier)
596 return;
597 g_network_change_notifier->histogram_watcher_.reset(new HistogramWatcher());
598 g_network_change_notifier->histogram_watcher_->Init();
601 // static
602 void NetworkChangeNotifier::ShutdownHistogramWatcher() {
603 if (!g_network_change_notifier)
604 return;
605 g_network_change_notifier->histogram_watcher_.reset();
608 // static
609 void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type) {
610 #if defined(OS_ANDROID)
611 // On a connection type change to 2/3/4G, log the network operator MCC/MNC.
612 // Log zero in other cases.
613 unsigned mcc_mnc = 0;
614 if (type == NetworkChangeNotifier::CONNECTION_2G ||
615 type == NetworkChangeNotifier::CONNECTION_3G ||
616 type == NetworkChangeNotifier::CONNECTION_4G) {
617 // Log zero if not perfectly converted.
618 if (!base::StringToUint(android::GetTelephonyNetworkOperator(), &mcc_mnc)) {
619 mcc_mnc = 0;
622 UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc);
623 #endif
626 #if defined(OS_LINUX)
627 // static
628 const internal::AddressTrackerLinux*
629 NetworkChangeNotifier::GetAddressTracker() {
630 return g_network_change_notifier ?
631 g_network_change_notifier->GetAddressTrackerInternal() : NULL;
633 #endif
635 // static
636 bool NetworkChangeNotifier::IsOffline() {
637 return GetConnectionType() == CONNECTION_NONE;
640 // static
641 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) {
642 bool is_cellular = false;
643 switch (type) {
644 case CONNECTION_2G:
645 case CONNECTION_3G:
646 case CONNECTION_4G:
647 is_cellular = true;
648 break;
649 case CONNECTION_UNKNOWN:
650 case CONNECTION_ETHERNET:
651 case CONNECTION_WIFI:
652 case CONNECTION_NONE:
653 case CONNECTION_BLUETOOTH:
654 is_cellular = false;
655 break;
657 return is_cellular;
660 // static
661 NetworkChangeNotifier::ConnectionType
662 NetworkChangeNotifier::ConnectionTypeFromInterfaceList(
663 const NetworkInterfaceList& interfaces) {
664 bool first = true;
665 ConnectionType result = CONNECTION_NONE;
666 for (size_t i = 0; i < interfaces.size(); ++i) {
667 #if defined(OS_WIN)
668 if (interfaces[i].friendly_name == "Teredo Tunneling Pseudo-Interface")
669 continue;
670 #endif
671 // Remove VMware network interfaces as they're internal and should not be
672 // used to determine the network connection type.
673 if (base::ToLowerASCII(interfaces[i].friendly_name).find("vmnet") !=
674 std::string::npos) {
675 continue;
677 if (first) {
678 first = false;
679 result = interfaces[i].type;
680 } else if (result != interfaces[i].type) {
681 return CONNECTION_UNKNOWN;
684 return result;
687 // static
688 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
689 return new MockNetworkChangeNotifier();
692 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
693 if (g_network_change_notifier)
694 g_network_change_notifier->ip_address_observer_list_->AddObserver(observer);
697 void NetworkChangeNotifier::AddConnectionTypeObserver(
698 ConnectionTypeObserver* observer) {
699 if (g_network_change_notifier) {
700 g_network_change_notifier->connection_type_observer_list_->AddObserver(
701 observer);
705 void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
706 if (g_network_change_notifier) {
707 g_network_change_notifier->resolver_state_observer_list_->AddObserver(
708 observer);
712 void NetworkChangeNotifier::AddNetworkChangeObserver(
713 NetworkChangeObserver* observer) {
714 if (g_network_change_notifier) {
715 g_network_change_notifier->network_change_observer_list_->AddObserver(
716 observer);
720 void NetworkChangeNotifier::AddMaxBandwidthObserver(
721 MaxBandwidthObserver* observer) {
722 if (g_network_change_notifier) {
723 g_network_change_notifier->max_bandwidth_observer_list_->AddObserver(
724 observer);
728 void NetworkChangeNotifier::RemoveIPAddressObserver(
729 IPAddressObserver* observer) {
730 if (g_network_change_notifier) {
731 g_network_change_notifier->ip_address_observer_list_->RemoveObserver(
732 observer);
736 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
737 ConnectionTypeObserver* observer) {
738 if (g_network_change_notifier) {
739 g_network_change_notifier->connection_type_observer_list_->RemoveObserver(
740 observer);
744 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
745 if (g_network_change_notifier) {
746 g_network_change_notifier->resolver_state_observer_list_->RemoveObserver(
747 observer);
751 void NetworkChangeNotifier::RemoveNetworkChangeObserver(
752 NetworkChangeObserver* observer) {
753 if (g_network_change_notifier) {
754 g_network_change_notifier->network_change_observer_list_->RemoveObserver(
755 observer);
759 void NetworkChangeNotifier::RemoveMaxBandwidthObserver(
760 MaxBandwidthObserver* observer) {
761 if (g_network_change_notifier) {
762 g_network_change_notifier->max_bandwidth_observer_list_->RemoveObserver(
763 observer);
767 // static
768 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
769 if (g_network_change_notifier)
770 g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
773 // static
774 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
775 ConnectionType type) {
776 if (g_network_change_notifier)
777 g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type);
780 // static
781 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
782 ConnectionType type) {
783 if (g_network_change_notifier)
784 g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
787 // static
788 void NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigReadForTests() {
789 if (g_network_change_notifier)
790 g_network_change_notifier->NotifyObserversOfInitialDNSConfigReadImpl();
793 // static
794 void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only) {
795 DCHECK(!g_network_change_notifier);
796 NetworkChangeNotifier::test_notifications_only_ = test_only;
799 NetworkChangeNotifier::NetworkChangeNotifier(
800 const NetworkChangeCalculatorParams& params
801 /*= NetworkChangeCalculatorParams()*/)
802 : ip_address_observer_list_(
803 new base::ObserverListThreadSafe<IPAddressObserver>(
804 base::ObserverListBase<IPAddressObserver>::NOTIFY_EXISTING_ONLY)),
805 connection_type_observer_list_(
806 new base::ObserverListThreadSafe<ConnectionTypeObserver>(
807 base::ObserverListBase<
808 ConnectionTypeObserver>::NOTIFY_EXISTING_ONLY)),
809 resolver_state_observer_list_(
810 new base::ObserverListThreadSafe<DNSObserver>(
811 base::ObserverListBase<DNSObserver>::NOTIFY_EXISTING_ONLY)),
812 network_change_observer_list_(new base::ObserverListThreadSafe<
813 NetworkChangeObserver>(
814 base::ObserverListBase<NetworkChangeObserver>::NOTIFY_EXISTING_ONLY)),
815 max_bandwidth_observer_list_(new base::ObserverListThreadSafe<
816 MaxBandwidthObserver>(
817 base::ObserverListBase<MaxBandwidthObserver>::NOTIFY_EXISTING_ONLY)),
818 network_state_(new NetworkState()),
819 network_change_calculator_(new NetworkChangeCalculator(params)) {
820 DCHECK(!g_network_change_notifier);
821 g_network_change_notifier = this;
822 network_change_calculator_->Init();
825 #if defined(OS_LINUX)
826 const internal::AddressTrackerLinux*
827 NetworkChangeNotifier::GetAddressTrackerInternal() const {
828 return NULL;
830 #endif
832 double NetworkChangeNotifier::GetCurrentMaxBandwidth() const {
833 // This default implementation conforms to the NetInfo V3 specification but
834 // should be overridden to provide specific bandwidth data based on the
835 // platform.
836 if (GetCurrentConnectionType() == CONNECTION_NONE)
837 return 0.0;
838 return std::numeric_limits<double>::infinity();
841 // static
842 double NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype(
843 ConnectionSubtype subtype) {
844 switch (subtype) {
845 case SUBTYPE_GSM:
846 return 0.01;
847 case SUBTYPE_IDEN:
848 return 0.064;
849 case SUBTYPE_CDMA:
850 return 0.115;
851 case SUBTYPE_1XRTT:
852 return 0.153;
853 case SUBTYPE_GPRS:
854 return 0.237;
855 case SUBTYPE_EDGE:
856 return 0.384;
857 case SUBTYPE_UMTS:
858 return 2.0;
859 case SUBTYPE_EVDO_REV_0:
860 return 2.46;
861 case SUBTYPE_EVDO_REV_A:
862 return 3.1;
863 case SUBTYPE_HSPA:
864 return 3.6;
865 case SUBTYPE_EVDO_REV_B:
866 return 14.7;
867 case SUBTYPE_HSDPA:
868 return 14.3;
869 case SUBTYPE_HSUPA:
870 return 14.4;
871 case SUBTYPE_EHRPD:
872 return 21.0;
873 case SUBTYPE_HSPAP:
874 return 42.0;
875 case SUBTYPE_LTE:
876 return 100.0;
877 case SUBTYPE_LTE_ADVANCED:
878 return 100.0;
879 case SUBTYPE_BLUETOOTH_1_2:
880 return 1.0;
881 case SUBTYPE_BLUETOOTH_2_1:
882 return 3.0;
883 case SUBTYPE_BLUETOOTH_3_0:
884 return 24.0;
885 case SUBTYPE_BLUETOOTH_4_0:
886 return 1.0;
887 case SUBTYPE_ETHERNET:
888 return 10.0;
889 case SUBTYPE_FAST_ETHERNET:
890 return 100.0;
891 case SUBTYPE_GIGABIT_ETHERNET:
892 return 1000.0;
893 case SUBTYPE_10_GIGABIT_ETHERNET:
894 return 10000.0;
895 case SUBTYPE_WIFI_B:
896 return 11.0;
897 case SUBTYPE_WIFI_G:
898 return 54.0;
899 case SUBTYPE_WIFI_N:
900 return 600.0;
901 case SUBTYPE_WIFI_AC:
902 return 1300.0;
903 case SUBTYPE_WIFI_AD:
904 return 7000.0;
905 case SUBTYPE_UNKNOWN:
906 return std::numeric_limits<double>::infinity();
907 case SUBTYPE_NONE:
908 return 0.0;
909 case SUBTYPE_OTHER:
910 return std::numeric_limits<double>::infinity();
912 NOTREACHED();
913 return std::numeric_limits<double>::infinity();
916 // static
917 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
918 if (g_network_change_notifier &&
919 !NetworkChangeNotifier::test_notifications_only_) {
920 g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
924 // static
925 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
926 if (g_network_change_notifier &&
927 !NetworkChangeNotifier::test_notifications_only_) {
928 g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(
929 GetConnectionType());
933 // static
934 void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
935 ConnectionType type) {
936 if (g_network_change_notifier &&
937 !NetworkChangeNotifier::test_notifications_only_) {
938 g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
942 // static
943 void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange(
944 double max_bandwidth_mbps) {
945 if (g_network_change_notifier &&
946 !NetworkChangeNotifier::test_notifications_only_) {
947 g_network_change_notifier->NotifyObserversOfMaxBandwidthChangeImpl(
948 max_bandwidth_mbps);
952 // static
953 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
954 if (g_network_change_notifier &&
955 !NetworkChangeNotifier::test_notifications_only_) {
956 g_network_change_notifier->NotifyObserversOfDNSChangeImpl();
960 // static
961 void NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigRead() {
962 if (g_network_change_notifier &&
963 !NetworkChangeNotifier::test_notifications_only_) {
964 g_network_change_notifier->NotifyObserversOfInitialDNSConfigReadImpl();
968 // static
969 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) {
970 if (!g_network_change_notifier)
971 return;
972 g_network_change_notifier->network_state_->SetDnsConfig(config);
973 NotifyObserversOfDNSChange();
976 // static
977 void NetworkChangeNotifier::SetInitialDnsConfig(const DnsConfig& config) {
978 if (!g_network_change_notifier)
979 return;
980 #if DCHECK_IS_ON()
981 // Verify we've never received a valid DnsConfig previously.
982 DnsConfig old_config;
983 g_network_change_notifier->network_state_->GetDnsConfig(&old_config);
984 DCHECK(!old_config.IsValid());
985 #endif
986 g_network_change_notifier->network_state_->SetDnsConfig(config);
987 NotifyObserversOfInitialDNSConfigRead();
990 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
991 ip_address_observer_list_->Notify(FROM_HERE,
992 &IPAddressObserver::OnIPAddressChanged);
995 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
996 ConnectionType type) {
997 connection_type_observer_list_->Notify(
998 FROM_HERE, &ConnectionTypeObserver::OnConnectionTypeChanged, type);
1001 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
1002 ConnectionType type) {
1003 network_change_observer_list_->Notify(
1004 FROM_HERE, &NetworkChangeObserver::OnNetworkChanged, type);
1007 void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
1008 resolver_state_observer_list_->Notify(FROM_HERE, &DNSObserver::OnDNSChanged);
1011 void NetworkChangeNotifier::NotifyObserversOfInitialDNSConfigReadImpl() {
1012 resolver_state_observer_list_->Notify(FROM_HERE,
1013 &DNSObserver::OnInitialDNSConfigRead);
1016 void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeImpl(
1017 double max_bandwidth_mbps) {
1018 max_bandwidth_observer_list_->Notify(
1019 FROM_HERE, &MaxBandwidthObserver::OnMaxBandwidthChanged,
1020 max_bandwidth_mbps);
1023 NetworkChangeNotifier::DisableForTest::DisableForTest()
1024 : network_change_notifier_(g_network_change_notifier) {
1025 DCHECK(g_network_change_notifier);
1026 g_network_change_notifier = NULL;
1029 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
1030 DCHECK(!g_network_change_notifier);
1031 g_network_change_notifier = network_change_notifier_;
1034 void NetworkChangeNotifier::DNSObserver::OnInitialDNSConfigRead() {
1037 } // namespace net