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