diff options
author | stevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-09 02:21:19 +0000 |
---|---|---|
committer | stevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-09 02:21:19 +0000 |
commit | da42a133bc46ac23d34f32007d75932a6fffa1b2 (patch) | |
tree | 57c42eb21b7b560a01ffbe701474cfdbd1c3c43c /chromeos/network | |
parent | 227c1a12c4f4e741f29fcc6e56bf86a94188fadd (diff) | |
download | chromium_src-da42a133bc46ac23d34f32007d75932a6fffa1b2.zip chromium_src-da42a133bc46ac23d34f32007d75932a6fffa1b2.tar.gz chromium_src-da42a133bc46ac23d34f32007d75932a6fffa1b2.tar.bz2 |
Add NetworkDeviceHandler
This will track Shill Device info, including Wifi access point data.
BUG=167987
Review URL: https://chromiumcodereview.appspot.com/11743006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175673 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chromeos/network')
-rw-r--r-- | chromeos/network/network_device_handler.cc | 216 | ||||
-rw-r--r-- | chromeos/network/network_device_handler.h | 103 | ||||
-rw-r--r-- | chromeos/network/network_device_handler_unittest.cc | 136 |
3 files changed, 455 insertions, 0 deletions
diff --git a/chromeos/network/network_device_handler.cc b/chromeos/network/network_device_handler.cc new file mode 100644 index 0000000..6524459 --- /dev/null +++ b/chromeos/network/network_device_handler.cc @@ -0,0 +1,216 @@ +// Copyright (c) 2012 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 "chromeos/network/network_device_handler.h" + +#include "base/bind.h" +#include "base/values.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/shill_device_client.h" +#include "chromeos/dbus/shill_manager_client.h" +#include "chromeos/dbus/shill_network_client.h" +#include "chromeos/network/network_event_log.h" +#include "dbus/object_path.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace chromeos { + +//------------------------------------------------------------------------------ +// NetworkDeviceHandler public methods + +NetworkDeviceHandler::NetworkDeviceHandler() + : devices_ready_(false), + weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) { +} + +NetworkDeviceHandler::~NetworkDeviceHandler() { + DBusThreadManager::Get()->GetShillManagerClient()-> + RemovePropertyChangedObserver(this); +} + +void NetworkDeviceHandler::Init() { + ShillManagerClient* shill_manager = + DBusThreadManager::Get()->GetShillManagerClient(); + shill_manager->GetProperties( + base::Bind(&NetworkDeviceHandler::ManagerPropertiesCallback, + weak_ptr_factory_.GetWeakPtr())); + shill_manager->AddPropertyChangedObserver(this); +} + +void NetworkDeviceHandler::AddObserver(Observer* observer) { + observers_.AddObserver(observer); +} + +void NetworkDeviceHandler::RemoveObserver(Observer* observer) { + observers_.RemoveObserver(observer); +} + +//------------------------------------------------------------------------------ +// ShillPropertyChangedObserver overrides + +void NetworkDeviceHandler::OnPropertyChanged(const std::string& key, + const base::Value& value) { + if (key != flimflam::kDevicesProperty) + return; + const base::ListValue* devices = NULL; + if (!value.GetAsList(&devices)) { + LOG(ERROR) << "Failed to parse Devices property."; + return; + } + DevicePropertyChanged(devices); +} + +//------------------------------------------------------------------------------ +// Private methods + +void NetworkDeviceHandler::ManagerPropertiesCallback( + DBusMethodCallStatus call_status, + const base::DictionaryValue& properties) { + if (call_status != DBUS_METHOD_CALL_SUCCESS) { + LOG(ERROR) << "Failed to get Manager properties: " << call_status; + return; + } + const base::ListValue* devices = NULL; + if (!properties.GetListWithoutPathExpansion( + flimflam::kDevicesProperty, &devices)) { + LOG(WARNING) << "Devices property not found"; + return; + } + DevicePropertyChanged(devices); +} + +void NetworkDeviceHandler::DevicePropertyChanged( + const base::ListValue* devices) { + DCHECK(devices); + devices_ready_ = false; + devices_.clear(); + pending_device_paths_.clear(); + for (size_t i = 0; i < devices->GetSize(); i++) { + std::string device_path; + if (!devices->GetString(i, &device_path)) { + LOG(WARNING) << "Failed to parse device[" << i << "]"; + continue; + } + pending_device_paths_.insert(device_path); + DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties( + dbus::ObjectPath(device_path), + base::Bind(&NetworkDeviceHandler::DevicePropertiesCallback, + weak_ptr_factory_.GetWeakPtr(), + device_path)); + } +} + +void NetworkDeviceHandler::DevicePropertiesCallback( + const std::string& device_path, + DBusMethodCallStatus call_status, + const base::DictionaryValue& properties) { + if (call_status != DBUS_METHOD_CALL_SUCCESS) { + LOG(ERROR) << "Failed to get Device properties for " << device_path + << ": " << call_status; + DeviceReady(device_path); + return; + } + std::string type; + if (!properties.GetStringWithoutPathExpansion( + flimflam::kTypeProperty, &type)) { + LOG(WARNING) << "Failed to parse Type property for " << device_path; + DeviceReady(device_path); + return; + } + Device& device = devices_[device_path]; + device.type = type; + properties.GetBooleanWithoutPathExpansion( + flimflam::kPoweredProperty, &device.powered); + properties.GetBooleanWithoutPathExpansion( + flimflam::kScanningProperty, &device.scanning); + properties.GetIntegerWithoutPathExpansion( + flimflam::kScanIntervalProperty, &device.scan_interval); + + if (!device.powered || + (type != flimflam::kTypeWifi && type != flimflam::kTypeWimax)) { + DeviceReady(device_path); + return; + } + + // Get WifiAccessPoint data for each Network property (only for powered + // wifi or wimax devices). + const base::ListValue* networks = NULL; + if (!properties.GetListWithoutPathExpansion( + flimflam::kNetworksProperty, &networks)) { + LOG(WARNING) << "Failed to parse Networks property for " << device_path; + DeviceReady(device_path); + return; + } + + for (size_t i = 0; i < networks->GetSize(); ++i) { + std::string network_path; + if (!networks->GetString(i, &network_path)) { + LOG(WARNING) << "Failed tp parse Networks[" << i << "]" + << " for device: " << device_path; + continue; + } + pending_network_paths_[device_path].insert(network_path); + DBusThreadManager::Get()->GetShillNetworkClient()->GetProperties( + dbus::ObjectPath(device_path), + base::Bind(&NetworkDeviceHandler::NetworkPropertiesCallback, + weak_ptr_factory_.GetWeakPtr(), + device_path, + network_path)); + } +} + +void NetworkDeviceHandler::NetworkPropertiesCallback( + const std::string& device_path, + const std::string& network_path, + DBusMethodCallStatus call_status, + const base::DictionaryValue& properties) { + if (call_status != DBUS_METHOD_CALL_SUCCESS) { + LOG(ERROR) << "Failed to get Network properties for " << network_path + << ", for device: " << device_path << ": " << call_status; + DeviceNetworkReady(device_path, network_path); + return; + } + + // Using the scan interval as a proxy for approximate age. + // TODO(joth): Replace with actual age, when available from dbus. + Device& device = devices_[device_path]; + WifiAccessPoint& wap = device.wifi_access_points[network_path]; + properties.GetStringWithoutPathExpansion( + flimflam::kAddressProperty, &wap.mac_address); + properties.GetStringWithoutPathExpansion( + flimflam::kNameProperty, &wap.name); + int age_seconds = device.scan_interval; + wap.timestamp = base::Time::Now() - base::TimeDelta::FromSeconds(age_seconds); + properties.GetIntegerWithoutPathExpansion( + flimflam::kSignalStrengthProperty, &wap.signal_strength); + properties.GetIntegerWithoutPathExpansion( + flimflam::kWifiChannelProperty, &wap.channel); + DeviceNetworkReady(device_path, network_path); +} + +void NetworkDeviceHandler::DeviceNetworkReady(const std::string& device_path, + const std::string& network_path) { + pending_network_paths_[device_path].erase(network_path); + if (pending_network_paths_[device_path].empty()) + DeviceReady(device_path); +} + +void NetworkDeviceHandler::DeviceReady(const std::string& device_path) { + pending_device_paths_.erase(device_path); + if (pending_device_paths_.empty()) { + devices_ready_ = true; + FOR_EACH_OBSERVER(Observer, observers_, NetworkDevicesUpdated(devices_)); + } +} + +//------------------------------------------------------------------------------ + +NetworkDeviceHandler::Device::Device() + : powered(false), scanning(false), scan_interval(0) { +} + +NetworkDeviceHandler::Device::~Device() { +} + +} // namespace chromeos diff --git a/chromeos/network/network_device_handler.h b/chromeos/network/network_device_handler.h new file mode 100644 index 0000000..66109fc --- /dev/null +++ b/chromeos/network/network_device_handler.h @@ -0,0 +1,103 @@ +// Copyright (c) 2012 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. + +#ifndef CHROMEOS_NETWORK_NETWORK_DEVICE_HANDLER_H_ +#define CHROMEOS_NETWORK_NETWORK_DEVICE_HANDLER_H_ + +#include <map> +#include <set> +#include <string> + +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "chromeos/chromeos_export.h" +#include "chromeos/dbus/dbus_method_call_status.h" +#include "chromeos/dbus/shill_property_changed_observer.h" +#include "chromeos/network/network_util.h" // WifiAccessPoint + +namespace base { +class DictionaryValue; +class ListValue; +class Value; +} + +namespace chromeos { + +class CHROMEOS_EXPORT NetworkDeviceHandler + : public ShillPropertyChangedObserver { + public: + struct Device { + Device(); + ~Device(); + std::string type; + bool powered; + bool scanning; + int scan_interval; + std::map<std::string, WifiAccessPoint> wifi_access_points; + }; + typedef std::map<std::string, Device> DeviceMap; + + class Observer { + public: + typedef NetworkDeviceHandler::DeviceMap DeviceMap; + + // Called when devices are updated. Passes the updated map of devices. + virtual void NetworkDevicesUpdated(const DeviceMap& devices) = 0; + + protected: + virtual ~Observer() {} + }; + + NetworkDeviceHandler(); + virtual ~NetworkDeviceHandler(); + void Init(); + + // Add/remove observers. + void AddObserver(Observer* observer); + void RemoveObserver(Observer* observer); + + bool devices_ready() const { return devices_ready_; } + const DeviceMap& devices() const { return devices_; } + + // ShillPropertyChangedObserver overrides + virtual void OnPropertyChanged(const std::string& key, + const base::Value& value) OVERRIDE; + + private: + void ManagerPropertiesCallback(DBusMethodCallStatus call_status, + const base::DictionaryValue& properties); + void DevicePropertyChanged(const base::ListValue* devices); + void DevicePropertiesCallback(const std::string& device_path, + DBusMethodCallStatus call_status, + const base::DictionaryValue& properties); + void NetworkPropertiesCallback(const std::string& device_path, + const std::string& network_path, + DBusMethodCallStatus call_status, + const base::DictionaryValue& properties); + void DeviceNetworkReady(const std::string& device_path, + const std::string& network_path); + void DeviceReady(const std::string& device_path); + + // True when the device list is up to date. + bool devices_ready_; + + // Map of Device structs, valid when |devices_ready_| is true. + DeviceMap devices_; + + // Map of pending devices. + std::set<std::string> pending_device_paths_; + + // Map of pending networks per device path. + std::map<std::string, std::set<std::string> > pending_network_paths_; + + // Observer list + ObserverList<Observer> observers_; + + // For Shill client callbacks + base::WeakPtrFactory<NetworkDeviceHandler> weak_ptr_factory_; +}; + +} // namespace chromeos + +#endif // CHROMEOS_NETWORK_NETWORK_DEVICE_HANDLER_H_ diff --git a/chromeos/network/network_device_handler_unittest.cc b/chromeos/network/network_device_handler_unittest.cc new file mode 100644 index 0000000..5ffd296 --- /dev/null +++ b/chromeos/network/network_device_handler_unittest.cc @@ -0,0 +1,136 @@ +// Copyright (c) 2012 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 "chromeos/network/network_device_handler.h" + +#include "base/bind.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop.h" +#include "base/values.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/shill_device_client.h" +#include "chromeos/dbus/shill_manager_client.h" +#include "dbus/object_path.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace chromeos { + +namespace { + +class TestObserver : public NetworkDeviceHandler::Observer { + public: + TestObserver() : device_updates_(0) {} + + virtual void NetworkDevicesUpdated(const DeviceMap& devices) { + ++device_updates_; + devices_ = devices; + } + + int device_updates() { return device_updates_; } + const DeviceMap& devices() { return devices_; } + + private: + int device_updates_; + DeviceMap devices_; +}; + +} // namespace + +class NetworkDeviceHandlerTest : public testing::Test { + public: + NetworkDeviceHandlerTest() + : manager_test_(NULL), + device_test_(NULL) { + } + virtual ~NetworkDeviceHandlerTest() { + } + + virtual void SetUp() OVERRIDE { + // Initialize DBusThreadManager with a stub implementation. + DBusThreadManager::InitializeWithStub(); + // Get the test interface for manager / device. + manager_test_ = + DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface(); + ASSERT_TRUE(manager_test_); + device_test_ = + DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface(); + ASSERT_TRUE(device_test_); + } + + virtual void TearDown() OVERRIDE { + device_handler_->RemoveObserver(observer_.get()); + observer_.reset(); + device_handler_.reset(); + DBusThreadManager::Shutdown(); + } + + void AddDevice(const std::string& type, const std::string& id) { + manager_test_->AddDevice(id); + device_test_->AddDevice(id, type, std::string("/device/" + id), "/stub"); + } + + void RemoveDevice(const std::string& id) { + manager_test_->RemoveDevice(id); + device_test_->RemoveDevice(id); + } + + // Call this after any initial Shill client setup + void SetupNetworkDeviceHandler() { + device_handler_.reset(new NetworkDeviceHandler()); + device_handler_->Init(); + observer_.reset(new TestObserver()); + device_handler_->AddObserver(observer_.get()); + } + + protected: + MessageLoopForUI message_loop_; + scoped_ptr<TestObserver> observer_; + scoped_ptr<NetworkDeviceHandler> device_handler_; + ShillManagerClient::TestInterface* manager_test_; + ShillDeviceClient::TestInterface* device_test_; + + private: + DISALLOW_COPY_AND_ASSIGN(NetworkDeviceHandlerTest); +}; + +TEST_F(NetworkDeviceHandlerTest, NetworkDeviceHandlerStub) { + SetupNetworkDeviceHandler(); + EXPECT_FALSE(device_handler_->devices_ready()); + + message_loop_.RunUntilIdle(); + EXPECT_EQ(1, observer_->device_updates()); + EXPECT_TRUE(device_handler_->devices_ready()); + // ShillManagerClient default stub entries are in shill_manager_client.cc. + // TODO(stevenjb): Eliminate default stub entries and add them explicitly. + const size_t kNumShillManagerClientStubImplDevices = 2; + EXPECT_EQ(kNumShillManagerClientStubImplDevices, + device_handler_->devices().size()); +} + +TEST_F(NetworkDeviceHandlerTest, NetworkDeviceHandlerPropertyChanged) { + // This relies on the stub dbus implementations for ShillManagerClient, + SetupNetworkDeviceHandler(); + + message_loop_.RunUntilIdle(); + EXPECT_EQ(1, observer_->device_updates()); + const size_t kNumShillManagerClientStubImplDevices = 2; + EXPECT_EQ(kNumShillManagerClientStubImplDevices, observer_->devices().size()); + + // Add a device. + const std::string kTestDevicePath("test_wifi_device1"); + AddDevice(flimflam::kTypeWifi, kTestDevicePath); + message_loop_.RunUntilIdle(); + EXPECT_EQ(2, observer_->device_updates()); + EXPECT_EQ(kNumShillManagerClientStubImplDevices + 1, + observer_->devices().size()); + + // Remove a device + RemoveDevice(kTestDevicePath); + message_loop_.RunUntilIdle(); + EXPECT_EQ(3, observer_->device_updates()); + EXPECT_EQ(kNumShillManagerClientStubImplDevices, observer_->devices().size()); +} + +} // namespace chromeos |