Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(593)

Side by Side Diff: net/base/network_change_notifier_win.cc

Issue 2893943002: [NetworkChangeNotifier] Run Windows connection type computation on other thread (Closed)
Patch Set: Nits Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/base/network_change_notifier_win.h" 5 #include "net/base/network_change_notifier_win.h"
6 6
7 #include <iphlpapi.h> 7 #include <iphlpapi.h>
8 #include <winsock2.h> 8 #include <winsock2.h>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/location.h" 11 #include "base/location.h"
12 #include "base/logging.h" 12 #include "base/logging.h"
13 #include "base/macros.h" 13 #include "base/macros.h"
14 #include "base/message_loop/message_loop.h" 14 #include "base/message_loop/message_loop.h"
15 #include "base/metrics/histogram_macros.h" 15 #include "base/metrics/histogram_macros.h"
16 #include "base/single_thread_task_runner.h" 16 #include "base/single_thread_task_runner.h"
17 #include "base/task_runner_util.h"
17 #include "base/threading/thread.h" 18 #include "base/threading/thread.h"
18 #include "base/threading/thread_task_runner_handle.h" 19 #include "base/threading/thread_task_runner_handle.h"
19 #include "base/time/time.h" 20 #include "base/time/time.h"
20 #include "net/base/winsock_init.h" 21 #include "net/base/winsock_init.h"
21 #include "net/base/winsock_util.h" 22 #include "net/base/winsock_util.h"
22 #include "net/dns/dns_config_service.h" 23 #include "net/dns/dns_config_service.h"
23 24
24 namespace net { 25 namespace net {
25 26
26 namespace { 27 namespace {
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
129 // * Approach (2) took an average of 3.25 milliseconds to enumerate the 130 // * Approach (2) took an average of 3.25 milliseconds to enumerate the
130 // adapters. 131 // adapters.
131 // * Approach (3) took an average of 0.8 ms to enumerate the providers. 132 // * Approach (3) took an average of 0.8 ms to enumerate the providers.
132 // 133 //
133 // In terms of correctness, all three approaches were comparable for the simple 134 // In terms of correctness, all three approaches were comparable for the simple
134 // experiments I ran... However none of them correctly returned "offline" when 135 // experiments I ran... However none of them correctly returned "offline" when
135 // executing 'ipconfig /release'. 136 // executing 'ipconfig /release'.
136 // 137 //
137 NetworkChangeNotifier::ConnectionType 138 NetworkChangeNotifier::ConnectionType
138 NetworkChangeNotifierWin::RecomputeCurrentConnectionType() const { 139 NetworkChangeNotifierWin::RecomputeCurrentConnectionType() const {
139 DCHECK(CalledOnValidThread());
140
141 EnsureWinsockInit(); 140 EnsureWinsockInit();
142 141
143 // The following code was adapted from: 142 // The following code was adapted from:
144 // http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/net/notifier/ base/win/async_network_alive_win32.cc?view=markup&pathrev=47343 143 // http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/net/notifier/ base/win/async_network_alive_win32.cc?view=markup&pathrev=47343
145 // The main difference is we only call WSALookupServiceNext once, whereas 144 // The main difference is we only call WSALookupServiceNext once, whereas
146 // the earlier code would traverse the entire list and pass LUP_FLUSHPREVIOUS 145 // the earlier code would traverse the entire list and pass LUP_FLUSHPREVIOUS
147 // to skip past the large results. 146 // to skip past the large results.
148 147
149 HANDLE ws_handle; 148 HANDLE ws_handle;
150 WSAQUERYSET query_set = {0}; 149 WSAQUERYSET query_set = {0};
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
198 197
199 result = WSALookupServiceEnd(ws_handle); 198 result = WSALookupServiceEnd(ws_handle);
200 LOG_IF(ERROR, result != 0) 199 LOG_IF(ERROR, result != 0)
201 << "WSALookupServiceEnd() failed with: " << result; 200 << "WSALookupServiceEnd() failed with: " << result;
202 201
203 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN. 202 // TODO(droger): Return something more detailed than CONNECTION_UNKNOWN.
204 return found_connection ? ConnectionTypeFromInterfaces() 203 return found_connection ? ConnectionTypeFromInterfaces()
205 : NetworkChangeNotifier::CONNECTION_NONE; 204 : NetworkChangeNotifier::CONNECTION_NONE;
206 } 205 }
207 206
207 void NetworkChangeNotifierWin::RecomputeCurrentConnectionTypeOnDnsThread(
208 base::Callback<void(ConnectionType)> reply_callback) const {
209 // Unretained is safe in this call because this object owns the thread and the
210 // thread is stopped in this object's destructor.
211 base::PostTaskAndReplyWithResult(
212 dns_config_service_thread_->message_loop()->task_runner().get(),
213 FROM_HERE,
214 base::Bind(&NetworkChangeNotifierWin::RecomputeCurrentConnectionType,
215 base::Unretained(this)),
216 reply_callback);
217 }
218
208 NetworkChangeNotifier::ConnectionType 219 NetworkChangeNotifier::ConnectionType
209 NetworkChangeNotifierWin::GetCurrentConnectionType() const { 220 NetworkChangeNotifierWin::GetCurrentConnectionType() const {
210 base::AutoLock auto_lock(last_computed_connection_type_lock_); 221 base::AutoLock auto_lock(last_computed_connection_type_lock_);
211 return last_computed_connection_type_; 222 return last_computed_connection_type_;
212 } 223 }
213 224
214 void NetworkChangeNotifierWin::SetCurrentConnectionType( 225 void NetworkChangeNotifierWin::SetCurrentConnectionType(
215 ConnectionType connection_type) { 226 ConnectionType connection_type) {
216 base::AutoLock auto_lock(last_computed_connection_type_lock_); 227 base::AutoLock auto_lock(last_computed_connection_type_lock_);
217 last_computed_connection_type_ = connection_type; 228 last_computed_connection_type_ = connection_type;
218 } 229 }
219 230
220 void NetworkChangeNotifierWin::OnObjectSignaled(HANDLE object) { 231 void NetworkChangeNotifierWin::OnObjectSignaled(HANDLE object) {
221 DCHECK(CalledOnValidThread()); 232 DCHECK(CalledOnValidThread());
222 DCHECK(is_watching_); 233 DCHECK(is_watching_);
223 is_watching_ = false; 234 is_watching_ = false;
224 235
225 // Start watching for the next address change. 236 // Start watching for the next address change.
226 WatchForAddressChange(); 237 WatchForAddressChange();
227 238
228 NotifyObservers(); 239 RecomputeCurrentConnectionTypeOnDnsThread(base::Bind(
240 &NetworkChangeNotifierWin::NotifyObservers, weak_factory_.GetWeakPtr()));
229 } 241 }
230 242
231 void NetworkChangeNotifierWin::NotifyObservers() { 243 void NetworkChangeNotifierWin::NotifyObservers(ConnectionType connection_type) {
232 DCHECK(CalledOnValidThread()); 244 DCHECK(CalledOnValidThread());
233 SetCurrentConnectionType(RecomputeCurrentConnectionType()); 245 SetCurrentConnectionType(connection_type);
234 NotifyObserversOfIPAddressChange(); 246 NotifyObserversOfIPAddressChange();
235 247
236 // Calling GetConnectionType() at this very moment is likely to give 248 // Calling GetConnectionType() at this very moment is likely to give
237 // the wrong result, so we delay that until a little bit later. 249 // the wrong result, so we delay that until a little bit later.
238 // 250 //
239 // The one second delay chosen here was determined experimentally 251 // The one second delay chosen here was determined experimentally
240 // by adamk on Windows 7. 252 // by adamk on Windows 7.
241 // If after one second we determine we are still offline, we will 253 // If after one second we determine we are still offline, we will
242 // delay again. 254 // delay again.
243 offline_polls_ = 0; 255 offline_polls_ = 0;
(...skipping 23 matching lines...) Expand all
267 FROM_HERE, base::Bind(&NetworkChangeNotifierWin::WatchForAddressChange, 279 FROM_HERE, base::Bind(&NetworkChangeNotifierWin::WatchForAddressChange,
268 weak_factory_.GetWeakPtr()), 280 weak_factory_.GetWeakPtr()),
269 base::TimeDelta::FromMilliseconds( 281 base::TimeDelta::FromMilliseconds(
270 kWatchForAddressChangeRetryIntervalMs)); 282 kWatchForAddressChangeRetryIntervalMs));
271 return; 283 return;
272 } 284 }
273 285
274 // Treat the transition from NotifyAddrChange failing to succeeding as a 286 // Treat the transition from NotifyAddrChange failing to succeeding as a
275 // network change event, since network changes were not being observed in 287 // network change event, since network changes were not being observed in
276 // that interval. 288 // that interval.
277 if (sequential_failures_ > 0) 289 if (sequential_failures_ > 0) {
278 NotifyObservers(); 290 RecomputeCurrentConnectionTypeOnDnsThread(
291 base::Bind(&NetworkChangeNotifierWin::NotifyObservers,
292 weak_factory_.GetWeakPtr()));
293 }
279 294
280 if (sequential_failures_ < 2000) { 295 if (sequential_failures_ < 2000) {
281 UMA_HISTOGRAM_COUNTS_10000("Net.NotifyAddrChangeFailures", 296 UMA_HISTOGRAM_COUNTS_10000("Net.NotifyAddrChangeFailures",
282 sequential_failures_); 297 sequential_failures_);
283 } 298 }
284 299
285 is_watching_ = true; 300 is_watching_ = true;
286 sequential_failures_ = 0; 301 sequential_failures_ = 0;
287 } 302 }
288 303
289 bool NetworkChangeNotifierWin::WatchForAddressChangeInternal() { 304 bool NetworkChangeNotifierWin::WatchForAddressChangeInternal() {
290 DCHECK(CalledOnValidThread()); 305 DCHECK(CalledOnValidThread());
291 306
292 if (!dns_config_service_thread_->IsRunning()) { 307 if (!dns_config_service_thread_->IsRunning()) {
293 dns_config_service_thread_->StartWithOptions( 308 dns_config_service_thread_->StartWithOptions(
294 base::Thread::Options(base::MessageLoop::TYPE_IO, 0)); 309 base::Thread::Options(base::MessageLoop::TYPE_IO, 0));
295 } 310 }
296 311
297 ResetEventIfSignaled(addr_overlapped_.hEvent); 312 ResetEventIfSignaled(addr_overlapped_.hEvent);
298 HANDLE handle = NULL; 313 HANDLE handle = NULL;
299 DWORD ret = NotifyAddrChange(&handle, &addr_overlapped_); 314 DWORD ret = NotifyAddrChange(&handle, &addr_overlapped_);
300 if (ret != ERROR_IO_PENDING) 315 if (ret != ERROR_IO_PENDING)
301 return false; 316 return false;
302 317
303 addr_watcher_.StartWatchingOnce(addr_overlapped_.hEvent, this); 318 addr_watcher_.StartWatchingOnce(addr_overlapped_.hEvent, this);
304 return true; 319 return true;
305 } 320 }
306 321
307 void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange() { 322 void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange() {
308 SetCurrentConnectionType(RecomputeCurrentConnectionType()); 323 RecomputeCurrentConnectionTypeOnDnsThread(base::Bind(
324 &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChangeImpl,
325 weak_factory_.GetWeakPtr()));
326 }
327
328 void NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChangeImpl(
329 ConnectionType connection_type) {
330 SetCurrentConnectionType(connection_type);
309 bool current_offline = IsOffline(); 331 bool current_offline = IsOffline();
310 offline_polls_++; 332 offline_polls_++;
311 // If we continue to appear offline, delay sending out the notification in 333 // If we continue to appear offline, delay sending out the notification in
312 // case we appear to go online within 20 seconds. UMA histogram data shows 334 // case we appear to go online within 20 seconds. UMA histogram data shows
313 // we may not detect the transition to online state after 1 second but within 335 // we may not detect the transition to online state after 1 second but within
314 // 20 seconds we generally do. 336 // 20 seconds we generally do.
315 if (last_announced_offline_ && current_offline && offline_polls_ <= 20) { 337 if (last_announced_offline_ && current_offline && offline_polls_ <= 20) {
316 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this, 338 timer_.Start(FROM_HERE, base::TimeDelta::FromSeconds(1), this,
317 &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange); 339 &NetworkChangeNotifierWin::NotifyParentOfConnectionTypeChange);
318 return; 340 return;
319 } 341 }
320 if (last_announced_offline_) 342 if (last_announced_offline_)
321 UMA_HISTOGRAM_CUSTOM_COUNTS("NCN.OfflinePolls", offline_polls_, 1, 50, 50); 343 UMA_HISTOGRAM_CUSTOM_COUNTS("NCN.OfflinePolls", offline_polls_, 1, 50, 50);
322 last_announced_offline_ = current_offline; 344 last_announced_offline_ = current_offline;
323 345
324 NotifyObserversOfConnectionTypeChange(); 346 NotifyObserversOfConnectionTypeChange();
325 double max_bandwidth_mbps = 0.0; 347 double max_bandwidth_mbps = 0.0;
326 ConnectionType connection_type = CONNECTION_NONE; 348 ConnectionType max_connection_type = CONNECTION_NONE;
327 GetCurrentMaxBandwidthAndConnectionType(&max_bandwidth_mbps, 349 GetCurrentMaxBandwidthAndConnectionType(&max_bandwidth_mbps,
328 &connection_type); 350 &max_connection_type);
329 NotifyObserversOfMaxBandwidthChange(max_bandwidth_mbps, connection_type); 351 NotifyObserversOfMaxBandwidthChange(max_bandwidth_mbps, max_connection_type);
330 } 352 }
331 353
332 } // namespace net 354 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698