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: 39 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: 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. 68 void Init() { 69 NetworkChangeNotifier::AddConnectionTypeObserver(this); 70 NetworkChangeNotifier::AddIPAddressObserver(this); 71 NetworkChangeNotifier::AddDNSObserver(this); 72 NetworkChangeNotifier::AddNetworkChangeObserver(this); 73 } 74 75 virtual ~HistogramWatcher() {} 76 77 // NetworkChangeNotifier::IPAddressObserver implementation. 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. 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. 231 virtual void OnDNSChanged() OVERRIDE { 232 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange", 233 SinceLast(&last_dns_change_)); 234 } 235 236 // NetworkChangeNotifier::NetworkChangeObserver implementation. 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. 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: 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: 346 NetworkState() {} 347 ~NetworkState() {} 348 349 void GetDnsConfig(DnsConfig* config) const { 350 base::AutoLock lock(lock_); 351 *config = dns_config_; 352 } 353 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:: 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: 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 379 void Init() { 380 AddConnectionTypeObserver(this); 381 AddIPAddressObserver(this); 382 } 383 384 virtual ~NetworkChangeCalculator() { 385 RemoveConnectionTypeObserver(this); 386 RemoveIPAddressObserver(this); 387 } 388 389 // NetworkChangeNotifier::IPAddressObserver implementation. 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. 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: 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 437 NetworkChangeNotifier::~NetworkChangeNotifier() { 438 DCHECK_EQ(this, g_network_change_notifier); 439 g_network_change_notifier = NULL; 440 } 441 442 // static 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 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 480 NetworkChangeNotifier::GetConnectionType() { 481 return g_network_change_notifier ? 482 g_network_change_notifier->GetCurrentConnectionType() : 483 CONNECTION_UNKNOWN; 484 } 485 486 // static 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 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 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 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* 537 NetworkChangeNotifier::GetAddressTracker() { 538 return g_network_change_notifier ? 539 g_network_change_notifier->GetAddressTrackerInternal() : NULL; 540 } 541 #endif 542 543 // static 544 bool NetworkChangeNotifier::IsOffline() { 545 return GetConnectionType() == CONNECTION_NONE; 546 } 547 548 // static 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 568 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() { 569 return new MockNetworkChangeNotifier(); 570 } 571 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 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 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 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 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 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 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 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 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* 656 NetworkChangeNotifier::GetAddressTrackerInternal() const { 657 return NULL; 658 } 659 #endif 660 661 // static 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 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 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 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 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 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 708 NetworkChangeNotifier::DisableForTest::~DisableForTest() { 709 DCHECK(!g_network_change_notifier); 710 g_network_change_notifier = network_change_notifier_; 711 } 712 713 } // namespace net 714