diff options
author | satorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-25 21:26:17 +0000 |
---|---|---|
committer | satorux@chromium.org <satorux@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-08-25 21:26:17 +0000 |
commit | 34168967957a98806999ed30da341823e973dda4 (patch) | |
tree | 8beadb9e42239690818122db652e8253412ab4a4 | |
parent | 0e935c74fd6ca38866df63af66dc535497172950 (diff) | |
download | chromium_src-34168967957a98806999ed30da341823e973dda4.zip chromium_src-34168967957a98806999ed30da341823e973dda4.tar.gz chromium_src-34168967957a98806999ed30da341823e973dda4.tar.bz2 |
Rework wifi_data_provider_linux.cc with our D-Bus library.
The code is now a lot simpler, and unit tested.
The dlopen hack and the timeout hack are now gone.
BUG=90036
TEST=confirm that the geolocation works on maps.google.com on a device with wifi network
Review URL: http://codereview.chromium.org/7725001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@98307 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/chrome_tests.gypi | 4 | ||||
-rw-r--r-- | content/DEPS | 1 | ||||
-rw-r--r-- | content/browser/geolocation/wifi_data_provider_linux.cc | 453 | ||||
-rw-r--r-- | content/browser/geolocation/wifi_data_provider_linux.h | 9 | ||||
-rw-r--r-- | content/browser/geolocation/wifi_data_provider_linux_unittest.cc | 221 | ||||
-rw-r--r-- | content/content_browser.gypi | 3 |
6 files changed, 437 insertions, 254 deletions
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 74e60db..d7ca942 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -2009,6 +2009,7 @@ '../content/browser/geolocation/location_arbitrator_unittest.cc', '../content/browser/geolocation/network_location_provider_unittest.cc', '../content/browser/geolocation/wifi_data_provider_common_unittest.cc', + '../content/browser/geolocation/wifi_data_provider_linux_unittest.cc', '../content/browser/geolocation/wifi_data_provider_unittest_win.cc', '../content/browser/geolocation/win7_location_api_unittest_win.cc', '../content/browser/geolocation/win7_location_provider_unittest_win.cc', @@ -2086,6 +2087,7 @@ ['chromeos==1', { 'sources/': [ ['exclude', '^browser/password_manager/native_backend_gnome_x_unittest.cc'], + ['exclude', '^../content/browser/geolocation/wifi_data_provider_linux_unittest.cc'], # TODO(thestig) Enable PrintPreviewUI tests on CrOS when # print preview is enabled on CrOS. ['exclude', '^browser/ui/webui/print_preview_ui_unittest.cc'], @@ -2136,8 +2138,10 @@ }], ], 'dependencies': [ + '../build/linux/system.gyp:dbus', '../build/linux/system.gyp:gtk', '../build/linux/system.gyp:ssl', + '../dbus/dbus.gyp:dbus_test_support', '../tools/xdisplaycheck/xdisplaycheck.gyp:xdisplaycheck', ], 'sources!': [ diff --git a/content/DEPS b/content/DEPS index 24476e0..b05fedd 100644 --- a/content/DEPS +++ b/content/DEPS @@ -21,6 +21,7 @@ include_rules = [ "+content/common", "+content/test", + "+dbus", "+grit", "+gpu", "+net", diff --git a/content/browser/geolocation/wifi_data_provider_linux.cc b/content/browser/geolocation/wifi_data_provider_linux.cc index c1a6a04..178260a 100644 --- a/content/browser/geolocation/wifi_data_provider_linux.cc +++ b/content/browser/geolocation/wifi_data_provider_linux.cc @@ -8,15 +8,12 @@ #include "content/browser/geolocation/wifi_data_provider_linux.h" -#include <dbus/dbus-glib.h> -#include <dbus/dbus-glib-lowlevel.h> -#include <dbus/dbus.h> -#include <dlfcn.h> -#include <glib.h> - #include "base/memory/scoped_ptr.h" #include "base/string_number_conversions.h" #include "base/utf_string_conversions.h" +#include "dbus/bus.h" +#include "dbus/message.h" +#include "dbus/object_proxy.h" namespace { // The time periods between successive polls of the wifi data. @@ -32,67 +29,6 @@ const char kNetworkManagerInterface[] = "org.freedesktop.NetworkManager"; // From http://projects.gnome.org/NetworkManager/developers/spec.html enum { NM_DEVICE_TYPE_WIFI = 2 }; -// Function type matching dbus_g_bus_get_private so that we can -// dynamically determine the presence of this symbol (see -// NetworkManagerWlanApi::Init) -typedef DBusGConnection* DBusGBusGetPrivateFunc( - DBusBusType type, GMainContext* context, GError** error); - -// 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; - -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; -}; - -// Use ScopedDLHandle to automatically clean up after dlopen. -class ScopedDLHandle { - public: - ScopedDLHandle(void* handle) - : handle_(handle) { - } - ~ScopedDLHandle() { - if (handle_) - dlclose(handle_); - } - void* get() { - return handle_; - } - private: - void *handle_; -}; - // Wifi API binding to NetworkManager, to allow reuse of the polling behavior // defined in WifiDataProviderCommon. // TODO(joth): NetworkManager also allows for notification based handling, @@ -108,41 +44,34 @@ class NetworkManagerWlanApi : public WifiDataProviderCommon::WlanApiInterface { // in which case no other method may be called. bool Init(); + // Similar to Init() but can inject the bus object. Used for testing. + bool InitWithBus(dbus::Bus* bus); + // WifiDataProviderCommon::WlanApiInterface - bool GetAccessPointData(WifiData::AccessPointDataSet* data); + // + // This function makes blocking D-Bus calls, but it's totally fine as + // the code runs in "Geolocation" thread, not the browser's UI thread. + virtual 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(); + // NetworkManager. Return true on success. + bool GetAdapterDeviceList(std::vector<std::string>* device_paths); // 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, + bool GetAccessPointsForAdapter(const std::string& 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_; - // Main context - GMainContext* context_; - // Proxy to the network manager dbus service. - ScopedDBusGProxyPtr proxy_; + // point proxy retrieves the named property and returns it. Returns NULL if + // the property could not be read. + dbus::Response* GetAccessPointProperty(dbus::ObjectProxy* proxy, + const std::string& property_name); + + scoped_refptr<dbus::Bus> system_bus_; + dbus::ObjectProxy* network_manager_proxy_; DISALLOW_COPY_AND_ASSIGN(NetworkManagerWlanApi); }; @@ -161,102 +90,73 @@ int frquency_in_khz_to_channel(int frequency_khz) { } NetworkManagerWlanApi::NetworkManagerWlanApi() - : error_(NULL), - connection_(NULL), - context_(NULL) -{ + : network_manager_proxy_(NULL) { } NetworkManagerWlanApi::~NetworkManagerWlanApi() { - proxy_.reset(); - if (connection_) { - dbus_connection_close(dbus_g_connection_get_connection(connection_)); - dbus_g_connection_unref(connection_); - } - if (context_) - g_main_context_unref(context_); - - DCHECK(!error_) << "Missing a call to CheckError() to clear |error_|"; + // Close the connection. + system_bus_->ShutdownAndBlock(); } 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 require a private bus to ensure that we don't interfere with the - // default loop on the main thread. Unforunately this functionality is only - // available in dbus-glib-0.84 and later. We do a dynamic symbol lookup - // to determine if dbus_g_bus_get_private is available. See bug - // http://code.google.com/p/chromium/issues/detail?id=59913 for more - // information. - ScopedDLHandle handle(dlopen(NULL, RTLD_LAZY)); - if (!handle.get()) - return false; - - DBusGBusGetPrivateFunc *my_dbus_g_bus_get_private = - (DBusGBusGetPrivateFunc *) dlsym(handle.get(), "dbus_g_bus_get_private"); - - if (!my_dbus_g_bus_get_private) { - LOG(ERROR) << "We need dbus-glib >= 0.84 for wifi geolocation."; - return false; - } - // Get a private connection to the session bus. - context_ = g_main_context_new(); - DCHECK(context_); - connection_ = my_dbus_g_bus_get_private(DBUS_BUS_SYSTEM, context_, &error_); - - if (CheckError()) - return false; - DCHECK(connection_); - - // Disable timers on the connection since we don't need them and - // we're not going to run them anyway as the connection is associated - // with a private context. See bug http://crbug.com/40803 - dbus_bool_t ok = dbus_connection_set_timeout_functions( - dbus_g_connection_get_connection(connection_), - NULL, NULL, NULL, NULL, NULL); - DCHECK(ok); - - proxy_.reset(dbus_g_proxy_new_for_name(connection_, - kNetworkManagerServiceName, - kNetworkManagerPath, - kNetworkManagerInterface)); - DCHECK(proxy_.get()); + dbus::Bus::Options options; + options.bus_type = dbus::Bus::SYSTEM; + options.connection_type = dbus::Bus::PRIVATE; + return InitWithBus(new dbus::Bus(options)); +} +bool NetworkManagerWlanApi::InitWithBus(dbus::Bus* bus) { + system_bus_ = bus; + // system_bus_ will own all object proxies created from the bus. + network_manager_proxy_ = + system_bus_->GetObjectProxy(kNetworkManagerServiceName, + kNetworkManagerPath); // Validate the proxy object by checking we can enumerate devices. - ScopedGPtrArrayPtr device_list(GetAdapterDeviceList()); - return !!device_list.get(); + std::vector<std::string> adapter_paths; + const bool success = GetAdapterDeviceList(&adapter_paths); + VLOG(1) << "Init() result: " << success; + return success; } bool NetworkManagerWlanApi::GetAccessPointData( WifiData::AccessPointDataSet* data) { - ScopedGPtrArrayPtr device_list(GetAdapterDeviceList()); - if (device_list == NULL) { - DLOG(WARNING) << "Could not enumerate access points"; + std::vector<std::string> device_paths; + if (!GetAdapterDeviceList(&device_paths)) { + LOG(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); + for (size_t i = 0; i < device_paths.size(); ++i) { + const std::string& device_path = device_paths[i]; + VLOG(1) << "Checking device: " << device_path; + + dbus::ObjectProxy* device_proxy = + system_bus_->GetObjectProxy(kNetworkManagerServiceName, + device_path); + + dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get"); + dbus::MessageWriter builder(&method_call); + builder.AppendString("org.freedesktop.NetworkManager.Device"); + builder.AppendString("DeviceType"); + scoped_ptr<dbus::Response> response( + device_proxy->CallMethodAndBlock( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); + if (!response.get()) { + LOG(WARNING) << "Failed to get the device type for " << device_path; + continue; // Check the next device. + } + dbus::MessageReader reader(response.get()); + uint32 device_type = 0; + if (!reader.PopVariantOfUint32(&device_type)) { + LOG(WARNING) << "Unexpected response for " << device_type << ": " + << response->ToString(); + continue; // Check the next device. + } + VLOG(1) << "Device type: " << device_type; if (device_type == NM_DEVICE_TYPE_WIFI) { // Found a wlan adapter if (GetAccessPointsForAdapter(device_path, data)) @@ -269,84 +169,107 @@ bool NetworkManagerWlanApi::GetAccessPointData( return success_count || fail_count == 0; } -bool NetworkManagerWlanApi::CheckError() { - if (error_) { - LOG(ERROR) << "Failed to complete NetworkManager call: " << error_->message; - g_error_free(error_); - error_ = NULL; - return true; +bool NetworkManagerWlanApi::GetAdapterDeviceList( + std::vector<std::string>* device_paths) { + dbus::MethodCall method_call(kNetworkManagerInterface, "GetDevices"); + scoped_ptr<dbus::Response> response( + network_manager_proxy_->CallMethodAndBlock( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); + if (!response.get()) { + LOG(WARNING) << "Failed to get the device list"; + return false; } - return false; -} -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; + dbus::MessageReader reader(response.get()); + if (!reader.PopArrayOfObjectPaths(device_paths)) { + LOG(WARNING) << "Unexpected response: " << response->ToString(); + return false; + } + return true; } -bool NetworkManagerWlanApi::GetAccessPointsForAdapter( - const gchar* adapter_path, WifiData::AccessPointDataSet* data) { - DCHECK(proxy_.get()); +bool NetworkManagerWlanApi::GetAccessPointsForAdapter( + const std::string& adapter_path, WifiData::AccessPointDataSet* data) { // 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()) + dbus::ObjectProxy* device_proxy = + system_bus_->GetObjectProxy(kNetworkManagerServiceName, + adapter_path); + dbus::MethodCall method_call( + "org.freedesktop.NetworkManager.Device.Wireless", + "GetAccessPoints"); + scoped_ptr<dbus::Response> response( + device_proxy->CallMethodAndBlock( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT)); + if (!response.get()) { + LOG(WARNING) << "Failed to get access points data for " << adapter_path; + return false; + } + dbus::MessageReader reader(response.get()); + std::vector<std::string> access_point_paths; + if (!reader.PopArrayOfObjectPaths(&access_point_paths)) { + LOG(WARNING) << "Unexpected response for " << adapter_path << ": " + << response->ToString(); return false; + } + + VLOG(1) << "Wireless adapter " << adapter_path << " found " + << access_point_paths.size() << " access points."; - DVLOG(1) << "Wireless adapter " << adapter_path << " found " << ap_list->len - << " access points."; + for (size_t i = 0; i < access_point_paths.size(); ++i) { + const std::string& access_point_path = access_point_paths[i]; + VLOG(1) << "Checking access point: " << access_point_path; - 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)); + dbus::ObjectProxy* access_point_proxy = + system_bus_->GetObjectProxy(kNetworkManagerServiceName, + access_point_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)) + { + scoped_ptr<dbus::Response> response( + GetAccessPointProperty(access_point_proxy, "Ssid")); + if (!response.get()) 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); + // The response should contain a variant that contains an array of bytes. + dbus::MessageReader reader(response.get()); + dbus::MessageReader variant_reader(response.get()); + if (!reader.PopVariant(&variant_reader)) { + LOG(WARNING) << "Unexpected response for " << access_point_path << ": " + << response->ToString(); + continue; + } + uint8* ssid_bytes = NULL; + size_t ssid_length = 0; + if (!variant_reader.PopArrayOfBytes(&ssid_bytes, &ssid_length)) { + LOG(WARNING) << "Unexpected response for " << access_point_path << ": " + << response->ToString(); + continue; + } + std::string ssid(ssid_bytes, ssid_bytes + ssid_length); + access_point_data.ssid = UTF8ToUTF16(ssid); } { // Read the mac address - ScopedGValue mac_g_value; - if (!GetAccessPointProperty(access_point_proxy.get(), "HwAddress", - G_TYPE_STRING, &mac_g_value.v)) + scoped_ptr<dbus::Response> response( + GetAccessPointProperty(access_point_proxy, "HwAddress")); + if (!response.get()) continue; - std::string mac = g_value_get_string(&mac_g_value.v); + dbus::MessageReader reader(response.get()); + std::string mac; + if (!reader.PopVariantOfString(&mac)) { + LOG(WARNING) << "Unexpected response for " << access_point_path << ": " + << response->ToString(); + continue; + } + ReplaceSubstringsAfterOffset(&mac, 0U, ":", ""); std::vector<uint8> mac_bytes; if (!base::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; + LOG(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]); @@ -354,47 +277,63 @@ bool NetworkManagerWlanApi::GetAccessPointsForAdapter( } { // Read signal strength. - ScopedGValue signal_g_value; - if (!GetAccessPointProperty(access_point_proxy.get(), "Strength", - G_TYPE_UCHAR, &signal_g_value.v)) + scoped_ptr<dbus::Response> response( + GetAccessPointProperty(access_point_proxy, "Strength")); + if (!response.get()) continue; + dbus::MessageReader reader(response.get()); + uint8 strength = 0; + if (!reader.PopVariantOfByte(&strength)) { + LOG(WARNING) << "Unexpected response for " << access_point_path << ": " + << response->ToString(); + continue; + } // Convert strength as a percentage into dBs. - access_point_data.radio_signal_strength = - -100 + g_value_get_uchar(&signal_g_value.v) / 2; + access_point_data.radio_signal_strength = -100 + strength / 2; } { // Read the channel - ScopedGValue freq_g_value; - if (!GetAccessPointProperty(access_point_proxy.get(), "Frequency", - G_TYPE_UINT, &freq_g_value.v)) + scoped_ptr<dbus::Response> response( + GetAccessPointProperty(access_point_proxy, "Frequency")); + if (!response.get()) continue; + dbus::MessageReader reader(response.get()); + uint32 frequency = 0; + if (!reader.PopVariantOfUint32(&frequency)) { + LOG(WARNING) << "Unexpected response for " << access_point_path << ": " + << response->ToString(); + continue; + } + // NetworkManager returns frequency in MHz. access_point_data.channel = - frquency_in_khz_to_channel(g_value_get_uint(&freq_g_value.v) * 1000); + frquency_in_khz_to_channel(frequency * 1000); } + VLOG(1) << "Access point data of " << access_point_path << ": " + << "SSID: " << access_point_data.ssid << ", " + << "MAC: " << access_point_data.mac_address << ", " + << "Strength: " << access_point_data.radio_signal_strength << ", " + << "Channel: " << access_point_data.channel; + data->insert(access_point_data); } return true; } -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; +dbus::Response* NetworkManagerWlanApi::GetAccessPointProperty( + dbus::ObjectProxy* access_point_proxy, + const std::string& property_name) { + dbus::MethodCall method_call(DBUS_INTERFACE_PROPERTIES, "Get"); + dbus::MessageWriter builder(&method_call); + builder.AppendString("org.freedesktop.NetworkManager.AccessPoint"); + builder.AppendString(property_name); + dbus::Response* response = access_point_proxy->CallMethodAndBlock( + &method_call, + dbus::ObjectProxy::TIMEOUT_USE_DEFAULT); + if (!response) { + LOG(WARNING) << "Failed to get property for " << property_name; } - return true; + return response; } } // namespace @@ -425,3 +364,11 @@ PollingPolicyInterface* WifiDataProviderLinux::NewPollingPolicy() { kTwoNoChangePollingIntervalMilliseconds, kNoWifiPollingIntervalMilliseconds>; } + +WifiDataProviderCommon::WlanApiInterface* +WifiDataProviderLinux::NewWlanApiForTesting(dbus::Bus* bus) { + scoped_ptr<NetworkManagerWlanApi> wlan_api(new NetworkManagerWlanApi); + if (wlan_api->InitWithBus(bus)) + return wlan_api.release(); + return NULL; +} diff --git a/content/browser/geolocation/wifi_data_provider_linux.h b/content/browser/geolocation/wifi_data_provider_linux.h index 978bd8f..434e6e5 100644 --- a/content/browser/geolocation/wifi_data_provider_linux.h +++ b/content/browser/geolocation/wifi_data_provider_linux.h @@ -8,17 +8,26 @@ #include "content/browser/geolocation/wifi_data_provider_common.h" +namespace dbus { +class Bus; +}; + class WifiDataProviderLinux : public WifiDataProviderCommon { public: WifiDataProviderLinux(); private: + friend class GeolocationWifiDataProviderLinuxTest; + virtual ~WifiDataProviderLinux(); // WifiDataProviderCommon virtual WlanApiInterface* NewWlanApi(); virtual PollingPolicyInterface* NewPollingPolicy(); + // For testing. + WlanApiInterface* NewWlanApiForTesting(dbus::Bus* bus); + DISALLOW_COPY_AND_ASSIGN(WifiDataProviderLinux); }; diff --git a/content/browser/geolocation/wifi_data_provider_linux_unittest.cc b/content/browser/geolocation/wifi_data_provider_linux_unittest.cc new file mode 100644 index 0000000..e5a39b9 --- /dev/null +++ b/content/browser/geolocation/wifi_data_provider_linux_unittest.cc @@ -0,0 +1,221 @@ +// Copyright (c) 2011 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 "content/browser/geolocation/wifi_data_provider_linux.h" + +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/utf_string_conversions.h" +#include "dbus/message.h" +#include "dbus/mock_bus.h" +#include "dbus/mock_object_proxy.h" +#include "dbus/object_proxy.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using ::testing::_; +using ::testing::Invoke; +using ::testing::Return; +using ::testing::Unused; + +class GeolocationWifiDataProviderLinuxTest : public testing::Test { + void SetUp() { + // Create a mock bus. + dbus::Bus::Options options; + options.bus_type = dbus::Bus::SYSTEM; + mock_bus_ = new dbus::MockBus(options); + + // Create a mock proxy that behaves as NetworkManager. + mock_network_manager_proxy_ = + new dbus::MockObjectProxy(mock_bus_.get(), + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager"); + // Set an expectation so mock_network_manager_proxy_'s + // CallMethodAndBlock() will use CreateNetowrkManagerProxyResponse() + // to return responses. + EXPECT_CALL(*mock_network_manager_proxy_, + CallMethodAndBlock(_, _)) + .WillRepeatedly(Invoke( + this, + &GeolocationWifiDataProviderLinuxTest:: + CreateNetowrkManagerProxyResponse)); + + // Create a mock proxy that behaves as NetworkManager/Devices/0. + mock_device_proxy_ = + new dbus::MockObjectProxy(mock_bus_.get(), + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager/Devices/0"); + EXPECT_CALL(*mock_device_proxy_, + CallMethodAndBlock(_, _)) + .WillRepeatedly(Invoke( + this, + &GeolocationWifiDataProviderLinuxTest::CreateDeviceProxyResponse)); + + // Create a mock proxy that behaves as NetworkManager/AccessPoint/0. + mock_access_point_proxy_ = + new dbus::MockObjectProxy( + mock_bus_.get(), + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager/AccessPoint/0"); + EXPECT_CALL(*mock_access_point_proxy_, + CallMethodAndBlock(_, _)) + .WillRepeatedly(Invoke( + this, + &GeolocationWifiDataProviderLinuxTest:: + CreateAccessPointProxyResponse)); + + // Set an expectation so mock_bus_'s GetObjectProxy() for the given + // service name and the object path will return + // mock_network_manager_proxy_. + EXPECT_CALL(*mock_bus_, GetObjectProxy( + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager")) + .WillOnce(Return(mock_network_manager_proxy_.get())); + // Likewise, set an expectation for mock_device_proxy_. + EXPECT_CALL(*mock_bus_, GetObjectProxy( + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager/Devices/0")) + .WillOnce(Return(mock_device_proxy_.get())) + .WillOnce(Return(mock_device_proxy_.get())); + // Likewise, set an expectation for mock_access_point_proxy_. + EXPECT_CALL(*mock_bus_, GetObjectProxy( + "org.freedesktop.NetworkManager", + "/org/freedesktop/NetworkManager/AccessPoint/0")) + .WillOnce(Return(mock_access_point_proxy_.get())); + + // ShutdownAndBlock() should be called. + EXPECT_CALL(*mock_bus_, ShutdownAndBlock()).WillOnce(Return()); + + // Create the wlan API with the mock bus object injected. + wifi_provider_linux_ = new WifiDataProviderLinux; + wlan_api_.reset( + wifi_provider_linux_->NewWlanApiForTesting(mock_bus_.get())); + ASSERT_TRUE(wlan_api_.get()); + } + + protected: + // DeviceDataProviderImplBase, a super class of WifiDataProviderLinux, + // requires a message loop to be present. message_loop_ is defined here, + // as it should outlive wifi_provider_linux_. + MessageLoop message_loop_; + scoped_refptr<dbus::MockBus> mock_bus_; + scoped_refptr<dbus::MockObjectProxy> mock_network_manager_proxy_; + scoped_refptr<dbus::MockObjectProxy> mock_access_point_proxy_; + scoped_refptr<dbus::MockObjectProxy> mock_device_proxy_; + scoped_refptr<WifiDataProviderLinux> wifi_provider_linux_; + scoped_ptr<WifiDataProviderCommon::WlanApiInterface> wlan_api_; + + private: + // Creates a response for |mock_network_manager_proxy_|. + dbus::Response* CreateNetowrkManagerProxyResponse( + dbus::MethodCall* method_call, + Unused) { + if (method_call->GetInterface() == "org.freedesktop.NetworkManager" && + method_call->GetMember() == "GetDevices") { + // The list of devices is asked. Return the object path. + std::vector<std::string> object_paths; + object_paths.push_back("/org/freedesktop/NetworkManager/Devices/0"); + + dbus::Response* response = dbus::Response::CreateEmpty(); + dbus::MessageWriter writer(response); + writer.AppendArrayOfObjectPaths(object_paths); + return response; + } + + LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); + return NULL; + } + + // Creates a response for |mock_device_proxy_|. + dbus::Response* CreateDeviceProxyResponse(dbus::MethodCall* method_call, + Unused) { + if (method_call->GetInterface() == DBUS_INTERFACE_PROPERTIES && + method_call->GetMember() == "Get") { + dbus::MessageReader reader(method_call); + std::string interface_name; + std::string property_name; + if (reader.PopString(&interface_name) && + reader.PopString(&property_name)) { + // The device type is asked. Respond that the device type is wifi. + dbus::Response* response = dbus::Response::CreateEmpty(); + dbus::MessageWriter writer(response); + // This matches NM_DEVICE_TYPE_WIFI in wifi_data_provider_linux.cc. + const int kDeviceTypeWifi = 2; + writer.AppendVariantOfUint32(kDeviceTypeWifi); + return response; + } + } else if (method_call->GetInterface() == + "org.freedesktop.NetworkManager.Device.Wireless" && + method_call->GetMember() == "GetAccessPoints") { + // The list of access points is asked. Return the object path. + dbus::Response* response = dbus::Response::CreateEmpty(); + dbus::MessageWriter writer(response); + std::vector<std::string> object_paths; + object_paths.push_back("/org/freedesktop/NetworkManager/AccessPoint/0"); + writer.AppendArrayOfObjectPaths(object_paths); + return response; + } + + LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); + return NULL; + } + + + // Creates a response for |mock_access_point_proxy_|. + dbus::Response* CreateAccessPointProxyResponse(dbus::MethodCall* method_call, + Unused) { + if (method_call->GetInterface() == DBUS_INTERFACE_PROPERTIES && + method_call->GetMember() == "Get") { + dbus::MessageReader reader(method_call); + + std::string interface_name; + std::string property_name; + if (reader.PopString(&interface_name) && + reader.PopString(&property_name)) { + dbus::Response* response = dbus::Response::CreateEmpty(); + dbus::MessageWriter writer(response); + + if (property_name == "Ssid") { + const uint8 kSsid[] = {0x74, 0x65, 0x73, 0x74}; // "test" + dbus::MessageWriter variant_writer(response); + writer.OpenVariant("ay", &variant_writer); + variant_writer.AppendArrayOfBytes(kSsid, arraysize(kSsid)); + writer.CloseContainer(&variant_writer); + } else if (property_name == "HwAddress") { + // This will be converted to "00-11-22-33-44-55". + const std::string kMacAddress = "00:11:22:33:44:55"; + writer.AppendVariantOfString(kMacAddress); + } else if (property_name == "Strength") { + // This will be converted to -50. + const uint8 kStrength = 100; + writer.AppendVariantOfByte(kStrength); + } else if (property_name == "Frequency") { + // This will be converted to channel 4. + const uint32 kFrequency = 2427; + writer.AppendVariantOfUint32(kFrequency); + } + return response; + } + } + + LOG(ERROR) << "Unexpected method call: " << method_call->ToString(); + return NULL; + } +}; + +TEST_F(GeolocationWifiDataProviderLinuxTest, GetAccessPointData) { + WifiData::AccessPointDataSet access_point_data_set; + ASSERT_TRUE(wlan_api_->GetAccessPointData(&access_point_data_set)); + + ASSERT_EQ(1U, access_point_data_set.size()); + AccessPointData access_point_data = *access_point_data_set.begin(); + + // Check the contents of the access point data. + // The expected values come from CreateAccessPointProxyResponse() above. + EXPECT_EQ("test", UTF16ToUTF8(access_point_data.ssid)); + EXPECT_EQ("00-11-22-33-44-55", UTF16ToUTF8(access_point_data.mac_address)); + EXPECT_EQ(-50, access_point_data.radio_signal_strength); + EXPECT_EQ(4, access_point_data.channel); +} diff --git a/content/content_browser.gypi b/content/content_browser.gypi index db946e5..93880eb 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi @@ -560,12 +560,13 @@ }], ['toolkit_uses_gtk == 1', { 'dependencies': [ - '../build/linux/system.gyp:dbus-glib', + '../build/linux/system.gyp:dbus', # For FcLangSetAdd call in render_sandbox_host_linux.cc '../build/linux/system.gyp:fontconfig', '../build/linux/system.gyp:gtk', # For XShm* in backing_store_x.cc '../build/linux/system.gyp:x11', + '../dbus/dbus.gyp:dbus', ], }], ['OS=="linux" and chromeos==1', { |