Index: chrome/browser/geolocation/wifi_data_provider_linux.cc |
=================================================================== |
--- chrome/browser/geolocation/wifi_data_provider_linux.cc (revision 40894) |
+++ chrome/browser/geolocation/wifi_data_provider_linux.cc (working copy) |
@@ -2,256 +2,365 @@ |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
-// WiFi card drivers for Linux implement the Wireless Extensions interface. |
-// This interface is part of the Linux kernel. |
-// |
-// Various sets of tools are available to manipulate the Wireless Extensions, |
-// of which Wireless Tools is the default implementation. Wireless Tools |
-// provides a C++ library (libiw) as well as a set of command line tools |
-// (iwconfig, iwlist etc). See |
-// http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html for details. |
-// |
-// Ideally, we would use libiw to obtain WiFi data. However, Wireless Tools is |
-// released under GPL, which is not compatible with Gears. Furthermore, little |
-// documentation is available for Wireless Extensions, so replicating libiw |
-// without copying it directly would be difficult. |
-// |
-// We therefore simply invoke iwlist (one of the Wireless Tools command line |
-// tools) and parse the output. Sample output is shown below. |
-// |
-// lo Interface doesn't support scanning. |
-// |
-// ath0 Scan completed : |
-// Cell 01 - Address: 00:24:86:11:4C:42 |
-// ESSID:"Test SSID" |
-// Mode:Master |
-// Frequency:2.427 GHz (Channel 4) |
-// Quality=5/94 Signal level=-90 dBm Noise level=-95 dBm |
-// Encryption key:off |
-// Bit Rates:1 Mb/s; 2 Mb/s; 5 Mb/s; 6 Mb/s; 9 Mb/s |
-// 11 Mb/s; 12 Mb/s; 18 Mb/s |
-// Extra:bcn_int=100 |
-// Cell 02 - Address: 00:24:86:11:6F:E2 |
-// ESSID:"Test SSID" |
-// Mode:Master |
-// Frequency:2.447 GHz (Channel 8) |
-// Quality=4/94 Signal level=-91 dBm Noise level=-95 dBm |
-// Encryption key:off |
-// Bit Rates:1 Mb/s; 2 Mb/s; 5 Mb/s; 6 Mb/s; 9 Mb/s |
-// 11 Mb/s; 12 Mb/s; 18 Mb/s |
-// Extra:bcn_int=100 |
-// |
-// TODO(steveblock): Investigate the possibility of the author of Wireless Tools |
-// releasing libiw under a Gears-compatible license. |
+// Provides wifi scan API binding for suitable for typical linux distributions. |
+// Currently, only the NetworkManager API is used, accessed via D-Bus (in turn |
+// accessed via the GLib wrapper). |
-// TODO(joth): port to chromium |
-#if 0 |
+#include "chrome/browser/geolocation/wifi_data_provider_linux.h" |
-#include "gears/geolocation/wifi_data_provider_linux.h" |
+#include <dbus/dbus-glib.h> |
+#include <glib.h> |
-#include <ctype.h> // For isxdigit() |
-#include <stdio.h> |
-#include "gears/base/common/string_utils.h" |
-#include "gears/geolocation/wifi_data_provider_common.h" |
+#include "base/scoped_ptr.h" |
+#include "base/utf_string_conversions.h" |
-// The time periods, in milliseconds, between successive polls of the wifi data. |
-extern const int kDefaultPollingInterval = 10000; // 10s |
-extern const int kNoChangePollingInterval = 120000; // 2 mins |
-extern const int kTwoNoChangePollingInterval = 600000; // 10 mins |
+namespace { |
+// The time periods between successive polls of the wifi data. |
+const int kDefaultPollingIntervalMilliseconds = 10 * 1000; // 10s |
+const int kNoChangePollingIntervalMilliseconds = 2 * 60 * 1000; // 2 mins |
+const int kTwoNoChangePollingIntervalMilliseconds = 10 * 60 * 1000; // 10 mins |
-// Local function |
-static bool GetAccessPointData(WifiData::AccessPointDataSet *access_points); |
+const char kNetworkManagerServiceName[] = "org.freedesktop.NetworkManager"; |
+const char kNetworkManagerPath[] = "/org/freedesktop/NetworkManager"; |
+const char kNetworkManagerInterface[] = "org.freedesktop.NetworkManager"; |
-// static |
-template<> |
-WifiDataProviderImplBase *WifiDataProvider::DefaultFactoryFunction() { |
- return new LinuxWifiDataProvider(); |
-} |
+// From http://projects.gnome.org/NetworkManager/developers/spec.html |
+enum { NM_DEVICE_TYPE_WIFI = 2 }; |
+// Utility wrappers to make various GLib & DBus structs into scoped objects. |
+class ScopedGPtrArrayFree { |
+ public: |
+ void operator()(GPtrArray* x) const { |
+ if (x) |
+ g_ptr_array_free(x, TRUE); |
+ } |
+}; |
+// Use ScopedGPtrArrayPtr as if it were scoped_ptr<GPtrArray> |
+typedef scoped_ptr_malloc<GPtrArray, ScopedGPtrArrayFree> ScopedGPtrArrayPtr; |
-LinuxWifiDataProvider::LinuxWifiDataProvider() |
- : is_first_scan_complete_(false) { |
- Start(); |
+class ScopedGObjectFree { |
+ public: |
+ void operator()(void* x) const { |
+ if (x) |
+ g_object_unref(x); |
+ } |
+}; |
+// Use ScopedDBusGProxyPtr as if it were scoped_ptr<DBusGProxy> |
+typedef scoped_ptr_malloc<DBusGProxy, ScopedGObjectFree> ScopedDBusGProxyPtr; |
+ |
+// Use ScopedGValue::v as an instance of GValue with automatic cleanup. |
+class ScopedGValue { |
+ public: |
+ ScopedGValue() |
+ : v(empty_gvalue()) { |
+ } |
+ ~ScopedGValue() { |
+ g_value_unset(&v); |
+ } |
+ static GValue empty_gvalue() { |
+ GValue value = {0}; |
+ return value; |
+ } |
+ |
+ GValue v; |
+}; |
+ |
+// Wifi API binding to NetworkManager, to allow reuse of the polling behavior |
+// defined in WifiDataProviderCommon. |
+// TODO(joth): NetworkManager also allows for notification based handling, |
+// however this will require reworking of the threading code to run a GLib |
+// event loop (GMainLoop). |
+class NetworkManagerWlanApi : public WifiDataProviderCommon::WlanApiInterface { |
+ public: |
+ NetworkManagerWlanApi(); |
+ ~NetworkManagerWlanApi(); |
+ |
+ // Must be called before any other interface method. Will return false if the |
+ // NetworkManager session cannot be created (e.g. not present on this distro), |
+ // in which case no other method may be called. |
+ bool Init(); |
+ |
+ // WifiDataProviderCommon::WlanApiInterface |
+ bool GetAccessPointData(WifiData::AccessPointDataSet* data); |
+ |
+ private: |
+ // Checks if the last dbus call returned an error. If it did, logs the error |
+ // message, frees it and returns true. |
+ // This must be called after every dbus call that accepts |&error_| |
+ bool CheckError(); |
+ |
+ // Enumerates the list of available network adapter devices known to |
+ // NetworkManager. Ownership of the array (and contained objects) is returned |
+ // to the caller. |
+ GPtrArray* GetAdapterDeviceList(); |
+ |
+ // Given the NetworkManager path to a wireless adapater, dumps the wifi scan |
+ // results and appends them to |data|. Returns false if a fatal error is |
+ // encountered such that the data set could not be populated. |
+ bool GetAccessPointsForAdapter(const gchar* adapter_path, |
+ WifiData::AccessPointDataSet* data); |
+ |
+ // Internal method used by |GetAccessPointsForAdapter|, given a wifi access |
+ // point proxy retrieves the named property into |value_out|. Returns false if |
+ // the property could not be read, or is not of type |expected_gvalue_type|. |
+ bool GetAccessPointProperty(DBusGProxy* proxy, const char* property_name, |
+ int expected_gvalue_type, GValue* value_out); |
+ |
+ // Error from the last dbus call. NULL when there's no error. Freed and |
+ // cleared by CheckError(). |
+ GError* error_; |
+ // Connection to the dbus system bus. |
+ DBusGConnection* connection_; |
+ // Proxy to the network maanger dbus service. |
+ ScopedDBusGProxyPtr proxy_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(NetworkManagerWlanApi); |
+}; |
+ |
+// Convert a wifi frequency to the corresponding channel. Adapted from |
+// geolocaiton/wifilib.cc in googleclient (internal to google). |
+int frquency_in_khz_to_channel(int frequency_khz) { |
+ if (frequency_khz >= 2412000 && frequency_khz <= 2472000) // Channels 1-13. |
+ return (frequency_khz - 2407000) / 5000; |
+ if (frequency_khz == 2484000) |
+ return 14; |
+ if (frequency_khz > 5000000 && frequency_khz < 6000000) // .11a bands. |
+ return (frequency_khz - 5000000) / 5000; |
+ // Ignore everything else. |
+ return AccessPointData().channel; // invalid channel |
} |
-LinuxWifiDataProvider::~LinuxWifiDataProvider() { |
- stop_event_.Signal(); |
- Join(); |
+NetworkManagerWlanApi::NetworkManagerWlanApi() |
+ : error_(NULL), connection_(NULL) { |
} |
-bool LinuxWifiDataProvider::GetData(WifiData *data) { |
- DCHECK(data); |
- MutexLock lock(&data_mutex_); |
- *data = wifi_data_; |
- // If we've successfully completed a scan, indicate that we have all of the |
- // data we can get. |
- return is_first_scan_complete_; |
+NetworkManagerWlanApi::~NetworkManagerWlanApi() { |
+ proxy_.reset(); |
+ if (connection_) { |
+ dbus_g_connection_unref(connection_); |
+ } |
+ DCHECK(!error_) << "Missing a call to CheckError() to clear |error_|"; |
} |
-// Thread implementation |
-void LinuxWifiDataProvider::Run() { |
- // Regularly get the access point data. |
- int polling_interval = kDefaultPollingInterval; |
- do { |
- WifiData new_data; |
- if (GetAccessPointData(&new_data.access_point_data)) { |
- bool update_available; |
- data_mutex_.Lock(); |
- update_available = wifi_data_.DiffersSignificantly(new_data); |
- wifi_data_ = new_data; |
- data_mutex_.Unlock(); |
- polling_interval = |
- UpdatePollingInterval(polling_interval, update_available); |
- if (update_available) { |
- is_first_scan_complete_ = true; |
- NotifyListeners(); |
- } |
+bool NetworkManagerWlanApi::Init() { |
+ // Chrome DLL init code handles initializing the thread system, so rather than |
+ // get caught up with that nonsense here, lets just assert our requirement. |
+ CHECK(g_thread_supported()); |
+ |
+ // We should likely do this higher up too, the docs say it must only be done |
+ // once but there's no way to know if it already was or not. |
+ dbus_g_thread_init(); |
+ |
+ // Get a connection to the session bus. |
+ connection_ = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error_); |
+ if (CheckError()) |
+ return false; |
+ DCHECK(connection_); |
+ |
+ proxy_.reset(dbus_g_proxy_new_for_name(connection_, |
+ kNetworkManagerServiceName, |
+ kNetworkManagerPath, |
+ kNetworkManagerInterface)); |
+ DCHECK(proxy_.get()); |
+ |
+ // Validate the proxy object by checking we can enumerate devices. |
+ ScopedGPtrArrayPtr device_list(GetAdapterDeviceList()); |
+ return !!device_list.get(); |
+} |
+ |
+bool NetworkManagerWlanApi::GetAccessPointData( |
+ WifiData::AccessPointDataSet* data) { |
+ ScopedGPtrArrayPtr device_list(GetAdapterDeviceList()); |
+ if (device_list == NULL) { |
+ DLOG(WARNING) << "Could not enumerate access points"; |
+ return false; |
+ } |
+ int success_count = 0; |
+ int fail_count = 0; |
+ |
+ // Iterate the devices, getting APs for each wireless adapter found |
+ for (guint i = 0; i < device_list->len; i++) { |
+ const gchar* device_path = |
+ reinterpret_cast<const gchar*>(g_ptr_array_index(device_list, i)); |
+ |
+ ScopedDBusGProxyPtr device_properties_proxy(dbus_g_proxy_new_from_proxy( |
+ proxy_.get(), DBUS_INTERFACE_PROPERTIES, device_path)); |
+ ScopedGValue device_type_g_value; |
+ dbus_g_proxy_call(device_properties_proxy.get(), "Get", &error_, |
+ G_TYPE_STRING, "org.freedesktop.NetworkManager.Device", |
+ G_TYPE_STRING, "DeviceType", |
+ G_TYPE_INVALID, |
+ G_TYPE_VALUE, &device_type_g_value.v, |
+ G_TYPE_INVALID); |
+ if (CheckError()) |
+ continue; |
+ |
+ const guint device_type = g_value_get_uint(&device_type_g_value.v); |
+ |
+ if (device_type == NM_DEVICE_TYPE_WIFI) { // Found a wlan adapter |
+ if (GetAccessPointsForAdapter(device_path, data)) |
+ ++success_count; |
+ else |
+ ++fail_count; |
} |
- } while (!stop_event_.WaitWithTimeout(polling_interval)); |
+ } |
+ // At least one successfull scan overrides any other adapter reporting error. |
+ return success_count || fail_count == 0; |
} |
-// Local functions |
+bool NetworkManagerWlanApi::CheckError() { |
+ if (error_) { |
+ LOG(ERROR) << "Failed to complete NetworkManager call: " << error_->message; |
+ g_error_free(error_); |
+ error_ = NULL; |
+ return true; |
+ } |
+ return false; |
+} |
-static bool IsValidMacAddress(const char *mac_address) { |
- return isxdigit(mac_address[0]) && |
- isxdigit(mac_address[1]) && |
- mac_address[2] == ':' && |
- isxdigit(mac_address[3]) && |
- isxdigit(mac_address[4]) && |
- mac_address[5] == ':' && |
- isxdigit(mac_address[6]) && |
- isxdigit(mac_address[7]) && |
- mac_address[8] == ':' && |
- isxdigit(mac_address[9]) && |
- isxdigit(mac_address[10]) && |
- mac_address[11] == ':' && |
- isxdigit(mac_address[12]) && |
- isxdigit(mac_address[13]) && |
- mac_address[14] == ':' && |
- isxdigit(mac_address[15]) && |
- isxdigit(mac_address[16]); |
+GPtrArray* NetworkManagerWlanApi::GetAdapterDeviceList() { |
+ GPtrArray* device_list = NULL; |
+ dbus_g_proxy_call(proxy_.get(), "GetDevices", &error_, |
+ G_TYPE_INVALID, |
+ dbus_g_type_get_collection("GPtrArray", |
+ DBUS_TYPE_G_OBJECT_PATH), |
+ &device_list, |
+ G_TYPE_INVALID); |
+ if (CheckError()) |
+ return NULL; |
+ return device_list; |
} |
-static void ParseLine(const std::string &line, |
- const std::string &mac_address_string, |
- const std::string &ssid_string, |
- const std::string &signal_strength_string, |
- AccessPointData *access_point_data) { |
- // Currently we get only MAC address, SSID and signal strength. |
- // TODO(steveblock): Work out how to get age, channel and signal-to-noise. |
- std::string::size_type index; |
- if ((index = line.find(mac_address_string)) != std::string::npos) { |
- // MAC address |
- if (IsValidMacAddress(&line.at(index + mac_address_string.size()))) { |
- UTF8ToString16(&line.at(index + mac_address_string.size()), |
- 17, // XX:XX:XX:XX:XX:XX |
- &access_point_data->mac_address); |
+bool NetworkManagerWlanApi::GetAccessPointsForAdapter( |
+ const gchar* adapter_path, WifiData::AccessPointDataSet* data) { |
+ DCHECK(proxy_.get()); |
+ |
+ // Create a proxy object for this wifi adapter, and ask it to do a scan |
+ // (or at least, dump its scan results). |
+ ScopedDBusGProxyPtr wifi_adapter_proxy(dbus_g_proxy_new_from_proxy( |
+ proxy_.get(), "org.freedesktop.NetworkManager.Device.Wireless", |
+ adapter_path)); |
+ |
+ GPtrArray* ap_list_raw = NULL; |
+ // Enumerate the access points for this adapter. |
+ dbus_g_proxy_call(wifi_adapter_proxy.get(), "GetAccessPoints", &error_, |
+ G_TYPE_INVALID, |
+ dbus_g_type_get_collection("GPtrArray", |
+ DBUS_TYPE_G_OBJECT_PATH), |
+ &ap_list_raw, |
+ G_TYPE_INVALID); |
+ ScopedGPtrArrayPtr ap_list(ap_list_raw); // Takes ownership. |
+ ap_list_raw = NULL; |
+ |
+ if (CheckError()) |
+ return false; |
+ |
+ DLOG(INFO) << "Wireless adapter " << adapter_path << " found " |
+ << ap_list->len << " access points."; |
+ |
+ for (guint i = 0; i < ap_list->len; i++) { |
+ const gchar* ap_path = |
+ reinterpret_cast<const gchar*>(g_ptr_array_index(ap_list, i)); |
+ ScopedDBusGProxyPtr access_point_proxy(dbus_g_proxy_new_from_proxy( |
+ proxy_.get(), DBUS_INTERFACE_PROPERTIES, ap_path)); |
+ |
+ AccessPointData access_point_data; |
+ { // Read SSID. |
+ ScopedGValue ssid_g_value; |
+ if (!GetAccessPointProperty(access_point_proxy.get(), "Ssid", |
+ G_TYPE_BOXED, &ssid_g_value.v)) |
+ continue; |
+ const GArray* ssid = |
+ reinterpret_cast<const GArray*>(g_value_get_boxed(&ssid_g_value.v)); |
+ UTF8ToUTF16(ssid->data, ssid->len, &access_point_data.ssid); |
} |
- } else if ((index = line.find(ssid_string)) != std::string::npos) { |
- // SSID |
- // The string should be quoted. |
- std::string::size_type start = index + ssid_string.size() + 1; |
- std::string::size_type end = line.find('\"', start); |
- // If we can't find a trailing quote, something has gone wrong. |
- if (end != std::string::npos) { |
- UTF8ToString16(&line.at(start), end - start, &access_point_data->ssid); |
+ |
+ { // Read the mac address |
+ ScopedGValue mac_g_value; |
+ if (!GetAccessPointProperty(access_point_proxy.get(), "HwAddress", |
+ G_TYPE_STRING, &mac_g_value.v)) |
+ continue; |
+ std::string mac = g_value_get_string(&mac_g_value.v); |
+ ReplaceSubstringsAfterOffset(&mac, 0U, ":", ""); |
+ std::vector<uint8> mac_bytes; |
+ if (!HexStringToBytes(mac, &mac_bytes) || mac_bytes.size() != 6) { |
+ DLOG(WARNING) << "Can't parse mac address (found " << mac_bytes.size() |
+ << " bytes) so using raw string: " << mac; |
+ access_point_data.mac_address = UTF8ToUTF16(mac); |
+ } else { |
+ access_point_data.mac_address = MacAddressAsString16(&mac_bytes[0]); |
+ } |
} |
- } else if ((index = line.find(signal_strength_string)) != std::string::npos) { |
- // Signal strength |
- // iwlist will convert to dBm if it can. If it has failed to do so, we can't |
- // make use of the data. |
- if (line.find("dBm") != std::string::npos) { |
- // atoi will ignore trailing non-numeric characters |
- access_point_data->radio_signal_strength = |
- atoi(&line.at(index + signal_strength_string.size())); |
+ |
+ { // Read signal strength. |
+ ScopedGValue signal_g_value; |
+ if (!GetAccessPointProperty(access_point_proxy.get(), "Strength", |
+ G_TYPE_UCHAR, &signal_g_value.v)) |
+ continue; |
+ // Convert strength as a percentage into dBs. |
+ access_point_data.radio_signal_strength = |
+ -100 + g_value_get_uchar(&signal_g_value.v) / 2; |
} |
+ |
+ { // Read the channel |
+ ScopedGValue freq_g_value; |
+ if (!GetAccessPointProperty(access_point_proxy.get(), "Frequency", |
+ G_TYPE_UINT, &freq_g_value.v)) |
+ continue; |
+ // NetworkManager returns frequency in MHz. |
+ access_point_data.channel = |
+ frquency_in_khz_to_channel(g_value_get_uint(&freq_g_value.v) * 1000); |
+ } |
+ data->insert(access_point_data); |
} |
+ return true; |
} |
-static void ParseAccessPoint(const std::string &text, |
- const std::string &mac_address_string, |
- const std::string &ssid_string, |
- const std::string &signal_strength_string, |
- AccessPointData *access_point_data) { |
- // Split response into lines to aid parsing. |
- std::string::size_type start = 0; |
- std::string::size_type end; |
- do { |
- end = text.find('\n', start); |
- std::string::size_type length = (end == std::string::npos) ? |
- std::string::npos : end - start; |
- ParseLine(text.substr(start, length), |
- mac_address_string, |
- ssid_string, |
- signal_strength_string, |
- access_point_data); |
- start = end + 1; |
- } while (end != std::string::npos); |
-} |
- |
-// Issues the specified command, and parses the response. Data for each access |
-// point is separated by the given delimiter. Within each block of data, the |
-// repsonse is split into lines and data is extracted by searching for the MAC |
-// address, SSID and signal strength strings. |
-bool IssueCommandAndParseResult(const char *command, |
- const char *delimiter, |
- const std::string &mac_address_string, |
- const std::string &ssid_string, |
- const std::string &signal_strength_string, |
- WifiData::AccessPointDataSet *access_points) { |
- // Open pipe in read mode. |
- FILE *result_pipe = popen(command, "r"); |
- if (result_pipe == NULL) { |
- LOG(("IssueCommand(): Failed to open pipe.\n")); |
+bool NetworkManagerWlanApi::GetAccessPointProperty(DBusGProxy* proxy, |
+ const char* property_name, |
+ int expected_gvalue_type, |
+ GValue* value_out) { |
+ dbus_g_proxy_call(proxy, "Get", &error_, |
+ G_TYPE_STRING, "org.freedesktop.NetworkManager.AccessPoint", |
+ G_TYPE_STRING, property_name, |
+ G_TYPE_INVALID, |
+ G_TYPE_VALUE, value_out, |
+ G_TYPE_INVALID); |
+ if (CheckError()) |
return false; |
+ if (!G_VALUE_HOLDS(value_out, expected_gvalue_type)) { |
+ DLOG(WARNING) << "Property " << property_name << " unexptected type " |
+ << G_VALUE_TYPE(value_out); |
+ return false; |
} |
+ return true; |
+} |
- // Read results of command. |
- static const int kBufferSize = 1024; |
- char buffer[kBufferSize]; |
- size_t bytes_read; |
- std::string result; |
- do { |
- bytes_read = fread(buffer, 1, kBufferSize, result_pipe); |
- result.append(buffer, bytes_read); |
- } while (static_cast<int>(bytes_read) == kBufferSize); |
- pclose(result_pipe); |
+} // namespace |
+// static |
+template<> |
+WifiDataProviderImplBase* WifiDataProvider::DefaultFactoryFunction() { |
+ return new WifiDataProviderLinux(); |
+} |
- // Parse results. |
- DCHECK(access_points); |
- access_points->clear(); |
- std::string::size_type start = result.find(delimiter); |
- while (start != std::string::npos) { |
- std::string::size_type end = result.find(delimiter, start + 1); |
- std::string::size_type length = (end == std::string::npos) ? |
- std::string::npos : end - start; |
- AccessPointData access_point_data; |
- ParseAccessPoint(result.substr(start, length), |
- mac_address_string, |
- ssid_string, |
- signal_strength_string, |
- &access_point_data); |
- access_points->insert(access_point_data); |
- start = end; |
- } |
+WifiDataProviderLinux::WifiDataProviderLinux() { |
+} |
- return !access_points->empty(); |
+WifiDataProviderLinux::~WifiDataProviderLinux() { |
} |
-static bool GetAccessPointData(WifiData::AccessPointDataSet *access_points) { |
- return IssueCommandAndParseResult("iwlist scan 2> /dev/null", |
- "Cell ", |
- "Address: ", |
- "ESSID:", |
- "Signal level=", |
- access_points) || |
- IssueCommandAndParseResult("iwconfig 2> /dev/null", |
- "ESSID:\"", |
- "Access Point: ", |
- "ESSID:", |
- "Signal level=", |
- access_points); |
+WifiDataProviderCommon::WlanApiInterface* |
+WifiDataProviderLinux::NewWlanApi() { |
+ scoped_ptr<NetworkManagerWlanApi> wlan_api(new NetworkManagerWlanApi); |
+ if (wlan_api->Init()) |
+ return wlan_api.release(); |
+ return NULL; |
} |
-#endif // 0 |
+PollingPolicyInterface* WifiDataProviderLinux::NewPollingPolicy() { |
+ return new GenericPollingPolicy<kDefaultPollingIntervalMilliseconds, |
+ kNoChangePollingIntervalMilliseconds, |
+ kTwoNoChangePollingIntervalMilliseconds>; |
+} |
+ |