| Index: device/geolocation/wifi_data_provider_mac.mm
|
| diff --git a/device/geolocation/wifi_data_provider_mac.mm b/device/geolocation/wifi_data_provider_mac.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a5f978bf7f70b1d5268df0d109625ba2ca6b5f8d
|
| --- /dev/null
|
| +++ b/device/geolocation/wifi_data_provider_mac.mm
|
| @@ -0,0 +1,135 @@
|
| +// 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/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() {}
|
| +
|
| +WifiDataProviderMac::WlanApiInterface* WifiDataProviderMac::NewWlanApi() {
|
| + return new CoreWlanApi();
|
| +}
|
| +
|
| +WifiPollingPolicy* WifiDataProviderMac::NewPollingPolicy() {
|
| + return new GenericWifiPollingPolicy<
|
| + kDefaultPollingInterval, kNoChangePollingInterval,
|
| + kTwoNoChangePollingInterval, kNoWifiPollingIntervalMilliseconds>;
|
| +}
|
| +
|
| +} // namespace device
|
|
|