summaryrefslogtreecommitdiffstats
path: root/chromeos/network
diff options
context:
space:
mode:
authorstevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-09 02:21:19 +0000
committerstevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-09 02:21:19 +0000
commitda42a133bc46ac23d34f32007d75932a6fffa1b2 (patch)
tree57c42eb21b7b560a01ffbe701474cfdbd1c3c43c /chromeos/network
parent227c1a12c4f4e741f29fcc6e56bf86a94188fadd (diff)
downloadchromium_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.cc216
-rw-r--r--chromeos/network/network_device_handler.h103
-rw-r--r--chromeos/network/network_device_handler_unittest.cc136
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