Chromium Code Reviews| Index: net/base/network_change_notifier_win.cc |
| diff --git a/net/base/network_change_notifier_win.cc b/net/base/network_change_notifier_win.cc |
| index 9b2b35ec76bfbc08a1ac6008dbf9f85b80a2618b..26d4e2a764dc8f48878f8d48afc215fc264e2976 100644 |
| --- a/net/base/network_change_notifier_win.cc |
| +++ b/net/base/network_change_notifier_win.cc |
| @@ -14,6 +14,7 @@ |
| #include "base/message_loop/message_loop.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/single_thread_task_runner.h" |
| +#include "base/task_runner_util.h" |
| #include "base/threading/thread.h" |
| #include "base/threading/thread_task_runner_handle.h" |
| #include "base/time/time.h" |
| @@ -28,64 +29,6 @@ namespace { |
| // Time between NotifyAddrChange retries, on failure. |
| const int kWatchForAddressChangeRetryIntervalMs = 500; |
| -} // namespace |
| - |
| -// Thread on which we can run DnsConfigService, which requires AssertIOAllowed |
| -// to open registry keys and to handle FilePathWatcher updates. |
| -class NetworkChangeNotifierWin::DnsConfigServiceThread : public base::Thread { |
| - public: |
| - DnsConfigServiceThread() : base::Thread("DnsConfigService") {} |
| - |
| - ~DnsConfigServiceThread() override { Stop(); } |
| - |
| - void Init() override { |
| - service_ = DnsConfigService::CreateSystemService(); |
| - service_->WatchConfig(base::Bind(&NetworkChangeNotifier::SetDnsConfig)); |
| - } |
| - |
| - void CleanUp() override { service_.reset(); } |
| - |
| - private: |
| - std::unique_ptr<DnsConfigService> service_; |
| - |
| - DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceThread); |
| -}; |
| - |
| -NetworkChangeNotifierWin::NetworkChangeNotifierWin() |
| - : NetworkChangeNotifier(NetworkChangeCalculatorParamsWin()), |
| - is_watching_(false), |
| - sequential_failures_(0), |
| - dns_config_service_thread_(new DnsConfigServiceThread()), |
| - last_computed_connection_type_(RecomputeCurrentConnectionType()), |
| - last_announced_offline_(last_computed_connection_type_ == |
| - CONNECTION_NONE), |
| - weak_factory_(this) { |
| - memset(&addr_overlapped_, 0, sizeof addr_overlapped_); |
| - addr_overlapped_.hEvent = WSACreateEvent(); |
| -} |
| - |
| -NetworkChangeNotifierWin::~NetworkChangeNotifierWin() { |
| - if (is_watching_) { |
| - CancelIPChangeNotify(&addr_overlapped_); |
| - addr_watcher_.StopWatching(); |
| - } |
| - WSACloseEvent(addr_overlapped_.hEvent); |
| -} |
| - |
| -// static |
| -NetworkChangeNotifier::NetworkChangeCalculatorParams |
| -NetworkChangeNotifierWin::NetworkChangeCalculatorParamsWin() { |
| - NetworkChangeCalculatorParams params; |
| - // Delay values arrived at by simple experimentation and adjusted so as to |
| - // produce a single signal when switching between network connections. |
| - params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(1500); |
| - params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(1500); |
| - params.connection_type_offline_delay_ = |
| - base::TimeDelta::FromMilliseconds(1500); |
| - params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(500); |
| - return params; |
| -} |
| - |
| // This implementation does not return the actual connection type but merely |
| // determines if the user is "online" (in which case it returns |
| // CONNECTION_UNKNOWN) or "offline" (and then it returns CONNECTION_NONE). |
| @@ -134,10 +77,8 @@ NetworkChangeNotifierWin::NetworkChangeCalculatorParamsWin() { |
| // experiments I ran... However none of them correctly returned "offline" when |
| // executing 'ipconfig /release'. |
| // |
| -NetworkChangeNotifier::ConnectionType |
| -NetworkChangeNotifierWin::RecomputeCurrentConnectionType() const { |
| - DCHECK(CalledOnValidThread()); |
| - |
| +// It is not thread safe, see crbug.com/324913. |
| +NetworkChangeNotifier::ConnectionType RecomputeCurrentConnectionType() { |
| EnsureWinsockInit(); |
| // The following code was adapted from: |
| @@ -201,8 +142,69 @@ NetworkChangeNotifierWin::RecomputeCurrentConnectionType() const { |
| << "WSALookupServiceEnd() failed with: " << result; |
| // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. |
| - return found_connection ? ConnectionTypeFromInterfaces() |
| - : NetworkChangeNotifier::CONNECTION_NONE; |
| + return found_connection |
| + ? NetworkChangeNotifier::ConnectionTypeFromInterfaces() |
| + : NetworkChangeNotifier::CONNECTION_NONE; |
| +} |
| + |
| +} // namespace |
| + |
| +// Thread on which we can run DnsConfigService, which requires AssertIOAllowed |
| +// to open registry keys and to handle FilePathWatcher updates. |
| +class NetworkChangeNotifierWin::DnsConfigServiceThread : public base::Thread { |
| + public: |
| + DnsConfigServiceThread() : base::Thread("DnsConfigService") {} |
| + |
| + ~DnsConfigServiceThread() override { Stop(); } |
| + |
| + void Init() override { |
| + service_ = DnsConfigService::CreateSystemService(); |
| + service_->WatchConfig(base::Bind(&NetworkChangeNotifier::SetDnsConfig)); |
| + } |
| + |
| + void CleanUp() override { service_.reset(); } |
| + |
| + private: |
| + std::unique_ptr<DnsConfigService> service_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DnsConfigServiceThread); |
| +}; |
| + |
| +NetworkChangeNotifierWin::NetworkChangeNotifierWin() |
| + : NetworkChangeNotifier(NetworkChangeCalculatorParamsWin()), |
| + is_watching_(false), |
| + sequential_failures_(0), |
| + dns_config_service_thread_(new DnsConfigServiceThread()), |
| + last_computed_connection_type_(RecomputeCurrentConnectionType()), |
| + last_announced_offline_(last_computed_connection_type_ == |
| + CONNECTION_NONE), |
| + calculate_connection_type_( |
| + base::BindRepeating(&RecomputeCurrentConnectionType)), |
| + weak_factory_(this) { |
| + memset(&addr_overlapped_, 0, sizeof addr_overlapped_); |
| + addr_overlapped_.hEvent = WSACreateEvent(); |
| +} |
| + |
| +NetworkChangeNotifierWin::~NetworkChangeNotifierWin() { |
| + if (is_watching_) { |
| + CancelIPChangeNotify(&addr_overlapped_); |
| + addr_watcher_.StopWatching(); |
| + } |
| + WSACloseEvent(addr_overlapped_.hEvent); |
| +} |
| + |
| +// static |
| +NetworkChangeNotifier::NetworkChangeCalculatorParams |
| +NetworkChangeNotifierWin::NetworkChangeCalculatorParamsWin() { |
| + NetworkChangeCalculatorParams params; |
| + // Delay values arrived at by simple experimentation and adjusted so as to |
| + // produce a single signal when switching between network connections. |
| + params.ip_address_offline_delay_ = base::TimeDelta::FromMilliseconds(1500); |
| + params.ip_address_online_delay_ = base::TimeDelta::FromMilliseconds(1500); |
| + params.connection_type_offline_delay_ = |
| + base::TimeDelta::FromMilliseconds(1500); |
| + params.connection_type_online_delay_ = base::TimeDelta::FromMilliseconds(500); |
| + return params; |
| } |
| NetworkChangeNotifier::ConnectionType |
| @@ -224,13 +226,17 @@ void NetworkChangeNotifierWin::OnObjectSignaled(HANDLE object) { |
| // Start watching for the next address change. |
| WatchForAddressChange(); |
| + DCHECK(dns_task_runner_); |
| - NotifyObservers(); |
| + base::PostTaskAndReplyWithResult( |
| + dns_task_runner_.get(), FROM_HERE, calculate_connection_type_, |
| + base::Bind(&NetworkChangeNotifierWin::NotifyObservers, |
| + weak_factory_.GetWeakPtr())); |
| } |
| -void NetworkChangeNotifierWin::NotifyObservers() { |
| +void NetworkChangeNotifierWin::NotifyObservers(ConnectionType connection_type) { |
| DCHECK(CalledOnValidThread()); |
| - SetCurrentConnectionType(RecomputeCurrentConnectionType()); |
| + SetCurrentConnectionType(connection_type); |
| NotifyObserversOfIPAddressChange(); |
| // Calling GetConnectionType() at this very moment is likely to give |
| @@ -241,6 +247,8 @@ void NetworkChangeNotifierWin::NotifyObservers() { |
| // If after one second we determine we are still offline, we will |
| // delay again. |
| offline_polls_ = 0; |
| + // TODO(jkarlin): I'm not sure that calling with 'this' is safe. Can it be |
| + // deleted? |
| timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this, |
| &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange); |
| } |
| @@ -274,8 +282,12 @@ void NetworkChangeNotifierWin::WatchForAddressChange() { |
| // Treat the transition from NotifyAddrChange failing to succeeding as a |
| // network change event, since network changes were not being observed in |
| // that interval. |
| - if (sequential_failures_ > 0) |
| - NotifyObservers(); |
| + if (sequential_failures_ > 0) { |
| + base::PostTaskAndReplyWithResult( |
| + dns_task_runner_.get(), FROM_HERE, calculate_connection_type_, |
| + base::Bind(&NetworkChangeNotifierWin::NotifyObservers, |
| + weak_factory_.GetWeakPtr())); |
| + } |
| if (sequential_failures_ < 2000) { |
| UMA_HISTOGRAM_COUNTS_10000("Net.NotifyAddrChangeFailures", |
| @@ -292,6 +304,9 @@ bool NetworkChangeNotifierWin::WatchForAddressChangeInternal() { |
| if (!dns_config_service_thread_->IsRunning()) { |
| dns_config_service_thread_->StartWithOptions( |
| base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); |
| + if (!dns_task_runner_) |
| + dns_task_runner_ = |
| + dns_config_service_thread_->message_loop()->task_runner(); |
| } |
| ResetEventIfSignaled(addr_overlapped_.hEvent); |
| @@ -305,7 +320,16 @@ bool NetworkChangeNotifierWin::WatchForAddressChangeInternal() { |
| } |
| void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange() { |
| - SetCurrentConnectionType(RecomputeCurrentConnectionType()); |
| + base::PostTaskAndReplyWithResult( |
| + dns_task_runner_.get(), FROM_HERE, calculate_connection_type_, |
| + base::Bind( |
| + &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChangeImpl, |
| + weak_factory_.GetWeakPtr())); |
| +} |
| + |
| +void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChangeImpl( |
| + ConnectionType connection_type) { |
| + SetCurrentConnectionType(connection_type); |
| bool current_offline = IsOffline(); |
| offline_polls_++; |
| // If we continue to appear offline, delay sending out the notification in |
| @@ -323,10 +347,10 @@ void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange() { |
| NotifyObserversOfConnectionTypeChange(); |
| double max_bandwidth_mbps = 0.0; |
| - ConnectionType connection_type = CONNECTION_NONE; |
| + ConnectionType connection_type2 = CONNECTION_NONE; |
|
pauljensen
2017/05/22 18:01:51
can we give this variable a more descriptive name?
jkarlin
2017/05/23 11:44:38
Done.
|
| GetCurrentMaxBandwidthAndConnectionType(&max_bandwidth_mbps, |
| - &connection_type); |
| - NotifyObserversOfMaxBandwidthChange(max_bandwidth_mbps, connection_type); |
| + &connection_type2); |
| + NotifyObserversOfMaxBandwidthChange(max_bandwidth_mbps, connection_type2); |
| } |
| } // namespace net |