| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "services/device/geolocation/wifi_data_provider_mac.h" |
| |
| #import <CoreWLAN/CoreWLAN.h> |
| #import <Foundation/Foundation.h> |
| |
| #include "base/logging.h" |
| #include "base/strings/sys_string_conversions.h" |
| #include "services/device/geolocation/wifi_data_provider_common.h" |
| #include "services/device/geolocation/wifi_data_provider_handle.h" |
| #include "services/device/public/mojom/geolocation_internals.mojom.h" |
| |
| namespace device { |
| |
| namespace { |
| |
| class CoreWlanApi : public WifiDataProviderCommon::WlanApiInterface { |
| public: |
| CoreWlanApi() = default; |
| |
| CoreWlanApi(const CoreWlanApi&) = delete; |
| CoreWlanApi& operator=(const CoreWlanApi&) = delete; |
| |
| // WlanApiInterface: |
| void GetAccessPointData( |
| base::OnceCallback<void(std::unique_ptr<WifiData::AccessPointDataSet>)> |
| callback) override; |
| |
| private: |
| CWWiFiClient* __strong wifi_client_ = [CWWiFiClient sharedWiFiClient]; |
| }; |
| |
| void CoreWlanApi::GetAccessPointData( |
| base::OnceCallback<void(std::unique_ptr<WifiData::AccessPointDataSet>)> |
| callback) { |
| @autoreleasepool { |
| auto data = std::make_unique<WifiData::AccessPointDataSet>(); |
| NSArray<CWInterface*>* interfaces = wifi_client_.interfaces; |
| NSUInteger interface_error_count = 0; |
| for (CWInterface* interface in interfaces) { |
| NSError* err = nil; |
| NSSet<CWNetwork*>* scan = [interface scanForNetworksWithName:nil |
| 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.interfaceName |
| << ": CoreWLAN scan failed with error " << error_code; |
| ++interface_error_count; |
| continue; |
| } |
| |
| DVLOG(1) << interface.interfaceName << ": found " << count << " wifi APs"; |
| |
| for (CWNetwork* network in scan) { |
| DCHECK(network); |
| mojom::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::SysNSStringToUTF8([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; |
| data->insert(access_point_data); |
| } |
| } |
| |
| // Return true even if some interfaces failed to scan, so long as at least |
| // one interface did not fail. |
| if (interface_error_count > 0 && |
| interfaces.count <= interface_error_count) { |
| std::move(callback).Run(nullptr); |
| } else { |
| std::move(callback).Run(std::move(data)); |
| } |
| } |
| } |
| |
| // 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* WifiDataProviderHandle::DefaultFactoryFunction() { |
| return new WifiDataProviderMac(); |
| } |
| |
| WifiDataProviderMac::WifiDataProviderMac() = default; |
| |
| WifiDataProviderMac::~WifiDataProviderMac() = default; |
| |
| 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 |