move SK_DISABLE_DITHER_32BIT_GRADIENT from SkUserConfig.h to skia.gyp, so we can...
[chromium-blink-merge.git] / net / base / network_change_notifier.cc
blobe8dd1208e4127713433df6c0dfbb9836d6d46a57
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.
5 #include "net/base/network_change_notifier.h"
7 #include "base/metrics/histogram.h"
8 #include "base/synchronization/lock.h"
9 #include "build/build_config.h"
10 #include "googleurl/src/gurl.h"
11 #include "net/base/net_util.h"
12 #include "net/base/network_change_notifier_factory.h"
13 #include "net/dns/dns_config_service.h"
15 #if defined(OS_WIN)
16 #include "net/base/network_change_notifier_win.h"
17 #elif defined(OS_LINUX) && !defined(OS_CHROMEOS)
18 #include "net/base/network_change_notifier_linux.h"
19 #elif defined(OS_MACOSX)
20 #include "net/base/network_change_notifier_mac.h"
21 #endif
23 namespace net {
25 namespace {
27 // The actual singleton notifier. The class contract forbids usage of the API
28 // in ways that would require us to place locks around access to this object.
29 // (The prohibition on global non-POD objects makes it tricky to do such a thing
30 // anyway.)
31 NetworkChangeNotifier* g_network_change_notifier = NULL;
33 // Class factory singleton.
34 NetworkChangeNotifierFactory* g_network_change_notifier_factory = NULL;
36 class MockNetworkChangeNotifier : public NetworkChangeNotifier {
37 public:
38 virtual ConnectionType GetCurrentConnectionType() const OVERRIDE {
39 return CONNECTION_UNKNOWN;
43 } // namespace
45 // The main observer class that records UMAs for network events.
46 class HistogramWatcher
47 : public NetworkChangeNotifier::ConnectionTypeObserver,
48 public NetworkChangeNotifier::IPAddressObserver,
49 public NetworkChangeNotifier::DNSObserver {
50 public:
51 HistogramWatcher()
52 : last_ip_address_change_(base::TimeTicks::Now()),
53 last_connection_change_(base::TimeTicks::Now()),
54 last_dns_change_(base::TimeTicks::Now()),
55 last_connection_type_(NetworkChangeNotifier::CONNECTION_UNKNOWN),
56 offline_packets_received_(0) {}
58 // Registers our three Observer implementations. This is called from the
59 // network thread so that our Observer implementations are also called
60 // from the network thread. This avoids multi-threaded race conditions
61 // because the only other interface, |NotifyDataReceived| is also
62 // only called from the network thread.
63 void Init() {
64 NetworkChangeNotifier::AddConnectionTypeObserver(this);
65 NetworkChangeNotifier::AddIPAddressObserver(this);
66 NetworkChangeNotifier::AddDNSObserver(this);
69 virtual ~HistogramWatcher() {}
71 // NetworkChangeNotifier::IPAddressObserver implementation.
72 virtual void OnIPAddressChanged() OVERRIDE {
73 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.IPAddressChange",
74 SinceLast(&last_ip_address_change_));
77 // NetworkChangeNotifier::ConnectionTypeObserver implementation.
78 virtual void OnConnectionTypeChanged(
79 NetworkChangeNotifier::ConnectionType type) OVERRIDE {
80 if (type != NetworkChangeNotifier::CONNECTION_NONE) {
81 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OnlineChange",
82 SinceLast(&last_connection_change_));
84 if (offline_packets_received_) {
85 if ((last_connection_change_ - last_offline_packet_received_) <
86 base::TimeDelta::FromSeconds(5)) {
87 // We can compare this sum with the sum of NCN.OfflineDataRecv.
88 UMA_HISTOGRAM_COUNTS_10000(
89 "NCN.OfflineDataRecvAny5sBeforeOnline",
90 offline_packets_received_);
93 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecvUntilOnline",
94 last_connection_change_ -
95 last_offline_packet_received_);
97 } else {
98 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineChange",
99 SinceLast(&last_connection_change_));
102 offline_packets_received_ = 0;
103 last_connection_type_ = type;
104 polling_interval_ = base::TimeDelta::FromSeconds(1);
107 // NetworkChangeNotifier::DNSObserver implementation.
108 virtual void OnDNSChanged() OVERRIDE {
109 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.DNSConfigChange",
110 SinceLast(&last_dns_change_));
113 // Record histogram data whenever we receive a packet but think we're
114 // offline. Should only be called from the network thread.
115 void NotifyDataReceived(const GURL& source) {
116 if (last_connection_type_ != NetworkChangeNotifier::CONNECTION_NONE ||
117 IsLocalhost(source.host()) ||
118 !(source.SchemeIs("http") || source.SchemeIs("https"))) {
119 return;
122 base::TimeTicks current_time = base::TimeTicks::Now();
123 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.OfflineDataRecv",
124 current_time - last_connection_change_);
125 offline_packets_received_++;
126 last_offline_packet_received_ = current_time;
128 if ((current_time - last_polled_connection_) > polling_interval_) {
129 polling_interval_ *= 2;
130 last_polled_connection_ = current_time;
131 base::TimeTicks started_get_connection_type = base::TimeTicks::Now();
132 last_polled_connection_type_ =
133 NetworkChangeNotifier::GetConnectionType();
134 UMA_HISTOGRAM_TIMES("NCN.GetConnectionTypeTime",
135 base::TimeTicks::Now() -
136 started_get_connection_type);
138 if (last_polled_connection_type_ ==
139 NetworkChangeNotifier::CONNECTION_NONE) {
140 UMA_HISTOGRAM_MEDIUM_TIMES("NCN.PollingOfflineDataRecv",
141 current_time - last_connection_change_);
145 private:
146 static base::TimeDelta SinceLast(base::TimeTicks *last_time) {
147 base::TimeTicks current_time = base::TimeTicks::Now();
148 base::TimeDelta delta = current_time - *last_time;
149 *last_time = current_time;
150 return delta;
153 base::TimeTicks last_ip_address_change_;
154 base::TimeTicks last_connection_change_;
155 base::TimeTicks last_dns_change_;
156 base::TimeTicks last_offline_packet_received_;
157 base::TimeTicks last_polled_connection_;
158 // |polling_interval_| is initialized by |OnConnectionTypeChanged| on our
159 // first transition to offline and on subsequent transitions. Once offline,
160 // |polling_interval_| doubles as offline data is received and we poll
161 // with |NetworkChangeNotifier::GetConnectionType| to verify the connection
162 // state.
163 base::TimeDelta polling_interval_;
164 // |last_connection_type_| is the last value passed to
165 // |OnConnectionTypeChanged|.
166 NetworkChangeNotifier::ConnectionType last_connection_type_;
167 // |last_polled_connection_type_| is last result from calling
168 // |NetworkChangeNotifier::GetConnectionType| in |NotifyDataReceived|.
169 NetworkChangeNotifier::ConnectionType last_polled_connection_type_;
170 int32 offline_packets_received_;
172 DISALLOW_COPY_AND_ASSIGN(HistogramWatcher);
175 // NetworkState is thread safe.
176 class NetworkChangeNotifier::NetworkState {
177 public:
178 NetworkState() {}
179 ~NetworkState() {}
181 void GetDnsConfig(DnsConfig* config) const {
182 base::AutoLock lock(lock_);
183 *config = dns_config_;
186 void SetDnsConfig(const DnsConfig& dns_config) {
187 base::AutoLock lock(lock_);
188 dns_config_ = dns_config;
191 private:
192 mutable base::Lock lock_;
193 DnsConfig dns_config_;
196 NetworkChangeNotifier::~NetworkChangeNotifier() {
197 DCHECK_EQ(this, g_network_change_notifier);
198 g_network_change_notifier = NULL;
201 // static
202 void NetworkChangeNotifier::SetFactory(
203 NetworkChangeNotifierFactory* factory) {
204 CHECK(!g_network_change_notifier_factory);
205 g_network_change_notifier_factory = factory;
208 // static
209 NetworkChangeNotifier* NetworkChangeNotifier::Create() {
210 if (g_network_change_notifier_factory)
211 return g_network_change_notifier_factory->CreateInstance();
213 #if defined(OS_WIN)
214 NetworkChangeNotifierWin* network_change_notifier =
215 new NetworkChangeNotifierWin();
216 network_change_notifier->WatchForAddressChange();
217 return network_change_notifier;
218 #elif defined(OS_CHROMEOS) || defined(OS_ANDROID)
219 // ChromeOS and Android builds MUST use their own class factory.
220 #if !defined(OS_CHROMEOS)
221 // TODO(oshima): ash_shell do not have access to chromeos'es
222 // notifier yet. Re-enable this when chromeos'es notifier moved to
223 // chromeos root directory. crbug.com/119298.
224 CHECK(false);
225 #endif
226 return NULL;
227 #elif defined(OS_LINUX)
228 return NetworkChangeNotifierLinux::Create();
229 #elif defined(OS_MACOSX)
230 return new NetworkChangeNotifierMac();
231 #else
232 NOTIMPLEMENTED();
233 return NULL;
234 #endif
237 // static
238 NetworkChangeNotifier::ConnectionType
239 NetworkChangeNotifier::GetConnectionType() {
240 return g_network_change_notifier ?
241 g_network_change_notifier->GetCurrentConnectionType() :
242 CONNECTION_UNKNOWN;
245 // static
246 void NetworkChangeNotifier::GetDnsConfig(DnsConfig* config) {
247 if (!g_network_change_notifier) {
248 *config = DnsConfig();
249 } else {
250 g_network_change_notifier->network_state_->GetDnsConfig(config);
254 // static
255 const char* NetworkChangeNotifier::ConnectionTypeToString(
256 ConnectionType type) {
257 static const char* kConnectionTypeNames[] = {
258 "CONNECTION_UNKNOWN",
259 "CONNECTION_ETHERNET",
260 "CONNECTION_WIFI",
261 "CONNECTION_2G",
262 "CONNECTION_3G",
263 "CONNECTION_4G",
264 "CONNECTION_NONE"
266 COMPILE_ASSERT(
267 arraysize(kConnectionTypeNames) ==
268 NetworkChangeNotifier::CONNECTION_NONE + 1,
269 ConnectionType_name_count_mismatch);
270 if (type < CONNECTION_UNKNOWN || type > CONNECTION_NONE) {
271 NOTREACHED();
272 return "CONNECTION_INVALID";
274 return kConnectionTypeNames[type];
277 // static
278 void NetworkChangeNotifier::NotifyDataReceived(const GURL& source) {
279 if (!g_network_change_notifier)
280 return;
281 g_network_change_notifier->histogram_watcher_->NotifyDataReceived(source);
284 // static
285 void NetworkChangeNotifier::InitHistogramWatcher() {
286 if (!g_network_change_notifier)
287 return;
288 g_network_change_notifier->histogram_watcher_->Init();
291 #if defined(OS_LINUX)
292 // static
293 const internal::AddressTrackerLinux*
294 NetworkChangeNotifier::GetAddressTracker() {
295 return g_network_change_notifier ?
296 g_network_change_notifier->GetAddressTrackerInternal() : NULL;
298 #endif
300 // static
301 bool NetworkChangeNotifier::IsOffline() {
302 return GetConnectionType() == CONNECTION_NONE;
305 // static
306 bool NetworkChangeNotifier::IsConnectionCellular(ConnectionType type) {
307 bool is_cellular = false;
308 switch (type) {
309 case CONNECTION_2G:
310 case CONNECTION_3G:
311 case CONNECTION_4G:
312 is_cellular = true;
313 break;
314 case CONNECTION_UNKNOWN:
315 case CONNECTION_ETHERNET:
316 case CONNECTION_WIFI:
317 case CONNECTION_NONE:
318 is_cellular = false;
319 break;
321 return is_cellular;
324 // static
325 NetworkChangeNotifier* NetworkChangeNotifier::CreateMock() {
326 return new MockNetworkChangeNotifier();
329 void NetworkChangeNotifier::AddIPAddressObserver(IPAddressObserver* observer) {
330 if (g_network_change_notifier)
331 g_network_change_notifier->ip_address_observer_list_->AddObserver(observer);
334 void NetworkChangeNotifier::AddConnectionTypeObserver(
335 ConnectionTypeObserver* observer) {
336 if (g_network_change_notifier) {
337 g_network_change_notifier->connection_type_observer_list_->AddObserver(
338 observer);
342 void NetworkChangeNotifier::AddDNSObserver(DNSObserver* observer) {
343 if (g_network_change_notifier) {
344 g_network_change_notifier->resolver_state_observer_list_->AddObserver(
345 observer);
349 void NetworkChangeNotifier::RemoveIPAddressObserver(
350 IPAddressObserver* observer) {
351 if (g_network_change_notifier) {
352 g_network_change_notifier->ip_address_observer_list_->RemoveObserver(
353 observer);
357 void NetworkChangeNotifier::RemoveConnectionTypeObserver(
358 ConnectionTypeObserver* observer) {
359 if (g_network_change_notifier) {
360 g_network_change_notifier->connection_type_observer_list_->RemoveObserver(
361 observer);
365 void NetworkChangeNotifier::RemoveDNSObserver(DNSObserver* observer) {
366 if (g_network_change_notifier) {
367 g_network_change_notifier->resolver_state_observer_list_->RemoveObserver(
368 observer);
372 NetworkChangeNotifier::NetworkChangeNotifier()
373 : ip_address_observer_list_(
374 new ObserverListThreadSafe<IPAddressObserver>(
375 ObserverListBase<IPAddressObserver>::NOTIFY_EXISTING_ONLY)),
376 connection_type_observer_list_(
377 new ObserverListThreadSafe<ConnectionTypeObserver>(
378 ObserverListBase<ConnectionTypeObserver>::NOTIFY_EXISTING_ONLY)),
379 resolver_state_observer_list_(
380 new ObserverListThreadSafe<DNSObserver>(
381 ObserverListBase<DNSObserver>::NOTIFY_EXISTING_ONLY)),
382 network_state_(new NetworkState()),
383 histogram_watcher_(new HistogramWatcher()) {
384 DCHECK(!g_network_change_notifier);
385 g_network_change_notifier = this;
388 #if defined(OS_LINUX)
389 const internal::AddressTrackerLinux*
390 NetworkChangeNotifier::GetAddressTrackerInternal() const {
391 return NULL;
393 #endif
395 // static
396 void NetworkChangeNotifier::NotifyObserversOfIPAddressChange() {
397 if (g_network_change_notifier) {
398 g_network_change_notifier->ip_address_observer_list_->Notify(
399 &IPAddressObserver::OnIPAddressChanged);
403 // static
404 void NetworkChangeNotifier::NotifyObserversOfDNSChange() {
405 if (g_network_change_notifier) {
406 g_network_change_notifier->resolver_state_observer_list_->Notify(
407 &DNSObserver::OnDNSChanged);
411 // static
412 void NetworkChangeNotifier::SetDnsConfig(const DnsConfig& config) {
413 if (!g_network_change_notifier)
414 return;
415 g_network_change_notifier->network_state_->SetDnsConfig(config);
416 NotifyObserversOfDNSChange();
419 void NetworkChangeNotifier::NotifyObserversOfConnectionTypeChange() {
420 if (g_network_change_notifier) {
421 g_network_change_notifier->connection_type_observer_list_->Notify(
422 &ConnectionTypeObserver::OnConnectionTypeChanged,
423 GetConnectionType());
427 NetworkChangeNotifier::DisableForTest::DisableForTest()
428 : network_change_notifier_(g_network_change_notifier) {
429 DCHECK(g_network_change_notifier);
430 g_network_change_notifier = NULL;
433 NetworkChangeNotifier::DisableForTest::~DisableForTest() {
434 DCHECK(!g_network_change_notifier);
435 g_network_change_notifier = network_change_notifier_;
438 } // namespace net