blob: d90080437b32db9a50a2117e9353b07045628c7c [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/base/network_change_notifier.h"
#include <limits>
#include <string>
#include <unordered_set>
#include <utility>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/no_destructor.h"
#include "base/optional.h"
#include "base/sequence_checker.h"
#include "base/stl_util.h"
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "base/threading/thread_checker.h"
#include "base/timer/timer.h"
#include "build/build_config.h"
#include "net/base/network_change_notifier_factory.h"
#include "net/base/network_interfaces.h"
#include "net/base/url_util.h"
#include "net/dns/dns_config.h"
#include "net/dns/dns_config_service.h"
#include "net/dns/system_dns_config_change_notifier.h"
#include "net/url_request/url_request.h"
#include "url/gurl.h"
#if defined(OS_WIN)
#include "net/base/network_change_notifier_win.h"
#elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
#include "net/base/network_change_notifier_linux.h"
#elif defined(OS_APPLE)
#include "net/base/network_change_notifier_mac.h"
#elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
#include "net/base/network_change_notifier_posix.h"
#elif defined(OS_FUCHSIA)
#include "net/base/network_change_notifier_fuchsia.h"
#endif
namespace net {
namespace {
// The process-wide singleton notifier.
NetworkChangeNotifier* g_network_change_notifier = nullptr;
// Class factory singleton.
NetworkChangeNotifierFactory* g_network_change_notifier_factory = nullptr;
// Lock to protect |g_network_change_notifier| during creation time. Since
// creation of the process-wide instance can happen on any thread, this lock is
// used to guarantee only one instance is created. Once the global instance is
// created, the owner is responsible for destroying it on the same thread. All
// the other calls to the NetworkChangeNotifier do not require this lock as
// the global instance is only destroyed when the process is getting killed.
base::Lock& NetworkChangeNotifierCreationLock() {
static base::NoDestructor<base::Lock> instance;
return *instance;
}
class MockNetworkChangeNotifier : public NetworkChangeNotifier {
public:
MockNetworkChangeNotifier(
std::unique_ptr<SystemDnsConfigChangeNotifier> dns_config_notifier)
: NetworkChangeNotifier(
NetworkChangeCalculatorParams(),
dns_config_notifier.get(),
// Omit adding observers from the constructor as that would prevent
// construction when SequencedTaskRunnerHandle isn't set.
/* omit_observers_in_constructor_for_testing=*/true),
dns_config_notifier_(std::move(dns_config_notifier)) {}
~MockNetworkChangeNotifier() override { StopSystemDnsConfigNotifier(); }
ConnectionType GetCurrentConnectionType() const override {
return CONNECTION_UNKNOWN;
}
private:
std::unique_ptr<SystemDnsConfigChangeNotifier> dns_config_notifier_;
};
} // namespace
// static
bool NetworkChangeNotifier::test_notifications_only_ = false;
// static
const NetworkChangeNotifier::NetworkHandle
NetworkChangeNotifier::kInvalidNetworkHandle = -1;
NetworkChangeNotifier::NetworkChangeCalculatorParams::
NetworkChangeCalculatorParams() = default;
// Calculates NetworkChange signal from IPAddress and ConnectionType signals.
class NetworkChangeNotifier::NetworkChangeCalculator
: public ConnectionTypeObserver,
public IPAddressObserver {
public:
explicit NetworkChangeCalculator(const NetworkChangeCalculatorParams& params)
: params_(params),
have_announced_(false),
last_announced_connection_type_(CONNECTION_NONE),
pending_connection_type_(CONNECTION_NONE) {}
void Init() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(g_network_change_notifier);
AddConnectionTypeObserver(this);
AddIPAddressObserver(this);
}
~NetworkChangeCalculator() override {
DCHECK(thread_checker_.CalledOnValidThread());
RemoveConnectionTypeObserver(this);
RemoveIPAddressObserver(this);
}
// NetworkChangeNotifier::IPAddressObserver implementation.
void OnIPAddressChanged() override {
DCHECK(thread_checker_.CalledOnValidThread());
pending_connection_type_ = GetConnectionType();
base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
? params_.ip_address_offline_delay_ : params_.ip_address_online_delay_;
// Cancels any previous timer.
timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
}
// NetworkChangeNotifier::ConnectionTypeObserver implementation.
void OnConnectionTypeChanged(ConnectionType type) override {
DCHECK(thread_checker_.CalledOnValidThread());
pending_connection_type_ = type;
base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE
? params_.connection_type_offline_delay_
: params_.connection_type_online_delay_;
// Cancels any previous timer.
timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify);
}
private:
void Notify() {
DCHECK(thread_checker_.CalledOnValidThread());
// Don't bother signaling about dead connections.
if (have_announced_ &&
(last_announced_connection_type_ == CONNECTION_NONE) &&
(pending_connection_type_ == CONNECTION_NONE)) {
return;
}
have_announced_ = true;
last_announced_connection_type_ = pending_connection_type_;
// Immediately before sending out an online signal, send out an offline
// signal to perform any destructive actions before constructive actions.
if (pending_connection_type_ != CONNECTION_NONE)
NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE);
NetworkChangeNotifier::NotifyObserversOfNetworkChange(
pending_connection_type_);
}
const NetworkChangeCalculatorParams params_;
// Indicates if NotifyObserversOfNetworkChange has been called yet.
bool have_announced_;
// Last value passed to NotifyObserversOfNetworkChange.
ConnectionType last_announced_connection_type_;
// Value to pass to NotifyObserversOfNetworkChange when Notify is called.
ConnectionType pending_connection_type_;
// Used to delay notifications so duplicates can be combined.
base::OneShotTimer timer_;
base::ThreadChecker thread_checker_;
DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator);
};
class NetworkChangeNotifier::SystemDnsConfigObserver
: public SystemDnsConfigChangeNotifier::Observer {
public:
virtual ~SystemDnsConfigObserver() = default;
void OnSystemDnsConfigChanged(base::Optional<DnsConfig> config) override {
NotifyObserversOfDNSChange();
}
};
void NetworkChangeNotifier::ClearGlobalPointer() {
if (!cleared_global_pointer_) {
cleared_global_pointer_ = true;
DCHECK_EQ(this, g_network_change_notifier);
g_network_change_notifier = nullptr;
}
}
NetworkChangeNotifier::~NetworkChangeNotifier() {
network_change_calculator_.reset();
ClearGlobalPointer();
StopSystemDnsConfigNotifier();
}
// static
NetworkChangeNotifierFactory* NetworkChangeNotifier::GetFactory() {
return g_network_change_notifier_factory;
}
// static
void NetworkChangeNotifier::SetFactory(
NetworkChangeNotifierFactory* factory) {
CHECK(!g_network_change_notifier_factory);
g_network_change_notifier_factory = factory;
}
// static
std::unique_ptr<NetworkChangeNotifier> NetworkChangeNotifier::CreateIfNeeded(
NetworkChangeNotifier::ConnectionType initial_type,
NetworkChangeNotifier::ConnectionSubtype initial_subtype) {
base::AutoLock auto_lock(NetworkChangeNotifierCreationLock());
if (g_network_change_notifier)
return nullptr;
if (g_network_change_notifier_factory)
return g_network_change_notifier_factory->CreateInstance();
#if defined(OS_WIN)
std::unique_ptr<NetworkChangeNotifierWin> network_change_notifier =
std::make_unique<NetworkChangeNotifierWin>();
network_change_notifier->WatchForAddressChange();
return network_change_notifier;
#elif defined(OS_ANDROID)
// Fallback to use NetworkChangeNotifierPosix if NetworkChangeNotifierFactory
// is not set. Currently used for tests and when running network
// service in a separate process.
return std::make_unique<NetworkChangeNotifierPosix>(initial_type,
initial_subtype);
#elif defined(OS_CHROMEOS)
return std::make_unique<NetworkChangeNotifierPosix>(initial_type,
initial_subtype);
#elif defined(OS_LINUX)
return std::make_unique<NetworkChangeNotifierLinux>(
std::unordered_set<std::string>());
#elif defined(OS_APPLE)
return std::make_unique<NetworkChangeNotifierMac>();
#elif defined(OS_FUCHSIA)
return std::make_unique<NetworkChangeNotifierFuchsia>(
fuchsia::hardware::ethernet::Features());
#else
NOTIMPLEMENTED();
return NULL;
#endif
}
// static
NetworkChangeNotifier::ConnectionType
NetworkChangeNotifier::GetConnectionType() {
return g_network_change_notifier ?
g_network_change_notifier->GetCurrentConnectionType() :
CONNECTION_UNKNOWN;
}
// static
NetworkChangeNotifier::ConnectionSubtype
NetworkChangeNotifier::GetConnectionSubtype() {
return g_network_change_notifier
? g_network_change_notifier->GetCurrentConnectionSubtype()
: SUBTYPE_UNKNOWN;
}
// static
void NetworkChangeNotifier::GetMaxBandwidthAndConnectionType(
double* max_bandwidth_mbps,
ConnectionType* connection_type) {
if (!g_network_change_notifier) {
*connection_type = CONNECTION_UNKNOWN;
*max_bandwidth_mbps =
GetMaxBandwidthMbpsForConnectionSubtype(SUBTYPE_UNKNOWN);
return;
}
g_network_change_notifier->GetCurrentMaxBandwidthAndConnectionType(
max_bandwidth_mbps, connection_type);
}
// static
double NetworkChangeNotifier::GetMaxBandwidthMbpsForConnectionSubtype(
ConnectionSubtype subtype) {
switch (subtype) {
case SUBTYPE_GSM:
return 0.01;
case SUBTYPE_IDEN:
return 0.064;
case SUBTYPE_CDMA:
return 0.115;
case SUBTYPE_1XRTT:
return 0.153;
case SUBTYPE_GPRS:
return 0.237;
case SUBTYPE_EDGE:
return 0.384;
case SUBTYPE_UMTS:
return 2.0;
case SUBTYPE_EVDO_REV_0:
return 2.46;
case SUBTYPE_EVDO_REV_A:
return 3.1;
case SUBTYPE_HSPA:
return 3.6;
case SUBTYPE_EVDO_REV_B:
return 14.7;
case SUBTYPE_HSDPA:
return 14.3;
case SUBTYPE_HSUPA:
return 14.4;
case SUBTYPE_EHRPD:
return 21.0;
case SUBTYPE_HSPAP:
return 42.0;
case SUBTYPE_LTE:
return 100.0;
case SUBTYPE_LTE_ADVANCED:
return 100.0;
case SUBTYPE_BLUETOOTH_1_2:
return 1.0;
case SUBTYPE_BLUETOOTH_2_1:
return 3.0;
case SUBTYPE_BLUETOOTH_3_0:
return 24.0;
case SUBTYPE_BLUETOOTH_4_0:
return 1.0;
case SUBTYPE_ETHERNET:
return 10.0;
case SUBTYPE_FAST_ETHERNET:
return 100.0;
case SUBTYPE_GIGABIT_ETHERNET:
return 1000.0;
case SUBTYPE_10_GIGABIT_ETHERNET:
return 10000.0;
case SUBTYPE_WIFI_B:
return 11.0;
case SUBTYPE_WIFI_G:
return 54.0;
case SUBTYPE_WIFI_N:
return 600.0;
case SUBTYPE_WIFI_AC:
return 1300.0;
case SUBTYPE_WIFI_AD:
return 7000.0;
case SUBTYPE_UNKNOWN:
return std::numeric_limits<double>::infinity();
case SUBTYPE_NONE:
return 0.0;
case SUBTYPE_OTHER:
return std::numeric_limits<double>::infinity();
}
NOTREACHED();
return std::numeric_limits<double>::infinity();
}
// static
bool NetworkChangeNotifier::AreNetworkHandlesSupported() {
if (g_network_change_notifier) {
return g_network_change_notifier->AreNetworkHandlesCurrentlySupported();
}
return false;
}
// static
void NetworkChangeNotifier::GetConnectedNetworks(NetworkList* network_list) {
DCHECK(AreNetworkHandlesSupported());
if (g_network_change_notifier) {
g_network_change_notifier->GetCurrentConnectedNetworks(network_list);
} else {
network_list->clear();
}
}
// static
NetworkChangeNotifier::ConnectionType
NetworkChangeNotifier::GetNetworkConnectionType(NetworkHandle network) {
DCHECK(AreNetworkHandlesSupported());
return g_network_change_notifier
? g_network_change_notifier->GetCurrentNetworkConnectionType(
network)
: CONNECTION_UNKNOWN;
}
// static
NetworkChangeNotifier::NetworkHandle
NetworkChangeNotifier::GetDefaultNetwork() {
DCHECK(AreNetworkHandlesSupported());
return g_network_change_notifier
? g_network_change_notifier->GetCurrentDefaultNetwork()
: kInvalidNetworkHandle;
}
// static
SystemDnsConfigChangeNotifier*
NetworkChangeNotifier::GetSystemDnsConfigNotifier() {
if (g_network_change_notifier)
return g_network_change_notifier->GetCurrentSystemDnsConfigNotifier();
return nullptr;
}
// static
const char* NetworkChangeNotifier::ConnectionTypeToString(
ConnectionType type) {
static const char* const kConnectionTypeNames[] = {
"CONNECTION_UNKNOWN",
"CONNECTION_ETHERNET",
"CONNECTION_WIFI",
"CONNECTION_2G",
"CONNECTION_3G",
"CONNECTION_4G",
"CONNECTION_NONE",
"CONNECTION_BLUETOOTH"
};
static_assert(base::size(kConnectionTypeNames) ==
NetworkChangeNotifier::CONNECTION_LAST + 1,
"ConnectionType name count should match");
if (type < CONNECTION_UNKNOWN || type > CONNECTION_LAST) {
NOTREACHED();
return "CONNECTION_INVALID";
}
return kConnectionTypeNames[type];
}
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
// static
const internal::AddressTrackerLinux*
NetworkChangeNotifier::GetAddressTracker() {
return g_network_change_notifier ?
g_network_change_notifier->GetAddressTrackerInternal() : NULL;
}
#endif
// static
bool NetworkChangeNotifier::IsOffline() {
return GetConnectionType() == CONNECTION_NONE;
}
// static
bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) {
bool is_cellular = false;
switch (type) {
case CONNECTION_2G:
case CONNECTION_3G:
case CONNECTION_4G:
is_cellular = true;
break;
case CONNECTION_UNKNOWN:
case CONNECTION_ETHERNET:
case CONNECTION_WIFI:
case CONNECTION_NONE:
case CONNECTION_BLUETOOTH:
is_cellular = false;
break;
}
return is_cellular;
}
// static
NetworkChangeNotifier::ConnectionType
NetworkChangeNotifier::ConnectionTypeFromInterfaces() {
NetworkInterfaceList interfaces;
if (!GetNetworkList(&interfaces, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES))
return CONNECTION_UNKNOWN;
return ConnectionTypeFromInterfaceList(interfaces);
}
// static
NetworkChangeNotifier::ConnectionType
NetworkChangeNotifier::ConnectionTypeFromInterfaceList(
const NetworkInterfaceList& interfaces) {
bool first = true;
ConnectionType result = CONNECTION_NONE;
for (size_t i = 0; i < interfaces.size(); ++i) {
#if defined(OS_WIN)
if (interfaces[i].friendly_name == "Teredo Tunneling Pseudo-Interface")
continue;
#endif
#if defined(OS_APPLE)
// Ignore link-local addresses as they aren't globally routable.
// Mac assigns these to disconnected interfaces like tunnel interfaces
// ("utun"), airdrop interfaces ("awdl"), and ethernet ports ("en").
if (interfaces[i].address.IsLinkLocal())
continue;
#endif
// Remove VMware network interfaces as they're internal and should not be
// used to determine the network connection type.
if (base::ToLowerASCII(interfaces[i].friendly_name).find("vmnet") !=
std::string::npos) {
continue;
}
if (first) {
first = false;
result = interfaces[i].type;
} else if (result != interfaces[i].type) {
return CONNECTION_UNKNOWN;
}
}
return result;
}
// static
std::unique_ptr<NetworkChangeNotifier>
NetworkChangeNotifier::CreateMockIfNeeded() {
base::AutoLock auto_lock(NetworkChangeNotifierCreationLock());
if (g_network_change_notifier)
return nullptr;
// Use an empty noop SystemDnsConfigChangeNotifier to disable actual system
// DNS configuration notifications.
return std::make_unique<MockNetworkChangeNotifier>(
std::make_unique<SystemDnsConfigChangeNotifier>(
nullptr /* task_runner */, nullptr /* dns_config_service */));
}
NetworkChangeNotifier::IPAddressObserver::IPAddressObserver() = default;
NetworkChangeNotifier::IPAddressObserver::~IPAddressObserver() = default;
NetworkChangeNotifier::ConnectionTypeObserver::ConnectionTypeObserver() =
default;
NetworkChangeNotifier::ConnectionTypeObserver::~ConnectionTypeObserver() =
default;
NetworkChangeNotifier::DNSObserver::DNSObserver() = default;
NetworkChangeNotifier::DNSObserver::~DNSObserver() = default;
NetworkChangeNotifier::NetworkChangeObserver::NetworkChangeObserver() = default;
NetworkChangeNotifier::NetworkChangeObserver::~NetworkChangeObserver() =
default;
NetworkChangeNotifier::MaxBandwidthObserver::MaxBandwidthObserver() = default;
NetworkChangeNotifier::MaxBandwidthObserver::~MaxBandwidthObserver() = default;
NetworkChangeNotifier::NetworkObserver::NetworkObserver() = default;
NetworkChangeNotifier::NetworkObserver::~NetworkObserver() = default;
void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
if (g_network_change_notifier &&
g_network_change_notifier->can_add_observers_) {
observer->observer_list_ =
g_network_change_notifier->ip_address_observer_list_;
observer->observer_list_->AddObserver(observer);
}
}
void NetworkChangeNotifier::AddConnectionTypeObserver(
ConnectionTypeObserver* observer) {
if (g_network_change_notifier &&
g_network_change_notifier->can_add_observers_) {
observer->observer_list_ =
g_network_change_notifier->connection_type_observer_list_;
observer->observer_list_->AddObserver(observer);
}
}
void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
if (g_network_change_notifier &&
g_network_change_notifier->can_add_observers_) {
observer->observer_list_ =
g_network_change_notifier->resolver_state_observer_list_;
observer->observer_list_->AddObserver(observer);
}
}
void NetworkChangeNotifier::AddNetworkChangeObserver(
NetworkChangeObserver* observer) {
if (g_network_change_notifier &&
g_network_change_notifier->can_add_observers_) {
observer->observer_list_ =
g_network_change_notifier->network_change_observer_list_;
observer->observer_list_->AddObserver(observer);
}
}
void NetworkChangeNotifier::AddMaxBandwidthObserver(
MaxBandwidthObserver* observer) {
if (g_network_change_notifier &&
g_network_change_notifier->can_add_observers_) {
observer->observer_list_ =
g_network_change_notifier->max_bandwidth_observer_list_;
observer->observer_list_->AddObserver(observer);
}
}
void NetworkChangeNotifier::AddNetworkObserver(NetworkObserver* observer) {
DCHECK(AreNetworkHandlesSupported());
if (g_network_change_notifier &&
g_network_change_notifier->can_add_observers_) {
observer->observer_list_ =
g_network_change_notifier->network_observer_list_;
observer->observer_list_->AddObserver(observer);
}
}
void NetworkChangeNotifier::RemoveIPAddressObserver(
IPAddressObserver* observer) {
if (observer->observer_list_) {
observer->observer_list_->RemoveObserver(observer);
observer->observer_list_.reset();
}
}
void NetworkChangeNotifier::RemoveConnectionTypeObserver(
ConnectionTypeObserver* observer) {
if (observer->observer_list_) {
observer->observer_list_->RemoveObserver(observer);
observer->observer_list_.reset();
}
}
void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
if (observer->observer_list_) {
observer->observer_list_->RemoveObserver(observer);
observer->observer_list_.reset();
}
}
void NetworkChangeNotifier::RemoveNetworkChangeObserver(
NetworkChangeObserver* observer) {
if (observer->observer_list_) {
observer->observer_list_->RemoveObserver(observer);
observer->observer_list_.reset();
}
}
void NetworkChangeNotifier::RemoveMaxBandwidthObserver(
MaxBandwidthObserver* observer) {
if (observer->observer_list_) {
observer->observer_list_->RemoveObserver(observer);
observer->observer_list_.reset();
}
}
void NetworkChangeNotifier::RemoveNetworkObserver(NetworkObserver* observer) {
if (observer->observer_list_) {
observer->observer_list_->RemoveObserver(observer);
observer->observer_list_.reset();
}
}
void NetworkChangeNotifier::TriggerNonSystemDnsChange() {
NetworkChangeNotifier::NotifyObserversOfDNSChange();
}
// static
void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() {
if (g_network_change_notifier)
g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
}
// static
void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests(
ConnectionType type) {
if (g_network_change_notifier)
g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type);
}
// static
void NetworkChangeNotifier::NotifyObserversOfDNSChangeForTests() {
if (g_network_change_notifier)
g_network_change_notifier->NotifyObserversOfDNSChangeImpl();
}
// static
void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests(
ConnectionType type) {
if (g_network_change_notifier)
g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
}
// static
void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeForTests(
double max_bandwidth_mbps,
ConnectionType type) {
if (g_network_change_notifier) {
g_network_change_notifier->NotifyObserversOfMaxBandwidthChangeImpl(
max_bandwidth_mbps, type);
}
}
// static
void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only) {
DCHECK(!g_network_change_notifier);
NetworkChangeNotifier::test_notifications_only_ = test_only;
}
NetworkChangeNotifier::NetworkChangeNotifier(
const NetworkChangeCalculatorParams& params
/*= NetworkChangeCalculatorParams()*/,
SystemDnsConfigChangeNotifier* system_dns_config_notifier /*= nullptr */,
bool omit_observers_in_constructor_for_testing /*= false */)
: ip_address_observer_list_(
new base::ObserverListThreadSafe<IPAddressObserver>(
base::ObserverListPolicy::EXISTING_ONLY)),
connection_type_observer_list_(
new base::ObserverListThreadSafe<ConnectionTypeObserver>(
base::ObserverListPolicy::EXISTING_ONLY)),
resolver_state_observer_list_(
new base::ObserverListThreadSafe<DNSObserver>(
base::ObserverListPolicy::EXISTING_ONLY)),
network_change_observer_list_(
new base::ObserverListThreadSafe<NetworkChangeObserver>(
base::ObserverListPolicy::EXISTING_ONLY)),
max_bandwidth_observer_list_(
new base::ObserverListThreadSafe<MaxBandwidthObserver>(
base::ObserverListPolicy::EXISTING_ONLY)),
network_observer_list_(new base::ObserverListThreadSafe<NetworkObserver>(
base::ObserverListPolicy::EXISTING_ONLY)),
system_dns_config_notifier_(system_dns_config_notifier),
system_dns_config_observer_(std::make_unique<SystemDnsConfigObserver>()),
network_change_calculator_(new NetworkChangeCalculator(params)),
can_add_observers_(!omit_observers_in_constructor_for_testing) {
if (!system_dns_config_notifier_) {
static base::NoDestructor<SystemDnsConfigChangeNotifier> singleton{};
system_dns_config_notifier_ = singleton.get();
}
DCHECK(!g_network_change_notifier);
g_network_change_notifier = this;
network_change_calculator_->Init();
system_dns_config_notifier_->AddObserver(system_dns_config_observer_.get());
can_add_observers_ = true;
}
#if defined(OS_LINUX) || defined(OS_CHROMEOS)
const internal::AddressTrackerLinux*
NetworkChangeNotifier::GetAddressTrackerInternal() const {
return NULL;
}
#endif
NetworkChangeNotifier::ConnectionSubtype
NetworkChangeNotifier::GetCurrentConnectionSubtype() const {
return SUBTYPE_UNKNOWN;
}
void NetworkChangeNotifier::GetCurrentMaxBandwidthAndConnectionType(
double* max_bandwidth_mbps,
ConnectionType* connection_type) const {
// This default implementation conforms to the NetInfo V3 specification but
// should be overridden to provide specific bandwidth data based on the
// platform.
*connection_type = GetCurrentConnectionType();
*max_bandwidth_mbps =
*connection_type == CONNECTION_NONE
? GetMaxBandwidthMbpsForConnectionSubtype(SUBTYPE_NONE)
: GetMaxBandwidthMbpsForConnectionSubtype(SUBTYPE_UNKNOWN);
}
bool NetworkChangeNotifier::AreNetworkHandlesCurrentlySupported() const {
return false;
}
void NetworkChangeNotifier::GetCurrentConnectedNetworks(
NetworkList* network_list) const {
network_list->clear();
}
NetworkChangeNotifier::ConnectionType
NetworkChangeNotifier::GetCurrentNetworkConnectionType(
NetworkHandle network) const {
return CONNECTION_UNKNOWN;
}
NetworkChangeNotifier::NetworkHandle
NetworkChangeNotifier::GetCurrentDefaultNetwork() const {
return kInvalidNetworkHandle;
}
SystemDnsConfigChangeNotifier*
NetworkChangeNotifier::GetCurrentSystemDnsConfigNotifier() {
DCHECK(system_dns_config_notifier_);
return system_dns_config_notifier_;
}
// static
void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
if (g_network_change_notifier &&
!NetworkChangeNotifier::test_notifications_only_) {
g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl();
}
}
// static
void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
if (g_network_change_notifier &&
!NetworkChangeNotifier::test_notifications_only_) {
g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(
GetConnectionType());
}
}
// static
void NetworkChangeNotifier::NotifyObserversOfNetworkChange(
ConnectionType type) {
if (g_network_change_notifier &&
!NetworkChangeNotifier::test_notifications_only_) {
g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type);
}
}
// static
void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange(
double max_bandwidth_mbps,
ConnectionType type) {
if (g_network_change_notifier &&
!NetworkChangeNotifier::test_notifications_only_) {
g_network_change_notifier->NotifyObserversOfMaxBandwidthChangeImpl(
max_bandwidth_mbps, type);
}
}
// static
void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
if (g_network_change_notifier &&
!NetworkChangeNotifier::test_notifications_only_) {
g_network_change_notifier->NotifyObserversOfDNSChangeImpl();
}
}
// static
void NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChange(
NetworkChangeType type,
NetworkHandle network) {
if (g_network_change_notifier &&
!NetworkChangeNotifier::test_notifications_only_) {
g_network_change_notifier->NotifyObserversOfSpecificNetworkChangeImpl(
type, network);
}
}
void NetworkChangeNotifier::StopSystemDnsConfigNotifier() {
if (!system_dns_config_notifier_)
return;
system_dns_config_notifier_->RemoveObserver(
system_dns_config_observer_.get());
system_dns_config_observer_ = nullptr;
system_dns_config_notifier_ = nullptr;
}
void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() {
ip_address_observer_list_->Notify(FROM_HERE,
&IPAddressObserver::OnIPAddressChanged);
}
void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl(
ConnectionType type) {
connection_type_observer_list_->Notify(
FROM_HERE, &ConnectionTypeObserver::OnConnectionTypeChanged, type);
}
void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl(
ConnectionType type) {
network_change_observer_list_->Notify(
FROM_HERE, &NetworkChangeObserver::OnNetworkChanged, type);
}
void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() {
resolver_state_observer_list_->Notify(FROM_HERE, &DNSObserver::OnDNSChanged);
}
void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeImpl(
double max_bandwidth_mbps,
ConnectionType type) {
max_bandwidth_observer_list_->Notify(
FROM_HERE, &MaxBandwidthObserver::OnMaxBandwidthChanged,
max_bandwidth_mbps, type);
}
void NetworkChangeNotifier::NotifyObserversOfSpecificNetworkChangeImpl(
NetworkChangeType type,
NetworkHandle network) {
switch (type) {
case CONNECTED:
network_observer_list_->Notify(
FROM_HERE, &NetworkObserver::OnNetworkConnected, network);
break;
case DISCONNECTED:
network_observer_list_->Notify(
FROM_HERE, &NetworkObserver::OnNetworkDisconnected, network);
break;
case SOON_TO_DISCONNECT:
network_observer_list_->Notify(
FROM_HERE, &NetworkObserver::OnNetworkSoonToDisconnect, network);
break;
case MADE_DEFAULT:
network_observer_list_->Notify(
FROM_HERE, &NetworkObserver::OnNetworkMadeDefault, network);
break;
}
}
NetworkChangeNotifier::DisableForTest::DisableForTest()
: network_change_notifier_(g_network_change_notifier) {
DCHECK(g_network_change_notifier);
g_network_change_notifier = nullptr;
}
NetworkChangeNotifier::DisableForTest::~DisableForTest() {
DCHECK(!g_network_change_notifier);
g_network_change_notifier = network_change_notifier_;
}
} // namespace net