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