OLD | NEW |
| (Empty) |
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 <limits> | |
8 | |
9 #include "base/metrics/histogram.h" | |
10 #include "base/synchronization/lock.h" | |
11 #include "base/threading/thread_checker.h" | |
12 #include "build/build_config.h" | |
13 #include "net/base/net_util.h" | |
14 #include "net/base/network_change_notifier_factory.h" | |
15 #include "net/dns/dns_config_service.h" | |
16 #include "net/url_request/url_request.h" | |
17 #include "url/gurl.h" | |
18 | |
19 #if defined(OS_ANDROID) | |
20 #include "base/metrics/sparse_histogram.h" | |
21 #include "base/strings/string_number_conversions.h" | |
22 #include "net/android/network_library.h" | |
23 #endif | |
24 | |
25 #if defined(OS_WIN) | |
26 #include "net/base/network_change_notifier_win.h" | |
27 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS) | |
28 #include "net/base/network_change_notifier_linux.h" | |
29 #elif defined(OS_MACOSX) | |
30 #include "net/base/network_change_notifier_mac.h" | |
31 #endif | |
32 | |
33 namespace net { | |
34 | |
35 namespace { | |
36 | |
37 // The actual singleton notifier. The class contract forbids usage of the API | |
38 // in ways that would require us to place locks around access to this object. | |
39 // (The prohibition on global non-POD objects makes it tricky to do such a thing | |
40 // anyway.) | |
41 NetworkChangeNotifier* g_network_change_notifier = NULL; | |
42 | |
43 // Class factory singleton. | |
44 NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL; | |
45 | |
46 class MockNetworkChangeNotifier : public NetworkChangeNotifier { | |
47 public: | |
48 ConnectionType GetCurrentConnectionType() const override { | |
49 return CONNECTION_UNKNOWN; | |
50 } | |
51 }; | |
52 | |
53 } // namespace | |
54 | |
55 // The main observer class that records UMAs for network events. | |
56 class HistogramWatcher | |
57 : public NetworkChangeNotifier::ConnectionTypeObserver, | |
58 public NetworkChangeNotifier::IPAddressObserver, | |
59 public NetworkChangeNotifier::DNSObserver, | |
60 public NetworkChangeNotifier::NetworkChangeObserver { | |
61 public: | |
62 HistogramWatcher() | |
63 : last_ip_address_change_(base::TimeTicks::Now()), | |
64 last_connection_change_(base::TimeTicks::Now()), | |
65 last_dns_change_(base::TimeTicks::Now()), | |
66 last_network_change_(base::TimeTicks::Now()), | |
67 last_connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN), | |
68 offline_packets_received_(0), | |
69 bytes_read_since_last_connection_change_(0), | |
70 peak_kbps_since_last_connection_change_(0) {} | |
71 | |
72 // Registers our three Observer implementations. This is called from the | |
73 // network thread so that our Observer implementations are also called | |
74 // from the network thread. This avoids multi-threaded race conditions | |
75 // because the only other interface, |NotifyDataReceived| is also | |
76 // only called from the network thread. | |
77 void Init() { | |
78 DCHECK(thread_checker_.CalledOnValidThread()); | |
79 DCHECK(g_network_change_notifier); | |
80 NetworkChangeNotifier::AddConnectionTypeObserver(this); | |
81 NetworkChangeNotifier::AddIPAddressObserver(this); | |
82 NetworkChangeNotifier::AddDNSObserver(this); | |
83 NetworkChangeNotifier::AddNetworkChangeObserver(this); | |
84 } | |
85 | |
86 ~HistogramWatcher() override { | |
87 DCHECK(thread_checker_.CalledOnValidThread()); | |
88 DCHECK(g_network_change_notifier); | |
89 NetworkChangeNotifier::RemoveConnectionTypeObserver(this); | |
90 NetworkChangeNotifier::RemoveIPAddressObserver(this); | |
91 NetworkChangeNotifier::RemoveDNSObserver(this); | |
92 NetworkChangeNotifier::RemoveNetworkChangeObserver(this); | |
93 } | |
94 | |
95 // NetworkChangeNotifier::IPAddressObserver implementation. | |
96 void OnIPAddressChanged() override { | |
97 DCHECK(thread_checker_.CalledOnValidThread()); | |
98 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.IPAddressChange", | |
99 SinceLast(&last_ip_address_change_)); | |
100 UMA_HISTOGRAM_MEDIUM_TIMES( | |
101 "NCN.ConnectionTypeChangeToIPAddressChange", | |
102 last_ip_address_change_ - last_connection_change_); | |
103 } | |
104 | |
105 // NetworkChangeNotifier::ConnectionTypeObserver implementation. | |
106 void OnConnectionTypeChanged( | |
107 NetworkChangeNotifier::ConnectionType type) override { | |
108 DCHECK(thread_checker_.CalledOnValidThread()); | |
109 base::TimeTicks now = base::TimeTicks::Now(); | |
110 int32 kilobytes_read = bytes_read_since_last_connection_change_ / 1000; | |
111 base::TimeDelta state_duration = SinceLast(&last_connection_change_); | |
112 if (bytes_read_since_last_connection_change_) { | |
113 switch (last_connection_type_) { | |
114 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | |
115 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnUnknown", | |
116 first_byte_after_connection_change_); | |
117 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnUnknown", | |
118 fastest_RTT_since_last_connection_change_); | |
119 break; | |
120 case NetworkChangeNotifier::CONNECTION_ETHERNET: | |
121 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnEthernet", | |
122 first_byte_after_connection_change_); | |
123 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnEthernet", | |
124 fastest_RTT_since_last_connection_change_); | |
125 break; | |
126 case NetworkChangeNotifier::CONNECTION_WIFI: | |
127 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnWifi", | |
128 first_byte_after_connection_change_); | |
129 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnWifi", | |
130 fastest_RTT_since_last_connection_change_); | |
131 break; | |
132 case NetworkChangeNotifier::CONNECTION_2G: | |
133 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn2G", | |
134 first_byte_after_connection_change_); | |
135 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn2G", | |
136 fastest_RTT_since_last_connection_change_); | |
137 break; | |
138 case NetworkChangeNotifier::CONNECTION_3G: | |
139 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn3G", | |
140 first_byte_after_connection_change_); | |
141 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn3G", | |
142 fastest_RTT_since_last_connection_change_); | |
143 break; | |
144 case NetworkChangeNotifier::CONNECTION_4G: | |
145 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOn4G", | |
146 first_byte_after_connection_change_); | |
147 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOn4G", | |
148 fastest_RTT_since_last_connection_change_); | |
149 break; | |
150 case NetworkChangeNotifier::CONNECTION_NONE: | |
151 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnNone", | |
152 first_byte_after_connection_change_); | |
153 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnNone", | |
154 fastest_RTT_since_last_connection_change_); | |
155 break; | |
156 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | |
157 UMA_HISTOGRAM_TIMES("NCN.CM.FirstReadOnBluetooth", | |
158 first_byte_after_connection_change_); | |
159 UMA_HISTOGRAM_TIMES("NCN.CM.FastestRTTOnBluetooth", | |
160 fastest_RTT_since_last_connection_change_); | |
161 } | |
162 } | |
163 if (peak_kbps_since_last_connection_change_) { | |
164 switch (last_connection_type_) { | |
165 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | |
166 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnUnknown", | |
167 peak_kbps_since_last_connection_change_); | |
168 break; | |
169 case NetworkChangeNotifier::CONNECTION_ETHERNET: | |
170 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnEthernet", | |
171 peak_kbps_since_last_connection_change_); | |
172 break; | |
173 case NetworkChangeNotifier::CONNECTION_WIFI: | |
174 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnWifi", | |
175 peak_kbps_since_last_connection_change_); | |
176 break; | |
177 case NetworkChangeNotifier::CONNECTION_2G: | |
178 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn2G", | |
179 peak_kbps_since_last_connection_change_); | |
180 break; | |
181 case NetworkChangeNotifier::CONNECTION_3G: | |
182 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn3G", | |
183 peak_kbps_since_last_connection_change_); | |
184 break; | |
185 case NetworkChangeNotifier::CONNECTION_4G: | |
186 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOn4G", | |
187 peak_kbps_since_last_connection_change_); | |
188 break; | |
189 case NetworkChangeNotifier::CONNECTION_NONE: | |
190 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnNone", | |
191 peak_kbps_since_last_connection_change_); | |
192 break; | |
193 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | |
194 UMA_HISTOGRAM_COUNTS("NCN.CM.PeakKbpsOnBluetooth", | |
195 peak_kbps_since_last_connection_change_); | |
196 break; | |
197 } | |
198 } | |
199 switch (last_connection_type_) { | |
200 case NetworkChangeNotifier::CONNECTION_UNKNOWN: | |
201 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnUnknown", state_duration); | |
202 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnUnknown", kilobytes_read); | |
203 break; | |
204 case NetworkChangeNotifier::CONNECTION_ETHERNET: | |
205 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnEthernet", state_duration); | |
206 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnEthernet", kilobytes_read); | |
207 break; | |
208 case NetworkChangeNotifier::CONNECTION_WIFI: | |
209 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnWifi", state_duration); | |
210 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnWifi", kilobytes_read); | |
211 break; | |
212 case NetworkChangeNotifier::CONNECTION_2G: | |
213 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn2G", state_duration); | |
214 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn2G", kilobytes_read); | |
215 break; | |
216 case NetworkChangeNotifier::CONNECTION_3G: | |
217 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn3G", state_duration); | |
218 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn3G", kilobytes_read); | |
219 break; | |
220 case NetworkChangeNotifier::CONNECTION_4G: | |
221 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOn4G", state_duration); | |
222 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOn4G", kilobytes_read); | |
223 break; | |
224 case NetworkChangeNotifier::CONNECTION_NONE: | |
225 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnNone", state_duration); | |
226 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnNone", kilobytes_read); | |
227 break; | |
228 case NetworkChangeNotifier::CONNECTION_BLUETOOTH: | |
229 UMA_HISTOGRAM_LONG_TIMES("NCN.CM.TimeOnBluetooth", state_duration); | |
230 UMA_HISTOGRAM_COUNTS("NCN.CM.KBTransferedOnBluetooth", kilobytes_read); | |
231 break; | |
232 } | |
233 | |
234 if (type != NetworkChangeNotifier::CONNECTION_NONE) { | |
235 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange", state_duration); | |
236 | |
237 if (offline_packets_received_) { | |
238 if ((now - last_offline_packet_received_) < | |
239 base::TimeDelta::FromSeconds(5)) { | |
240 // We can compare this sum with the sum of NCN.OfflineDataRecv. | |
241 UMA_HISTOGRAM_COUNTS_10000( | |
242 "NCN.OfflineDataRecvAny5sBeforeOnline", | |
243 offline_packets_received_); | |
244 } | |
245 | |
246 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline", | |
247 now - last_offline_packet_received_); | |
248 } | |
249 } else { | |
250 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange", state_duration); | |
251 } | |
252 | |
253 NetworkChangeNotifier::LogOperatorCodeHistogram(type); | |
254 | |
255 UMA_HISTOGRAM_MEDIUM_TIMES( | |
256 "NCN.IPAddressChangeToConnectionTypeChange", | |
257 now - last_ip_address_change_); | |
258 | |
259 offline_packets_received_ = 0; | |
260 bytes_read_since_last_connection_change_ = 0; | |
261 peak_kbps_since_last_connection_change_ = 0; | |
262 last_connection_type_ = type; | |
263 polling_interval_ = base::TimeDelta::FromSeconds(1); | |
264 } | |
265 | |
266 // NetworkChangeNotifier::DNSObserver implementation. | |
267 void OnDNSChanged() override { | |
268 DCHECK(thread_checker_.CalledOnValidThread()); | |
269 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange", | |
270 SinceLast(&last_dns_change_)); | |
271 } | |
272 | |
273 // NetworkChangeNotifier::NetworkChangeObserver implementation. | |
274 void OnNetworkChanged(NetworkChangeNotifier::ConnectionType type) override { | |
275 DCHECK(thread_checker_.CalledOnValidThread()); | |
276 if (type != NetworkChangeNotifier::CONNECTION_NONE) { | |
277 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOnlineChange", | |
278 SinceLast(&last_network_change_)); | |
279 } else { | |
280 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.NetworkOfflineChange", | |
281 SinceLast(&last_network_change_)); | |
282 } | |
283 } | |
284 | |
285 // Record histogram data whenever we receive a packet. Should only be called | |
286 // from the network thread. | |
287 void NotifyDataReceived(const URLRequest& request, int bytes_read) { | |
288 DCHECK(thread_checker_.CalledOnValidThread()); | |
289 if (IsLocalhost(request.url().host()) || | |
290 !request.url().SchemeIsHTTPOrHTTPS()) { | |
291 return; | |
292 } | |
293 | |
294 base::TimeTicks now = base::TimeTicks::Now(); | |
295 base::TimeDelta request_duration = now - request.creation_time(); | |
296 if (bytes_read_since_last_connection_change_ == 0) { | |
297 first_byte_after_connection_change_ = now - last_connection_change_; | |
298 fastest_RTT_since_last_connection_change_ = request_duration; | |
299 } | |
300 bytes_read_since_last_connection_change_ += bytes_read; | |
301 if (request_duration < fastest_RTT_since_last_connection_change_) | |
302 fastest_RTT_since_last_connection_change_ = request_duration; | |
303 // Ignore tiny transfers which will not produce accurate rates. | |
304 // Ignore zero duration transfers which might cause divide by zero. | |
305 if (bytes_read > 10000 && | |
306 request_duration > base::TimeDelta::FromMilliseconds(1) && | |
307 request.creation_time() > last_connection_change_) { | |
308 int32 kbps = static_cast<int32>( | |
309 bytes_read * 8 / request_duration.InMilliseconds()); | |
310 if (kbps > peak_kbps_since_last_connection_change_) | |
311 peak_kbps_since_last_connection_change_ = kbps; | |
312 } | |
313 | |
314 if (last_connection_type_ != NetworkChangeNotifier::CONNECTION_NONE) | |
315 return; | |
316 | |
317 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv", | |
318 now - last_connection_change_); | |
319 offline_packets_received_++; | |
320 last_offline_packet_received_ = now; | |
321 | |
322 if ((now - last_polled_connection_) > polling_interval_) { | |
323 polling_interval_ *= 2; | |
324 last_polled_connection_ = now; | |
325 last_polled_connection_type_ = | |
326 NetworkChangeNotifier::GetConnectionType(); | |
327 } | |
328 if (last_polled_connection_type_ == | |
329 NetworkChangeNotifier::CONNECTION_NONE) { | |
330 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv", | |
331 now - last_connection_change_); | |
332 } | |
333 } | |
334 | |
335 private: | |
336 static base::TimeDelta SinceLast(base::TimeTicks *last_time) { | |
337 base::TimeTicks current_time = base::TimeTicks::Now(); | |
338 base::TimeDelta delta = current_time - *last_time; | |
339 *last_time = current_time; | |
340 return delta; | |
341 } | |
342 | |
343 base::TimeTicks last_ip_address_change_; | |
344 base::TimeTicks last_connection_change_; | |
345 base::TimeTicks last_dns_change_; | |
346 base::TimeTicks last_network_change_; | |
347 base::TimeTicks last_offline_packet_received_; | |
348 base::TimeTicks last_polled_connection_; | |
349 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our | |
350 // first transition to offline and on subsequent transitions. Once offline, | |
351 // |polling_interval_| doubles as offline data is received and we poll | |
352 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection | |
353 // state. | |
354 base::TimeDelta polling_interval_; | |
355 // |last_connection_type_| is the last value passed to | |
356 // |OnConnectionTypeChanged|. | |
357 NetworkChangeNotifier::ConnectionType last_connection_type_; | |
358 // |last_polled_connection_type_| is last result from calling | |
359 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|. | |
360 NetworkChangeNotifier::ConnectionType last_polled_connection_type_; | |
361 // Count of how many times NotifyDataReceived() has been called while the | |
362 // NetworkChangeNotifier thought network connection was offline. | |
363 int32 offline_packets_received_; | |
364 // Number of bytes of network data received since last connectivity change. | |
365 int32 bytes_read_since_last_connection_change_; | |
366 // Fastest round-trip-time (RTT) since last connectivity change. RTT measured | |
367 // from URLRequest creation until first byte received. | |
368 base::TimeDelta fastest_RTT_since_last_connection_change_; | |
369 // Time between connectivity change and first network data byte received. | |
370 base::TimeDelta first_byte_after_connection_change_; | |
371 // Rough measurement of peak KB/s witnessed since last connectivity change. | |
372 // The accuracy is decreased by ignoring these factors: | |
373 // 1) Multiple URLRequests can occur concurrently. | |
374 // 2) NotifyDataReceived() may be called repeatedly for one URLRequest. | |
375 // 3) The transfer time includes at least one RTT while no bytes are read. | |
376 // Erring on the conservative side is hopefully offset by taking the maximum. | |
377 int32 peak_kbps_since_last_connection_change_; | |
378 | |
379 base::ThreadChecker thread_checker_; | |
380 | |
381 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher); | |
382 }; | |
383 | |
384 // NetworkState is thread safe. | |
385 class NetworkChangeNotifier::NetworkState { | |
386 public: | |
387 NetworkState() {} | |
388 ~NetworkState() {} | |
389 | |
390 void GetDnsConfig(DnsConfig* config) const { | |
391 base::AutoLock lock(lock_); | |
392 *config = dns_config_; | |
393 } | |
394 | |
395 void SetDnsConfig(const DnsConfig& dns_config) { | |
396 base::AutoLock lock(lock_); | |
397 dns_config_ = dns_config; | |
398 } | |
399 | |
400 private: | |
401 mutable base::Lock lock_; | |
402 DnsConfig dns_config_; | |
403 }; | |
404 | |
405 NetworkChangeNotifier::NetworkChangeCalculatorParams:: | |
406 NetworkChangeCalculatorParams() { | |
407 } | |
408 | |
409 // Calculates NetworkChange signal from IPAddress and ConnectionType signals. | |
410 class NetworkChangeNotifier::NetworkChangeCalculator | |
411 : public ConnectionTypeObserver, | |
412 public IPAddressObserver { | |
413 public: | |
414 NetworkChangeCalculator(const NetworkChangeCalculatorParams& params) | |
415 : params_(params), | |
416 have_announced_(false), | |
417 last_announced_connection_type_(CONNECTION_NONE), | |
418 pending_connection_type_(CONNECTION_NONE) {} | |
419 | |
420 void Init() { | |
421 DCHECK(thread_checker_.CalledOnValidThread()); | |
422 DCHECK(g_network_change_notifier); | |
423 AddConnectionTypeObserver(this); | |
424 AddIPAddressObserver(this); | |
425 } | |
426 | |
427 ~NetworkChangeCalculator() override { | |
428 DCHECK(thread_checker_.CalledOnValidThread()); | |
429 DCHECK(g_network_change_notifier); | |
430 RemoveConnectionTypeObserver(this); | |
431 RemoveIPAddressObserver(this); | |
432 } | |
433 | |
434 // NetworkChangeNotifier::IPAddressObserver implementation. | |
435 void OnIPAddressChanged() override { | |
436 DCHECK(thread_checker_.CalledOnValidThread()); | |
437 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE | |
438 ? params_.ip_address_offline_delay_ : params_.ip_address_online_delay_; | |
439 // Cancels any previous timer. | |
440 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify); | |
441 } | |
442 | |
443 // NetworkChangeNotifier::ConnectionTypeObserver implementation. | |
444 void OnConnectionTypeChanged(ConnectionType type) override { | |
445 DCHECK(thread_checker_.CalledOnValidThread()); | |
446 pending_connection_type_ = type; | |
447 base::TimeDelta delay = last_announced_connection_type_ == CONNECTION_NONE | |
448 ? params_.connection_type_offline_delay_ | |
449 : params_.connection_type_online_delay_; | |
450 // Cancels any previous timer. | |
451 timer_.Start(FROM_HERE, delay, this, &NetworkChangeCalculator::Notify); | |
452 } | |
453 | |
454 private: | |
455 void Notify() { | |
456 DCHECK(thread_checker_.CalledOnValidThread()); | |
457 // Don't bother signaling about dead connections. | |
458 if (have_announced_ && | |
459 (last_announced_connection_type_ == CONNECTION_NONE) && | |
460 (pending_connection_type_ == CONNECTION_NONE)) { | |
461 return; | |
462 } | |
463 have_announced_ = true; | |
464 last_announced_connection_type_ = pending_connection_type_; | |
465 // Immediately before sending out an online signal, send out an offline | |
466 // signal to perform any destructive actions before constructive actions. | |
467 if (pending_connection_type_ != CONNECTION_NONE) | |
468 NetworkChangeNotifier::NotifyObserversOfNetworkChange(CONNECTION_NONE); | |
469 NetworkChangeNotifier::NotifyObserversOfNetworkChange( | |
470 pending_connection_type_); | |
471 } | |
472 | |
473 const NetworkChangeCalculatorParams params_; | |
474 | |
475 // Indicates if NotifyObserversOfNetworkChange has been called yet. | |
476 bool have_announced_; | |
477 // Last value passed to NotifyObserversOfNetworkChange. | |
478 ConnectionType last_announced_connection_type_; | |
479 // Value to pass to NotifyObserversOfNetworkChange when Notify is called. | |
480 ConnectionType pending_connection_type_; | |
481 // Used to delay notifications so duplicates can be combined. | |
482 base::OneShotTimer<NetworkChangeCalculator> timer_; | |
483 | |
484 base::ThreadChecker thread_checker_; | |
485 | |
486 DISALLOW_COPY_AND_ASSIGN(NetworkChangeCalculator); | |
487 }; | |
488 | |
489 NetworkChangeNotifier::~NetworkChangeNotifier() { | |
490 network_change_calculator_.reset(); | |
491 DCHECK_EQ(this, g_network_change_notifier); | |
492 g_network_change_notifier = NULL; | |
493 } | |
494 | |
495 // static | |
496 void NetworkChangeNotifier::SetFactory( | |
497 NetworkChangeNotifierFactory* factory) { | |
498 CHECK(!g_network_change_notifier_factory); | |
499 g_network_change_notifier_factory = factory; | |
500 } | |
501 | |
502 // static | |
503 NetworkChangeNotifier* NetworkChangeNotifier::Create() { | |
504 if (g_network_change_notifier_factory) | |
505 return g_network_change_notifier_factory->CreateInstance(); | |
506 | |
507 #if defined(OS_WIN) | |
508 NetworkChangeNotifierWin* network_change_notifier = | |
509 new NetworkChangeNotifierWin(); | |
510 network_change_notifier->WatchForAddressChange(); | |
511 return network_change_notifier; | |
512 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID) | |
513 // ChromeOS and Android builds MUST use their own class factory. | |
514 #if !defined(OS_CHROMEOS) | |
515 // TODO(oshima): ash_shell do not have access to chromeos'es | |
516 // notifier yet. Re-enable this when chromeos'es notifier moved to | |
517 // chromeos root directory. crbug.com/119298. | |
518 CHECK(false); | |
519 #endif | |
520 return NULL; | |
521 #elif defined(OS_LINUX) | |
522 return NetworkChangeNotifierLinux::Create(); | |
523 #elif defined(OS_MACOSX) | |
524 return new NetworkChangeNotifierMac(); | |
525 #else | |
526 NOTIMPLEMENTED(); | |
527 return NULL; | |
528 #endif | |
529 } | |
530 | |
531 // static | |
532 NetworkChangeNotifier::ConnectionType | |
533 NetworkChangeNotifier::GetConnectionType() { | |
534 return g_network_change_notifier ? | |
535 g_network_change_notifier->GetCurrentConnectionType() : | |
536 CONNECTION_UNKNOWN; | |
537 } | |
538 | |
539 // static | |
540 double NetworkChangeNotifier::GetMaxBandwidth() { | |
541 return g_network_change_notifier ? | |
542 g_network_change_notifier->GetCurrentMaxBandwidth() : | |
543 std::numeric_limits<double>::infinity(); | |
544 } | |
545 | |
546 // static | |
547 void NetworkChangeNotifier::GetDnsConfig(DnsConfig* config) { | |
548 if (!g_network_change_notifier) { | |
549 *config = DnsConfig(); | |
550 } else { | |
551 g_network_change_notifier->network_state_->GetDnsConfig(config); | |
552 } | |
553 } | |
554 | |
555 // static | |
556 const char* NetworkChangeNotifier::ConnectionTypeToString( | |
557 ConnectionType type) { | |
558 static const char* const kConnectionTypeNames[] = { | |
559 "CONNECTION_UNKNOWN", | |
560 "CONNECTION_ETHERNET", | |
561 "CONNECTION_WIFI", | |
562 "CONNECTION_2G", | |
563 "CONNECTION_3G", | |
564 "CONNECTION_4G", | |
565 "CONNECTION_NONE", | |
566 "CONNECTION_BLUETOOTH" | |
567 }; | |
568 static_assert(arraysize(kConnectionTypeNames) == | |
569 NetworkChangeNotifier::CONNECTION_LAST + 1, | |
570 "ConnectionType name count should match"); | |
571 if (type < CONNECTION_UNKNOWN || type > CONNECTION_LAST) { | |
572 NOTREACHED(); | |
573 return "CONNECTION_INVALID"; | |
574 } | |
575 return kConnectionTypeNames[type]; | |
576 } | |
577 | |
578 // static | |
579 void NetworkChangeNotifier::NotifyDataReceived(const URLRequest& request, | |
580 int bytes_read) { | |
581 if (!g_network_change_notifier || | |
582 !g_network_change_notifier->histogram_watcher_) { | |
583 return; | |
584 } | |
585 g_network_change_notifier->histogram_watcher_->NotifyDataReceived(request, | |
586 bytes_read); | |
587 } | |
588 | |
589 // static | |
590 void NetworkChangeNotifier::InitHistogramWatcher() { | |
591 if (!g_network_change_notifier) | |
592 return; | |
593 g_network_change_notifier->histogram_watcher_.reset(new HistogramWatcher()); | |
594 g_network_change_notifier->histogram_watcher_->Init(); | |
595 } | |
596 | |
597 // static | |
598 void NetworkChangeNotifier::ShutdownHistogramWatcher() { | |
599 if (!g_network_change_notifier) | |
600 return; | |
601 g_network_change_notifier->histogram_watcher_.reset(); | |
602 } | |
603 | |
604 // static | |
605 void NetworkChangeNotifier::LogOperatorCodeHistogram(ConnectionType type) { | |
606 #if defined(OS_ANDROID) | |
607 // On a connection type change to 2/3/4G, log the network operator MCC/MNC. | |
608 // Log zero in other cases. | |
609 unsigned mcc_mnc = 0; | |
610 if (type == NetworkChangeNotifier::CONNECTION_2G || | |
611 type == NetworkChangeNotifier::CONNECTION_3G || | |
612 type == NetworkChangeNotifier::CONNECTION_4G) { | |
613 // Log zero if not perfectly converted. | |
614 if (!base::StringToUint( | |
615 net::android::GetTelephonyNetworkOperator(), &mcc_mnc)) { | |
616 mcc_mnc = 0; | |
617 } | |
618 } | |
619 UMA_HISTOGRAM_SPARSE_SLOWLY("NCN.NetworkOperatorMCCMNC", mcc_mnc); | |
620 #endif | |
621 } | |
622 | |
623 #if defined(OS_LINUX) | |
624 // static | |
625 const internal::AddressTrackerLinux* | |
626 NetworkChangeNotifier::GetAddressTracker() { | |
627 return g_network_change_notifier ? | |
628 g_network_change_notifier->GetAddressTrackerInternal() : NULL; | |
629 } | |
630 #endif | |
631 | |
632 // static | |
633 bool NetworkChangeNotifier::IsOffline() { | |
634 return GetConnectionType() == CONNECTION_NONE; | |
635 } | |
636 | |
637 // static | |
638 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) { | |
639 bool is_cellular = false; | |
640 switch (type) { | |
641 case CONNECTION_2G: | |
642 case CONNECTION_3G: | |
643 case CONNECTION_4G: | |
644 is_cellular = true; | |
645 break; | |
646 case CONNECTION_UNKNOWN: | |
647 case CONNECTION_ETHERNET: | |
648 case CONNECTION_WIFI: | |
649 case CONNECTION_NONE: | |
650 case CONNECTION_BLUETOOTH: | |
651 is_cellular = false; | |
652 break; | |
653 } | |
654 return is_cellular; | |
655 } | |
656 | |
657 // static | |
658 NetworkChangeNotifier::ConnectionType | |
659 NetworkChangeNotifier::ConnectionTypeFromInterfaceList( | |
660 const NetworkInterfaceList& interfaces) { | |
661 bool first = true; | |
662 ConnectionType result = CONNECTION_NONE; | |
663 for (size_t i = 0; i < interfaces.size(); ++i) { | |
664 #if defined(OS_WIN) | |
665 if (interfaces[i].friendly_name == "Teredo Tunneling Pseudo-Interface") | |
666 continue; | |
667 #endif | |
668 if (first) { | |
669 first = false; | |
670 result = interfaces[i].type; | |
671 } else if (result != interfaces[i].type) { | |
672 return CONNECTION_UNKNOWN; | |
673 } | |
674 } | |
675 return result; | |
676 } | |
677 | |
678 // static | |
679 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() { | |
680 return new MockNetworkChangeNotifier(); | |
681 } | |
682 | |
683 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) { | |
684 if (g_network_change_notifier) | |
685 g_network_change_notifier->ip_address_observer_list_->AddObserver(observer); | |
686 } | |
687 | |
688 void NetworkChangeNotifier::AddConnectionTypeObserver( | |
689 ConnectionTypeObserver* observer) { | |
690 if (g_network_change_notifier) { | |
691 g_network_change_notifier->connection_type_observer_list_->AddObserver( | |
692 observer); | |
693 } | |
694 } | |
695 | |
696 void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) { | |
697 if (g_network_change_notifier) { | |
698 g_network_change_notifier->resolver_state_observer_list_->AddObserver( | |
699 observer); | |
700 } | |
701 } | |
702 | |
703 void NetworkChangeNotifier::AddNetworkChangeObserver( | |
704 NetworkChangeObserver* observer) { | |
705 if (g_network_change_notifier) { | |
706 g_network_change_notifier->network_change_observer_list_->AddObserver( | |
707 observer); | |
708 } | |
709 } | |
710 | |
711 void NetworkChangeNotifier::AddMaxBandwidthObserver( | |
712 MaxBandwidthObserver* observer) { | |
713 if (g_network_change_notifier) { | |
714 g_network_change_notifier->max_bandwidth_observer_list_->AddObserver( | |
715 observer); | |
716 } | |
717 } | |
718 | |
719 void NetworkChangeNotifier::RemoveIPAddressObserver( | |
720 IPAddressObserver* observer) { | |
721 if (g_network_change_notifier) { | |
722 g_network_change_notifier->ip_address_observer_list_->RemoveObserver( | |
723 observer); | |
724 } | |
725 } | |
726 | |
727 void NetworkChangeNotifier::RemoveConnectionTypeObserver( | |
728 ConnectionTypeObserver* observer) { | |
729 if (g_network_change_notifier) { | |
730 g_network_change_notifier->connection_type_observer_list_->RemoveObserver( | |
731 observer); | |
732 } | |
733 } | |
734 | |
735 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) { | |
736 if (g_network_change_notifier) { | |
737 g_network_change_notifier->resolver_state_observer_list_->RemoveObserver( | |
738 observer); | |
739 } | |
740 } | |
741 | |
742 void NetworkChangeNotifier::RemoveNetworkChangeObserver( | |
743 NetworkChangeObserver* observer) { | |
744 if (g_network_change_notifier) { | |
745 g_network_change_notifier->network_change_observer_list_->RemoveObserver( | |
746 observer); | |
747 } | |
748 } | |
749 | |
750 void NetworkChangeNotifier::RemoveMaxBandwidthObserver( | |
751 MaxBandwidthObserver* observer) { | |
752 if (g_network_change_notifier) { | |
753 g_network_change_notifier->max_bandwidth_observer_list_->RemoveObserver( | |
754 observer); | |
755 } | |
756 } | |
757 | |
758 // static | |
759 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeForTests() { | |
760 if (g_network_change_notifier) | |
761 g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl(); | |
762 } | |
763 | |
764 // static | |
765 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeForTests( | |
766 ConnectionType type) { | |
767 if (g_network_change_notifier) | |
768 g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl(type); | |
769 } | |
770 | |
771 // static | |
772 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeForTests( | |
773 ConnectionType type) { | |
774 if (g_network_change_notifier) | |
775 g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type); | |
776 } | |
777 | |
778 // static | |
779 void NetworkChangeNotifier::SetTestNotificationsOnly(bool test_only) { | |
780 if (g_network_change_notifier) | |
781 g_network_change_notifier->test_notifications_only_ = test_only; | |
782 } | |
783 | |
784 NetworkChangeNotifier::NetworkChangeNotifier( | |
785 const NetworkChangeCalculatorParams& params | |
786 /*= NetworkChangeCalculatorParams()*/) | |
787 : ip_address_observer_list_(new ObserverListThreadSafe<IPAddressObserver>( | |
788 ObserverListBase<IPAddressObserver>::NOTIFY_EXISTING_ONLY)), | |
789 connection_type_observer_list_( | |
790 new ObserverListThreadSafe<ConnectionTypeObserver>( | |
791 ObserverListBase<ConnectionTypeObserver>::NOTIFY_EXISTING_ONLY)), | |
792 resolver_state_observer_list_(new ObserverListThreadSafe<DNSObserver>( | |
793 ObserverListBase<DNSObserver>::NOTIFY_EXISTING_ONLY)), | |
794 network_change_observer_list_( | |
795 new ObserverListThreadSafe<NetworkChangeObserver>( | |
796 ObserverListBase<NetworkChangeObserver>::NOTIFY_EXISTING_ONLY)), | |
797 max_bandwidth_observer_list_( | |
798 new ObserverListThreadSafe<MaxBandwidthObserver>( | |
799 ObserverListBase<MaxBandwidthObserver>::NOTIFY_EXISTING_ONLY)), | |
800 network_state_(new NetworkState()), | |
801 network_change_calculator_(new NetworkChangeCalculator(params)), | |
802 test_notifications_only_(false) { | |
803 DCHECK(!g_network_change_notifier); | |
804 g_network_change_notifier = this; | |
805 network_change_calculator_->Init(); | |
806 } | |
807 | |
808 #if defined(OS_LINUX) | |
809 const internal::AddressTrackerLinux* | |
810 NetworkChangeNotifier::GetAddressTrackerInternal() const { | |
811 return NULL; | |
812 } | |
813 #endif | |
814 | |
815 double NetworkChangeNotifier::GetCurrentMaxBandwidth() const { | |
816 // This default implementation conforms to the NetInfo V3 specification but | |
817 // should be overridden to provide specific bandwidth data based on the | |
818 // platform. | |
819 if (GetCurrentConnectionType() == CONNECTION_NONE) | |
820 return 0.0; | |
821 return std::numeric_limits<double>::infinity(); | |
822 } | |
823 | |
824 // static | |
825 double NetworkChangeNotifier::GetMaxBandwidthForConnectionSubtype( | |
826 ConnectionSubtype subtype) { | |
827 switch (subtype) { | |
828 case SUBTYPE_GSM: | |
829 return 0.01; | |
830 case SUBTYPE_IDEN: | |
831 return 0.064; | |
832 case SUBTYPE_CDMA: | |
833 return 0.115; | |
834 case SUBTYPE_1XRTT: | |
835 return 0.153; | |
836 case SUBTYPE_GPRS: | |
837 return 0.237; | |
838 case SUBTYPE_EDGE: | |
839 return 0.384; | |
840 case SUBTYPE_UMTS: | |
841 return 2.0; | |
842 case SUBTYPE_EVDO_REV_0: | |
843 return 2.46; | |
844 case SUBTYPE_EVDO_REV_A: | |
845 return 3.1; | |
846 case SUBTYPE_HSPA: | |
847 return 3.6; | |
848 case SUBTYPE_EVDO_REV_B: | |
849 return 14.7; | |
850 case SUBTYPE_HSDPA: | |
851 return 14.3; | |
852 case SUBTYPE_HSUPA: | |
853 return 14.4; | |
854 case SUBTYPE_EHRPD: | |
855 return 21.0; | |
856 case SUBTYPE_HSPAP: | |
857 return 42.0; | |
858 case SUBTYPE_LTE: | |
859 return 100.0; | |
860 case SUBTYPE_LTE_ADVANCED: | |
861 return 100.0; | |
862 case SUBTYPE_BLUETOOTH_1_2: | |
863 return 1.0; | |
864 case SUBTYPE_BLUETOOTH_2_1: | |
865 return 3.0; | |
866 case SUBTYPE_BLUETOOTH_3_0: | |
867 return 24.0; | |
868 case SUBTYPE_BLUETOOTH_4_0: | |
869 return 1.0; | |
870 case SUBTYPE_ETHERNET: | |
871 return 10.0; | |
872 case SUBTYPE_FAST_ETHERNET: | |
873 return 100.0; | |
874 case SUBTYPE_GIGABIT_ETHERNET: | |
875 return 1000.0; | |
876 case SUBTYPE_10_GIGABIT_ETHERNET: | |
877 return 10000.0; | |
878 case SUBTYPE_WIFI_B: | |
879 return 11.0; | |
880 case SUBTYPE_WIFI_G: | |
881 return 54.0; | |
882 case SUBTYPE_WIFI_N: | |
883 return 600.0; | |
884 case SUBTYPE_WIFI_AC: | |
885 return 1300.0; | |
886 case SUBTYPE_WIFI_AD: | |
887 return 7000.0; | |
888 case SUBTYPE_UNKNOWN: | |
889 return std::numeric_limits<double>::infinity(); | |
890 case SUBTYPE_NONE: | |
891 return 0.0; | |
892 case SUBTYPE_OTHER: | |
893 return std::numeric_limits<double>::infinity(); | |
894 } | |
895 NOTREACHED(); | |
896 return std::numeric_limits<double>::infinity(); | |
897 } | |
898 | |
899 // static | |
900 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() { | |
901 if (g_network_change_notifier && | |
902 !g_network_change_notifier->test_notifications_only_) { | |
903 g_network_change_notifier->NotifyObserversOfIPAddressChangeImpl(); | |
904 } | |
905 } | |
906 | |
907 // static | |
908 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() { | |
909 if (g_network_change_notifier && | |
910 !g_network_change_notifier->test_notifications_only_) { | |
911 g_network_change_notifier->NotifyObserversOfConnectionTypeChangeImpl( | |
912 GetConnectionType()); | |
913 } | |
914 } | |
915 | |
916 // static | |
917 void NetworkChangeNotifier::NotifyObserversOfNetworkChange( | |
918 ConnectionType type) { | |
919 if (g_network_change_notifier && | |
920 !g_network_change_notifier->test_notifications_only_) { | |
921 g_network_change_notifier->NotifyObserversOfNetworkChangeImpl(type); | |
922 } | |
923 } | |
924 | |
925 // static | |
926 void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChange( | |
927 double max_bandwidth_mbps) { | |
928 if (g_network_change_notifier && | |
929 !g_network_change_notifier->test_notifications_only_) { | |
930 g_network_change_notifier->NotifyObserversOfMaxBandwidthChangeImpl( | |
931 max_bandwidth_mbps); | |
932 } | |
933 } | |
934 | |
935 // static | |
936 void NetworkChangeNotifier::NotifyObserversOfDNSChange() { | |
937 if (g_network_change_notifier && | |
938 !g_network_change_notifier->test_notifications_only_) { | |
939 g_network_change_notifier->NotifyObserversOfDNSChangeImpl(); | |
940 } | |
941 } | |
942 | |
943 // static | |
944 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) { | |
945 if (!g_network_change_notifier) | |
946 return; | |
947 g_network_change_notifier->network_state_->SetDnsConfig(config); | |
948 NotifyObserversOfDNSChange(); | |
949 } | |
950 | |
951 void NetworkChangeNotifier::NotifyObserversOfIPAddressChangeImpl() { | |
952 ip_address_observer_list_->Notify(FROM_HERE, | |
953 &IPAddressObserver::OnIPAddressChanged); | |
954 } | |
955 | |
956 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChangeImpl( | |
957 ConnectionType type) { | |
958 connection_type_observer_list_->Notify( | |
959 FROM_HERE, &ConnectionTypeObserver::OnConnectionTypeChanged, type); | |
960 } | |
961 | |
962 void NetworkChangeNotifier::NotifyObserversOfNetworkChangeImpl( | |
963 ConnectionType type) { | |
964 network_change_observer_list_->Notify( | |
965 FROM_HERE, &NetworkChangeObserver::OnNetworkChanged, type); | |
966 } | |
967 | |
968 void NetworkChangeNotifier::NotifyObserversOfDNSChangeImpl() { | |
969 resolver_state_observer_list_->Notify(FROM_HERE, &DNSObserver::OnDNSChanged); | |
970 } | |
971 | |
972 void NetworkChangeNotifier::NotifyObserversOfMaxBandwidthChangeImpl( | |
973 double max_bandwidth_mbps) { | |
974 max_bandwidth_observer_list_->Notify( | |
975 FROM_HERE, &MaxBandwidthObserver::OnMaxBandwidthChanged, | |
976 max_bandwidth_mbps); | |
977 } | |
978 | |
979 NetworkChangeNotifier::DisableForTest::DisableForTest() | |
980 : network_change_notifier_(g_network_change_notifier) { | |
981 DCHECK(g_network_change_notifier); | |
982 g_network_change_notifier = NULL; | |
983 } | |
984 | |
985 NetworkChangeNotifier::DisableForTest::~DisableForTest() { | |
986 DCHECK(!g_network_change_notifier); | |
987 g_network_change_notifier = network_change_notifier_; | |
988 } | |
989 | |
990 } // namespace net | |
OLD | NEW |