1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
// Copyright 2016 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 "device/geolocation/wifi_data_provider_mac.h"
#import <CoreWLAN/CoreWLAN.h>
#import <Foundation/Foundation.h>
#include "base/mac/scoped_nsautorelease_pool.h"
#include "base/mac/scoped_nsobject.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/histogram_macros.h"
#include "base/strings/sys_string_conversions.h"
#include "device/geolocation/wifi_data_provider_common.h"
#include "device/geolocation/wifi_data_provider_manager.h"
extern "C" NSString* const kCWScanKeyMerge;
@interface CWInterface (Private)
- (NSArray*)scanForNetworksWithParameters:(NSDictionary*)params
error:(NSError**)error;
@end
namespace device {
namespace {
class CoreWlanApi : public WifiDataProviderCommon::WlanApiInterface {
public:
CoreWlanApi() {}
// WlanApiInterface:
bool GetAccessPointData(WifiData::AccessPointDataSet* data) override;
private:
DISALLOW_COPY_AND_ASSIGN(CoreWlanApi);
};
bool CoreWlanApi::GetAccessPointData(WifiData::AccessPointDataSet* data) {
base::mac::ScopedNSAutoreleasePool auto_pool;
// Initialize the scan parameters with scan key merging disabled, so we get
// every AP listed in the scan without any SSID de-duping logic.
NSDictionary* params = @{ kCWScanKeyMerge : @NO };
NSSet* supported_interfaces = [CWInterface interfaceNames];
NSUInteger interface_error_count = 0;
for (NSString* interface_name in supported_interfaces) {
CWInterface* corewlan_interface =
[CWInterface interfaceWithName:interface_name];
if (!corewlan_interface) {
DLOG(WARNING) << interface_name << ": initWithName failed";
++interface_error_count;
continue;
}
const base::TimeTicks start_time = base::TimeTicks::Now();
NSError* err = nil;
NSArray* scan =
[corewlan_interface scanForNetworksWithParameters:params error:&err];
const int error_code = [err code];
const int count = [scan count];
// We could get an error code but count != 0 if the scan was interrupted,
// for example. For our purposes this is not fatal, so process as normal.
if (error_code && count == 0) {
DLOG(WARNING) << interface_name << ": CoreWLAN scan failed with error "
<< error_code;
++interface_error_count;
continue;
}
const base::TimeDelta duration = base::TimeTicks::Now() - start_time;
UMA_HISTOGRAM_CUSTOM_TIMES("Net.Wifi.ScanLatency", duration,
base::TimeDelta::FromMilliseconds(1),
base::TimeDelta::FromMinutes(1), 100);
DVLOG(1) << interface_name << ": found " << count << " wifi APs";
for (CWNetwork* network in scan) {
DCHECK(network);
AccessPointData access_point_data;
// -[CWNetwork bssid] uses colons to separate the components of the MAC
// address, but AccessPointData requires they be separated with a dash.
access_point_data.mac_address = base::SysNSStringToUTF16([[network bssid]
stringByReplacingOccurrencesOfString:@":"
withString:@"-"]);
access_point_data.radio_signal_strength = [network rssiValue];
access_point_data.channel = [[network wlanChannel] channelNumber];
access_point_data.signal_to_noise =
access_point_data.radio_signal_strength - [network noiseMeasurement];
access_point_data.ssid = base::SysNSStringToUTF16([network ssid]);
data->insert(access_point_data);
}
}
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Net.Wifi.InterfaceCount",
[supported_interfaces count] - interface_error_count, 1, 5, 6);
// Return true even if some interfaces failed to scan, so long as at least
// one interface did not fail.
return interface_error_count == 0 ||
[supported_interfaces count] > interface_error_count;
};
// The time periods, in milliseconds, between successive polls of the wifi data.
const int kDefaultPollingInterval = 120000; // 2 mins
const int kNoChangePollingInterval = 300000; // 5 mins
const int kTwoNoChangePollingInterval = 600000; // 10 mins
const int kNoWifiPollingIntervalMilliseconds = 20 * 1000; // 20s
} // namespace
// static
WifiDataProvider* WifiDataProviderManager::DefaultFactoryFunction() {
return new WifiDataProviderMac();
}
WifiDataProviderMac::WifiDataProviderMac() {}
WifiDataProviderMac::~WifiDataProviderMac() {}
std::unique_ptr<WifiDataProviderMac::WlanApiInterface>
WifiDataProviderMac::CreateWlanApi() {
return std::make_unique<CoreWlanApi>();
}
std::unique_ptr<WifiPollingPolicy> WifiDataProviderMac::CreatePollingPolicy() {
return std::make_unique<GenericWifiPollingPolicy<
kDefaultPollingInterval, kNoChangePollingInterval,
kTwoNoChangePollingInterval, kNoWifiPollingIntervalMilliseconds>>();
}
} // namespace device
|