diff options
author | stevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-03 10:45:58 +0000 |
---|---|---|
committer | stevenjb@chromium.org <stevenjb@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-07-03 10:45:58 +0000 |
commit | ce21fc613336439b575823b7e223b3bf9f36da0c (patch) | |
tree | 1a7ccf12cd2a74f2b352acc8ac9a6acde9aefef6 | |
parent | 4b95f6f0055436bb5d33091182a4f58df9d6501d (diff) | |
download | chromium_src-ce21fc613336439b575823b7e223b3bf9f36da0c.zip chromium_src-ce21fc613336439b575823b7e223b3bf9f36da0c.tar.gz chromium_src-ce21fc613336439b575823b7e223b3bf9f36da0c.tar.bz2 |
Support network Favorite/Preferred list and removal
This CL tracks Manager.ServiceCompleteList to provide a list of
favorite/preferred networks to the UI. It uses
Service.GetLoadableProfileEntries to remove preferred services.
A test UI is provided in the status area (behind a flag).
Stub behavior is updated to enable testing the UI on Linux.
BUG=251922
Review URL: https://chromiumcodereview.appspot.com/17778003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@209950 0039d316-1c4b-4281-b951-d872f2087c98
30 files changed, 528 insertions, 101 deletions
diff --git a/ash/system/chromeos/network/network_state_notifier_unittest.cc b/ash/system/chromeos/network/network_state_notifier_unittest.cc index 009274c..2f681bc 100644 --- a/ash/system/chromeos/network/network_state_notifier_unittest.cc +++ b/ash/system/chromeos/network/network_state_notifier_unittest.cc @@ -68,10 +68,11 @@ class NetworkStateNotifierTest : public AshTestBase { DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); service_test->ClearServices(); const bool add_to_watchlist = true; + const bool add_to_visible = true; // Create wifi and cellular networks and set to online. service_test->AddService("wifi1", "wifi1", flimflam::kTypeWifi, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); RunAllPendingInMessageLoop(); } diff --git a/chrome/browser/chromeos/extensions/networking_private_apitest.cc b/chrome/browser/chromeos/extensions/networking_private_apitest.cc index 29368f3..0cb874a 100644 --- a/chrome/browser/chromeos/extensions/networking_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/networking_private_apitest.cc @@ -118,13 +118,14 @@ class ExtensionNetworkingPrivateApiTest : flimflam::kTypeCellular, "stub_cellular_device1"); const bool add_to_watchlist = true; + const bool add_to_visible = true; service_test->AddService("stub_ethernet", "eth0", flimflam::kTypeEthernet, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->AddService("stub_wifi1", "wifi1", flimflam::kTypeWifi, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->SetServiceProperty("stub_wifi1", flimflam::kSecurityProperty, base::StringValue(flimflam::kSecurityWep)); @@ -139,7 +140,7 @@ class ExtensionNetworkingPrivateApiTest : service_test->AddService("stub_wifi2", "wifi2_PSK", flimflam::kTypeWifi, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->SetServiceProperty("stub_wifi2", flimflam::kGuidProperty, base::StringValue("stub_wifi2")); @@ -165,7 +166,7 @@ class ExtensionNetworkingPrivateApiTest : service_test->AddService("stub_cellular1", "cellular1", flimflam::kTypeCellular, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->SetServiceProperty( "stub_cellular1", flimflam::kNetworkTechnologyProperty, @@ -182,7 +183,7 @@ class ExtensionNetworkingPrivateApiTest : service_test->AddService("stub_vpn1", "vpn1", flimflam::kTypeVPN, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); content::RunAllPendingInMessageLoop(); } diff --git a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc index 6b497dd..16994e8 100644 --- a/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc +++ b/chrome/browser/chromeos/net/network_portal_detector_impl_unittest.cc @@ -190,23 +190,24 @@ class NetworkPortalDetectorImplTest ShillServiceClient::TestInterface* service_test = DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); service_test->ClearServices(); + const bool add_to_visible = true; const bool add_to_watchlist = true; service_test->AddService(kStubEthernet, kStubEthernet, flimflam::kTypeEthernet, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->AddService(kStubWireless1, kStubWireless1, flimflam::kTypeWifi, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->AddService(kStubWireless2, kStubWireless2, flimflam::kTypeWifi, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->AddService(kStubCellular, kStubCellular, flimflam::kTypeCellular, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); } void SetupNetworkHandler() { diff --git a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc index ccc3cdb..feffd4d 100644 --- a/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc +++ b/chrome/browser/chromeos/proxy_config_service_impl_unittest.cc @@ -245,7 +245,7 @@ class ProxyConfigServiceImplTest : public testing::Test { service_test->AddService("stub_wifi2", "wifi2_PSK", flimflam::kTypeWifi, flimflam::kStateOnline, - true /* add to watchlist */); + true /* visible */, true /* watch */); service_test->SetServiceProperty("stub_wifi2", flimflam::kGuidProperty, base::StringValue("stub_wifi2")); diff --git a/chromeos/chromeos.gyp b/chromeos/chromeos.gyp index 3eef745..2c98c71 100644 --- a/chromeos/chromeos.gyp +++ b/chromeos/chromeos.gyp @@ -221,6 +221,8 @@ 'network/cros_network_functions.h', 'network/device_state.cc', 'network/device_state.h', + 'network/favorite_state.cc', + 'network/favorite_state.h', 'network/geolocation_handler.cc', 'network/geolocation_handler.h', 'network/managed_network_configuration_handler.cc', diff --git a/chromeos/dbus/dbus_thread_manager.cc b/chromeos/dbus/dbus_thread_manager.cc index 66f4baf..4559dc5 100644 --- a/chromeos/dbus/dbus_thread_manager.cc +++ b/chromeos/dbus/dbus_thread_manager.cc @@ -103,7 +103,8 @@ class DBusThreadManagerImpl : public DBusThreadManager { DebugDaemonClient::Create(client_type_, system_bus_.get())); // Construction order of the Stub implementations of the Shill clients - // matters; stub clients may depend only on clients previously constructed. + // matters; stub clients may only have construction dependencies on clients + // previously constructed. shill_manager_client_.reset( ShillManagerClient::Create(client_type_override_, system_bus_.get())); shill_device_client_.reset( diff --git a/chromeos/dbus/shill_manager_client.h b/chromeos/dbus/shill_manager_client.h index e9fca9c..0a2b9b06 100644 --- a/chromeos/dbus/shill_manager_client.h +++ b/chromeos/dbus/shill_manager_client.h @@ -66,6 +66,7 @@ class CHROMEOS_EXPORT ShillManagerClient { // Add/Remove/ClearService should only be called from ShillServiceClient. virtual void AddManagerService(const std::string& service_path, + bool add_to_visible_list, bool add_to_watch_list) = 0; virtual void RemoveManagerService(const std::string& service_path) = 0; virtual void ClearManagerServices() = 0; diff --git a/chromeos/dbus/shill_manager_client_stub.cc b/chromeos/dbus/shill_manager_client_stub.cc index 82eac3b..36f02939 100644 --- a/chromeos/dbus/shill_manager_client_stub.cc +++ b/chromeos/dbus/shill_manager_client_stub.cc @@ -213,7 +213,8 @@ void ShillManagerClientStub::ConfigureService( // Add a new service to the service client stub because none exists, yet. service_client->AddServiceWithIPConfig(service_path, guid, type, flimflam::kStateIdle, ipconfig_path, - true); // Add service to watch list. + true /* visible */, + true /* watch */); existing_properties = service_client->GetServiceProperties(service_path); } @@ -398,13 +399,17 @@ void ShillManagerClientStub::MoveServiceToIndex( } void ShillManagerClientStub::AddManagerService(const std::string& service_path, + bool add_to_visible_list, bool add_to_watch_list) { - if (GetListProperty(flimflam::kServicesProperty)->AppendIfNotPresent( + // Always add to ServiceCompleteListProperty. + GetListProperty(shill::kServiceCompleteListProperty)->AppendIfNotPresent( + base::Value::CreateStringValue(service_path)); + // If visible, add to Services and notify if new. + if (add_to_visible_list && + GetListProperty(flimflam::kServicesProperty)->AppendIfNotPresent( base::Value::CreateStringValue(service_path))) { CallNotifyObserversPropertyChanged(flimflam::kServicesProperty, 0); } - GetListProperty(shill::kServiceCompleteListProperty)->AppendIfNotPresent( - base::Value::CreateStringValue(service_path)); if (add_to_watch_list) AddServiceToWatchList(service_path); } @@ -478,14 +483,11 @@ void ShillManagerClientStub::PassStubProperties( const DictionaryValueCallback& callback) const { scoped_ptr<base::DictionaryValue> stub_properties( stub_properties_.DeepCopy()); - // Remove disabled services from the list + // Remove disabled services from the list. stub_properties->SetWithoutPathExpansion( flimflam::kServicesProperty, GetEnabledServiceList(flimflam::kServicesProperty)); stub_properties->SetWithoutPathExpansion( - shill::kServiceCompleteListProperty, - GetEnabledServiceList(shill::kServiceCompleteListProperty)); - stub_properties->SetWithoutPathExpansion( flimflam::kServiceWatchListProperty, GetEnabledServiceList(flimflam::kServiceWatchListProperty)); callback.Run(DBUS_METHOD_CALL_SUCCESS, *stub_properties); diff --git a/chromeos/dbus/shill_manager_client_stub.h b/chromeos/dbus/shill_manager_client_stub.h index 53863a2..569dd4f 100644 --- a/chromeos/dbus/shill_manager_client_stub.h +++ b/chromeos/dbus/shill_manager_client_stub.h @@ -93,6 +93,7 @@ class ShillManagerClientStub : public ShillManagerClient, size_t index, bool add_to_watch_list) OVERRIDE; virtual void AddManagerService(const std::string& service_path, + bool add_to_visible_list, bool add_to_watch_list) OVERRIDE; virtual void RemoveManagerService(const std::string& service_path) OVERRIDE; virtual void ClearManagerServices() OVERRIDE; diff --git a/chromeos/dbus/shill_profile_client.h b/chromeos/dbus/shill_profile_client.h index b93f335..bf81afb 100644 --- a/chromeos/dbus/shill_profile_client.h +++ b/chromeos/dbus/shill_profile_client.h @@ -43,16 +43,30 @@ class CHROMEOS_EXPORT ShillProfileClient { // Interface for setting up services for testing. Accessed through // GetTestInterface(), only implemented in the stub implementation. + // TODO(stevenjb): remove dependencies on entry_path -> service_path + // mappings in some of the TestInterface implementations. class TestInterface { public: virtual void AddProfile(const std::string& profile_path, const std::string& userhash) = 0; + + // Adds an entry to the profile only. |entry_path| corresponds to a + // 'service_path' and a corresponding entry will be added to + // ShillManagerClient ServiceCompleteList. No checking or updating of + // ShillServiceClient is performed. virtual void AddEntry(const std::string& profile_path, const std::string& entry_path, const base::DictionaryValue& properties) = 0; + + // Adds a service to the profile, copying properties from the + // ShillServiceClient entry (which must be present). Also sets the Profile + // property of the service in ShillServiceClient. virtual bool AddService(const std::string& profile_path, const std::string& service_path) = 0; + // Sets |profiles| to the current list of profile paths. + virtual void GetProfilePaths(std::vector<std::string>* profiles) = 0; + protected: virtual ~TestInterface() {} }; diff --git a/chromeos/dbus/shill_profile_client_stub.cc b/chromeos/dbus/shill_profile_client_stub.cc index b906d6d..c3cdf32 100644 --- a/chromeos/dbus/shill_profile_client_stub.cc +++ b/chromeos/dbus/shill_profile_client_stub.cc @@ -149,6 +149,8 @@ void ShillProfileClientStub::AddEntry(const std::string& profile_path, DCHECK(profile); profile->entries.SetWithoutPathExpansion(entry_path, properties.DeepCopy()); + DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()-> + AddManagerService(entry_path, false /* visible */, false /* watch */); } bool ShillProfileClientStub::AddService(const std::string& profile_path, @@ -186,6 +188,14 @@ bool ShillProfileClientStub::AddService(const std::string& profile_path, return true; } +void ShillProfileClientStub::GetProfilePaths( + std::vector<std::string>* profiles) { + for (ProfileMap::iterator iter = profiles_.begin(); + iter != profiles_.end(); ++iter) { + profiles->push_back(iter->first); + } +} + ShillProfileClientStub::ProfileProperties* ShillProfileClientStub::GetProfile( const dbus::ObjectPath& profile_path, const ErrorCallback& error_callback) { diff --git a/chromeos/dbus/shill_profile_client_stub.h b/chromeos/dbus/shill_profile_client_stub.h index fd6ef24d..92e9baa 100644 --- a/chromeos/dbus/shill_profile_client_stub.h +++ b/chromeos/dbus/shill_profile_client_stub.h @@ -50,6 +50,7 @@ class ShillProfileClientStub : public ShillProfileClient, const base::DictionaryValue& properties) OVERRIDE; virtual bool AddService(const std::string& profile_path, const std::string& service_path) OVERRIDE; + virtual void GetProfilePaths(std::vector<std::string>* profiles) OVERRIDE; private: struct ProfileProperties; diff --git a/chromeos/dbus/shill_service_client.h b/chromeos/dbus/shill_service_client.h index 3a3b3fa..4050c63 100644 --- a/chromeos/dbus/shill_service_client.h +++ b/chromeos/dbus/shill_service_client.h @@ -48,12 +48,14 @@ class CHROMEOS_EXPORT ShillServiceClient { const std::string& name, const std::string& type, const std::string& state, + bool add_to_visible_list, bool add_to_watch_list) = 0; virtual void AddServiceWithIPConfig(const std::string& service_path, const std::string& name, const std::string& type, const std::string& state, const std::string& ipconfig_path, + bool add_to_visible_list, bool add_to_watch_list) = 0; virtual void RemoveService(const std::string& service_path) = 0; virtual void SetServiceProperty(const std::string& service_path, diff --git a/chromeos/dbus/shill_service_client_stub.cc b/chromeos/dbus/shill_service_client_stub.cc index a1c56e9..3559ee4 100644 --- a/chromeos/dbus/shill_service_client_stub.cc +++ b/chromeos/dbus/shill_service_client_stub.cc @@ -326,9 +326,10 @@ void ShillServiceClientStub::AddService(const std::string& service_path, const std::string& name, const std::string& type, const std::string& state, + bool add_to_visible_list, bool add_to_watch_list) { AddServiceWithIPConfig(service_path, name, type, state, "", - add_to_watch_list); + add_to_visible_list, add_to_watch_list); } void ShillServiceClientStub::AddServiceWithIPConfig( @@ -337,9 +338,10 @@ void ShillServiceClientStub::AddServiceWithIPConfig( const std::string& type, const std::string& state, const std::string& ipconfig_path, + bool add_to_visible_list, bool add_to_watch_list) { DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()-> - AddManagerService(service_path, add_to_watch_list); + AddManagerService(service_path, add_to_visible_list, add_to_watch_list); base::DictionaryValue* properties = GetModifiableServiceProperties(service_path); @@ -391,6 +393,7 @@ void ShillServiceClientStub::ClearServices() { } void ShillServiceClientStub::SetDefaultProperties() { + const bool add_to_visible = true; const bool add_to_watchlist = true; if (!CommandLine::ForCurrentProcess()->HasSwitch( @@ -398,13 +401,13 @@ void ShillServiceClientStub::SetDefaultProperties() { AddService("eth1", "eth1", flimflam::kTypeEthernet, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); } AddService("wifi1", "wifi1", flimflam::kTypeWifi, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); SetServiceProperty("wifi1", flimflam::kSecurityProperty, base::StringValue(flimflam::kSecurityWep)); @@ -412,7 +415,7 @@ void ShillServiceClientStub::SetDefaultProperties() { AddService("wifi2", "wifi2_PSK", flimflam::kTypeWifi, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); SetServiceProperty("wifi2", flimflam::kSecurityProperty, base::StringValue(flimflam::kSecurityPsk)); @@ -424,7 +427,7 @@ void ShillServiceClientStub::SetDefaultProperties() { AddService("cellular1", "cellular1", flimflam::kTypeCellular, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); base::StringValue technology_value(flimflam::kNetworkTechnologyGsm); SetServiceProperty("cellular1", flimflam::kNetworkTechnologyProperty, @@ -439,12 +442,12 @@ void ShillServiceClientStub::SetDefaultProperties() { AddService("vpn1", "vpn1", flimflam::kTypeVPN, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); AddService("vpn2", "vpn2", flimflam::kTypeVPN, flimflam::kStateOffline, - add_to_watchlist); + add_to_visible, add_to_watchlist); } void ShillServiceClientStub::NotifyObserversPropertyChanged( diff --git a/chromeos/dbus/shill_service_client_stub.h b/chromeos/dbus/shill_service_client_stub.h index ee8d713..64f7f12 100644 --- a/chromeos/dbus/shill_service_client_stub.h +++ b/chromeos/dbus/shill_service_client_stub.h @@ -76,12 +76,14 @@ class ShillServiceClientStub : public ShillServiceClient, const std::string& name, const std::string& type, const std::string& state, + bool add_to_visible_list, bool add_to_watch_list) OVERRIDE; virtual void AddServiceWithIPConfig(const std::string& service_path, const std::string& name, const std::string& type, const std::string& state, const std::string& ipconfig_path, + bool add_to_visible_list, bool add_to_watch_list) OVERRIDE; virtual void RemoveService(const std::string& service_path) OVERRIDE; virtual void SetServiceProperty(const std::string& service_path, diff --git a/chromeos/network/favorite_state.cc b/chromeos/network/favorite_state.cc new file mode 100644 index 0000000..7f8bb31 --- /dev/null +++ b/chromeos/network/favorite_state.cc @@ -0,0 +1,30 @@ +// Copyright 2013 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/favorite_state.h" + +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "base/values.h" +#include "third_party/cros_system_api/dbus/service_constants.h" + +namespace chromeos { + +FavoriteState::FavoriteState(const std::string& path) + : ManagedState(MANAGED_TYPE_FAVORITE, path) { +} + +FavoriteState::~FavoriteState() { +} + +bool FavoriteState::PropertyChanged(const std::string& key, + const base::Value& value) { + if (ManagedStatePropertyChanged(key, value)) + return true; + if (key == flimflam::kProfileProperty) + return GetStringValue(key, value, &profile_path_); + return false; +} + +} // namespace chromeos diff --git a/chromeos/network/favorite_state.h b/chromeos/network/favorite_state.h new file mode 100644 index 0000000..54b8919 --- /dev/null +++ b/chromeos/network/favorite_state.h @@ -0,0 +1,41 @@ +// Copyright 2013 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_FAVORITE_STATE_H_ +#define CHROMEOS_NETWORK_FAVORITE_STATE_H_ + +#include "chromeos/network/managed_state.h" + +namespace chromeos { + +// A simple class to provide essential information for Services created +// by Shill corresponding to Profile Entries (i.e. 'preferred' or 'favorite' +// networks). +// Note: NetworkStateHandler will store an entry for each member of +// Manager.ServiceCompleteList, even for visible entries that are not +// favorites. This is necessary to avoid unnecessarily re-requesting entries, +// and to limit the code complexity. The is_favorite() accessor is used to skip +// entries that are not actually favorites. +class CHROMEOS_EXPORT FavoriteState : public ManagedState { + public: + explicit FavoriteState(const std::string& path); + virtual ~FavoriteState(); + + // ManagedState overrides + virtual bool PropertyChanged(const std::string& key, + const base::Value& value) OVERRIDE; + + // Accessors + const std::string& profile_path() const { return profile_path_; } + bool is_favorite() const { return !profile_path_.empty(); } + + private: + std::string profile_path_; + + DISALLOW_COPY_AND_ASSIGN(FavoriteState); +}; + +} // namespace chromeos + +#endif // CHROMEOS_NETWORK_FAVORITE_STATE_H_ diff --git a/chromeos/network/managed_network_configuration_handler_unittest.cc b/chromeos/network/managed_network_configuration_handler_unittest.cc index 2b4d0be..f47d2cb 100644 --- a/chromeos/network/managed_network_configuration_handler_unittest.cc +++ b/chromeos/network/managed_network_configuration_handler_unittest.cc @@ -132,7 +132,9 @@ class ShillProfileTestClient { class TestNetworkProfileHandler : public NetworkProfileHandler { public: - TestNetworkProfileHandler() {} + TestNetworkProfileHandler() { + Init(NULL /* No NetworkStateHandler */); + } virtual ~TestNetworkProfileHandler() {} void AddProfileForTest(const NetworkProfile& profile) { diff --git a/chromeos/network/managed_state.cc b/chromeos/network/managed_state.cc index 340b858..655e576 100644 --- a/chromeos/network/managed_state.cc +++ b/chromeos/network/managed_state.cc @@ -7,6 +7,7 @@ #include "base/logging.h" #include "base/values.h" #include "chromeos/network/device_state.h" +#include "chromeos/network/favorite_state.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state.h" #include "third_party/cros_system_api/dbus/service_constants.h" @@ -26,6 +27,8 @@ ManagedState* ManagedState::Create(ManagedType type, const std::string& path) { switch (type) { case MANAGED_TYPE_NETWORK: return new NetworkState(path); + case MANAGED_TYPE_FAVORITE: + return new FavoriteState(path); case MANAGED_TYPE_DEVICE: return new DeviceState(path); } @@ -44,6 +47,12 @@ DeviceState* ManagedState::AsDeviceState() { return NULL; } +FavoriteState* ManagedState::AsFavoriteState() { + if (managed_type() == MANAGED_TYPE_FAVORITE) + return static_cast<FavoriteState*>(this); + return NULL; +} + void ManagedState::InitialPropertiesReceived() { } diff --git a/chromeos/network/managed_state.h b/chromeos/network/managed_state.h index 4374e3c..93d39bb 100644 --- a/chromeos/network/managed_state.h +++ b/chromeos/network/managed_state.h @@ -18,6 +18,7 @@ class Value; namespace chromeos { class DeviceState; +class FavoriteState; class NetworkState; // Base class for states managed by NetworkStateManger which are associated @@ -26,6 +27,7 @@ class ManagedState { public: enum ManagedType { MANAGED_TYPE_NETWORK, + MANAGED_TYPE_FAVORITE, MANAGED_TYPE_DEVICE }; @@ -39,6 +41,7 @@ class ManagedState { // NULL if it is not. NetworkState* AsNetworkState(); DeviceState* AsDeviceState(); + FavoriteState* AsFavoriteState(); // Called by NetworkStateHandler when a property was received. The return // value indicates if the state changed and is used to reduce the number of diff --git a/chromeos/network/network_configuration_handler.cc b/chromeos/network/network_configuration_handler.cc index 812aa5f..1a5ba93 100644 --- a/chromeos/network/network_configuration_handler.cc +++ b/chromeos/network/network_configuration_handler.cc @@ -184,8 +184,8 @@ class NetworkConfigurationHandler::ProfileEntryDeleter // Run the callback if this is the last pending deletion. if (!callback_.is_null()) callback_.Run(); - // TODO(stevenjb): Request NetworkStateHandler manager update to update - // ServiceCompleteList once FavoriteStates are implemented. + // Request NetworkStateHandler manager update to update ServiceCompleteList. + owner_->network_state_handler_->UpdateManagerProperties(); owner_->ProfileEntryDeleterCompleted(service_path_); // Deletes this. } diff --git a/chromeos/network/network_handler.cc b/chromeos/network/network_handler.cc index 5bc9a0a..fbe0d4b 100644 --- a/chromeos/network/network_handler.cc +++ b/chromeos/network/network_handler.cc @@ -41,6 +41,7 @@ NetworkHandler::~NetworkHandler() { void NetworkHandler::Init() { network_state_handler_->InitShillPropertyHandler(); + network_profile_handler_->Init(network_state_handler_.get()); network_configuration_handler_->Init(network_state_handler_.get()); managed_network_configuration_handler_->Init( network_state_handler_.get(), diff --git a/chromeos/network/network_profile_handler.cc b/chromeos/network/network_profile_handler.cc index de92798..96d7f37 100644 --- a/chromeos/network/network_profile_handler.cc +++ b/chromeos/network/network_profile_handler.cc @@ -13,6 +13,7 @@ #include "chromeos/dbus/shill_manager_client.h" #include "chromeos/dbus/shill_profile_client.h" #include "chromeos/network/network_profile_observer.h" +#include "chromeos/network/network_state_handler.h" #include "dbus/object_path.h" #include "third_party/cros_system_api/dbus/service_constants.h" @@ -126,6 +127,11 @@ void NetworkProfileHandler::OnPropertyChanged(const std::string& name, *it), base::Bind(&LogProfileRequestError, *it)); } + + // When the profile list changes, ServiceCompleteList may also change, so + // trigger a Manager update to request the updated list. + if (network_state_handler_) + network_state_handler_->UpdateManagerProperties(); } void NetworkProfileHandler::GetProfilePropertiesCallback( @@ -180,7 +186,13 @@ const NetworkProfile* NetworkProfileHandler::GetProfileForUserhash( } NetworkProfileHandler::NetworkProfileHandler() - : weak_ptr_factory_(this) { + : network_state_handler_(NULL), + weak_ptr_factory_(this) { +} + +void NetworkProfileHandler::Init(NetworkStateHandler* network_state_handler) { + network_state_handler_ = network_state_handler; + DBusThreadManager::Get()->GetShillManagerClient()-> AddPropertyChangedObserver(this); diff --git a/chromeos/network/network_profile_handler.h b/chromeos/network/network_profile_handler.h index f175876..cf35b21 100644 --- a/chromeos/network/network_profile_handler.h +++ b/chromeos/network/network_profile_handler.h @@ -25,6 +25,7 @@ class DictionaryValue; namespace chromeos { class NetworkProfileObserver; +class NetworkStateHandler; class CHROMEOS_EXPORT NetworkProfileHandler : public ShillPropertyChangedObserver { @@ -55,14 +56,18 @@ class CHROMEOS_EXPORT NetworkProfileHandler friend class NetworkHandler; NetworkProfileHandler(); + // Add ShillManagerClient property observer and request initial list. + // Sets |network_state_handler_| for triggering Manager updates (can be NULL). + void Init(NetworkStateHandler* network_state_handler); + void AddProfile(const NetworkProfile& profile); void RemoveProfile(const std::string& profile_path); private: + NetworkStateHandler* network_state_handler_; ProfileList profiles_; ObserverList<NetworkProfileObserver> observers_; - protected: // For Shill client callbacks base::WeakPtrFactory<NetworkProfileHandler> weak_ptr_factory_; diff --git a/chromeos/network/network_state_handler.cc b/chromeos/network/network_state_handler.cc index 05807fd..6118955 100644 --- a/chromeos/network/network_state_handler.cc +++ b/chromeos/network/network_state_handler.cc @@ -12,6 +12,7 @@ #include "base/strings/stringprintf.h" #include "base/values.h" #include "chromeos/network/device_state.h" +#include "chromeos/network/favorite_state.h" #include "chromeos/network/managed_state.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state.h" @@ -114,6 +115,11 @@ void NetworkStateHandler::RemoveObserver( "NetworkStateHandler::RemoveObserver", ""); } +void NetworkStateHandler::UpdateManagerProperties() { + NET_LOG_USER("UpdateManagerProperties", ""); + shill_property_handler_->UpdateManagerProperties(); +} + NetworkStateHandler::TechnologyState NetworkStateHandler::GetTechnologyState( const std::string& type) const { std::string technology = GetTechnologyForType(type); @@ -268,6 +274,28 @@ void NetworkStateHandler::GetNetworkList(NetworkStateList* list) const { } } +void NetworkStateHandler::GetFavoriteList(FavoriteStateList* list) const { + DCHECK(list); + FavoriteStateList result; + list->clear(); + for (ManagedStateList::const_iterator iter = favorite_list_.begin(); + iter != favorite_list_.end(); ++iter) { + const FavoriteState* favorite = (*iter)->AsFavoriteState(); + DCHECK(favorite); + if (favorite->is_favorite()) + list->push_back(favorite); + } +} + +const FavoriteState* NetworkStateHandler::GetFavoriteState( + const std::string& service_path) const { + ManagedState* managed = + GetModifiableManagedState(&favorite_list_, service_path); + if (!managed) + return NULL; + return managed->AsFavoriteState(); +} + void NetworkStateHandler::RequestScan() const { NET_LOG_USER("RequestScan", ""); shill_property_handler_->RequestScan(); @@ -342,7 +370,8 @@ void NetworkStateHandler::GetNetworkStatePropertiesForTest( void NetworkStateHandler::UpdateManagedList(ManagedState::ManagedType type, const base::ListValue& entries) { ManagedStateList* managed_list = GetManagedList(type); - VLOG(2) << "UpdateManagedList: " << type; + NET_LOG_DEBUG(base::StringPrintf("UpdateManagedList:%d", type), + base::StringPrintf("%"PRIuS, entries.GetSize())); // Create a map of existing entries. std::map<std::string, ManagedState*> managed_map; for (ManagedStateList::iterator iter = managed_list->begin(); @@ -412,8 +441,12 @@ void NetworkStateHandler::UpdateManagedStateProperties( NetworkState* network = managed->AsNetworkState(); DCHECK(network); // Signal connection state changed after all properties have been updated. - if (ConnectionStateChanged(network, prev_connection_state)) + if (ConnectionStateChanged(network, prev_connection_state)) { OnNetworkConnectionStateChanged(network); + // If the network did not already have a profile entry, refresh favorites. + if (network->profile_path().empty()) + UpdateManagerProperties(); + } NetworkPropertiesUpdated(network); } managed->set_update_requested(false); @@ -423,6 +456,13 @@ void NetworkStateHandler::UpdateNetworkServiceProperty( const std::string& service_path, const std::string& key, const base::Value& value) { + // Update any associated FavoriteState. + ManagedState* favorite = + GetModifiableManagedState(&favorite_list_, service_path); + if (favorite) + favorite->PropertyChanged(key, value); + + // Update the NetworkState. NetworkState* network = GetModifiableNetworkState(service_path); if (!network) return; @@ -494,6 +534,11 @@ void NetworkStateHandler::ManagedStateListChanged( // The list order may have changed, so check if the default network changed. if (CheckDefaultNetworkChanged()) OnDefaultNetworkChanged(); + } else if (type == ManagedState::MANAGED_TYPE_FAVORITE) { + NET_LOG_DEBUG("FavoriteListChanged", + base::StringPrintf("Size:%"PRIuS, favorite_list_.size())); + FOR_EACH_OBSERVER(NetworkStateHandlerObserver, observers_, + NetworkListChanged()); } else if (type == ManagedState::MANAGED_TYPE_DEVICE) { NET_LOG_DEBUG("DeviceListChanged", base::StringPrintf("Size:%"PRIuS, device_list_.size())); @@ -541,6 +586,8 @@ NetworkStateHandler::ManagedStateList* NetworkStateHandler::GetManagedList( switch (type) { case ManagedState::MANAGED_TYPE_NETWORK: return &network_list_; + case ManagedState::MANAGED_TYPE_FAVORITE: + return &favorite_list_; case ManagedState::MANAGED_TYPE_DEVICE: return &device_list_; } diff --git a/chromeos/network/network_state_handler.h b/chromeos/network/network_state_handler.h index 4518634..d9bb1d2 100644 --- a/chromeos/network/network_state_handler.h +++ b/chromeos/network/network_state_handler.h @@ -61,6 +61,7 @@ class CHROMEOS_EXPORT NetworkStateHandler public: typedef std::vector<ManagedState*> ManagedStateList; typedef std::vector<const NetworkState*> NetworkStateList; + typedef std::vector<const FavoriteState*> FavoriteStateList; enum TechnologyState { TECHNOLOGY_UNAVAILABLE, @@ -78,6 +79,11 @@ class CHROMEOS_EXPORT NetworkStateHandler void RemoveObserver(NetworkStateHandlerObserver* observer, const tracked_objects::Location& from_here); + // Requests all Manager properties, specifically to update the complete + // list of services which determines the list of Favorites. This should be + // called any time a new service is configured or a Profile is loaded. + void UpdateManagerProperties(); + // Returns the state for technology |type|. kMatchTypeMobile (only) is // also supported. TechnologyState GetTechnologyState(const std::string& type) const; @@ -140,6 +146,16 @@ class CHROMEOS_EXPORT NetworkStateHandler // only on the UI thread). void GetNetworkList(NetworkStateList* list) const; + // Sets |list| to contain the list of favorite (aka "preferred") networks. + // See GetNetworkList() for usage, and notes for |favorite_list_|. + // Favorites that are visible have the same path() as the entries in + // GetNetworkList(), so GetNetworkState() can be used to determine if a + // favorite is visible and retrieve the complete properties (and vice-versa). + void GetFavoriteList(FavoriteStateList* list) const; + + // Finds and returns a favorite state by |service_path| or NULL if not found. + const FavoriteState* GetFavoriteState(const std::string& service_path) const; + // Requests a network scan. This may trigger updates to the network // list, which will trigger the appropriate observer calls. void RequestScan() const; @@ -287,8 +303,15 @@ class CHROMEOS_EXPORT NetworkStateHandler // Observer list ObserverList<NetworkStateHandlerObserver> observers_; - // Lists of managed states + // List of managed network states ManagedStateList network_list_; + + // List of managed favorite states; this list includes all entries in + // Manager.ServiceCompleteList, but only entries with a non-empty Profile + // property are returned in GetFavoriteList(). + ManagedStateList favorite_list_; + + // List of managed device states ManagedStateList device_list_; // Keeps track of the default network for notifying observers when it changes. diff --git a/chromeos/network/network_state_handler_unittest.cc b/chromeos/network/network_state_handler_unittest.cc index 004893c..3a8b819 100644 --- a/chromeos/network/network_state_handler_unittest.cc +++ b/chromeos/network/network_state_handler_unittest.cc @@ -15,6 +15,7 @@ #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_profile_client.h" #include "chromeos/dbus/shill_service_client.h" #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler_observer.h" @@ -43,7 +44,8 @@ class TestObserver : public chromeos::NetworkStateHandlerObserver { : handler_(handler), manager_changed_count_(0), network_count_(0), - default_network_change_count_(0) { + default_network_change_count_(0), + favorite_count_(0) { } virtual ~TestObserver() { @@ -61,6 +63,9 @@ class TestObserver : public chromeos::NetworkStateHandlerObserver { default_network_ = ""; default_network_connection_state_ = ""; } + NetworkStateHandler::FavoriteStateList favorites; + handler_->GetFavoriteList(&favorites); + favorite_count_ = favorites.size(); } virtual void DefaultNetworkChanged(const NetworkState* network) OVERRIDE { @@ -90,6 +95,7 @@ class TestObserver : public chromeos::NetworkStateHandlerObserver { std::string default_network_connection_state() { return default_network_connection_state_; } + size_t favorite_count() { return favorite_count_; } int PropertyUpdatesForService(const std::string& service_path) { return property_updates_[service_path]; @@ -111,6 +117,7 @@ class TestObserver : public chromeos::NetworkStateHandlerObserver { size_t default_network_change_count_; std::string default_network_; std::string default_network_connection_state_; + size_t favorite_count_; std::map<std::string, int> property_updates_; std::map<std::string, int> connection_state_changes_; std::map<std::string, std::string> network_connection_state_; @@ -163,23 +170,24 @@ class NetworkStateHandlerTest : public testing::Test { ShillServiceClient::TestInterface* service_test = DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); service_test->ClearServices(); + const bool add_to_visible = true; const bool add_to_watchlist = true; service_test->AddService(kShillManagerClientStubDefaultService, kShillManagerClientStubDefaultService, flimflam::kTypeEthernet, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->AddService(kShillManagerClientStubDefaultWireless, kShillManagerClientStubDefaultWireless, flimflam::kTypeWifi, flimflam::kStateOnline, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->AddService(kShillManagerClientStubWireless2, kShillManagerClientStubWireless2, flimflam::kTypeWifi, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); service_test->AddService(kShillManagerClientStubCellular, kShillManagerClientStubCellular, flimflam::kTypeCellular, flimflam::kStateIdle, - add_to_watchlist); + add_to_visible, add_to_watchlist); } base::MessageLoopForUI message_loop_; @@ -191,7 +199,6 @@ class NetworkStateHandlerTest : public testing::Test { }; TEST_F(NetworkStateHandlerTest, NetworkStateHandlerStub) { - EXPECT_EQ(1u, test_observer_->manager_changed_count()); // Ensure that the network list is the expected size. const size_t kNumShillManagerClientStubImplServices = 4; EXPECT_EQ(kNumShillManagerClientStubImplServices, @@ -213,7 +220,8 @@ TEST_F(NetworkStateHandlerTest, NetworkStateHandlerStub) { } TEST_F(NetworkStateHandlerTest, TechnologyChanged) { - EXPECT_EQ(1u, test_observer_->manager_changed_count()); + // There may be several manager changes during initialization. + size_t initial_changed_count = test_observer_->manager_changed_count(); // Enable a technology. EXPECT_NE(NetworkStateHandler::TECHNOLOGY_ENABLED, network_state_handler_->GetTechnologyState(flimflam::kTypeWimax)); @@ -221,13 +229,13 @@ TEST_F(NetworkStateHandlerTest, TechnologyChanged) { flimflam::kTypeWimax, true, network_handler::ErrorCallback()); // The technology state should immediately change to ENABLING and we should // receive a manager changed callback. - EXPECT_EQ(2u, test_observer_->manager_changed_count()); + EXPECT_EQ(initial_changed_count + 1, test_observer_->manager_changed_count()); EXPECT_EQ(NetworkStateHandler::TECHNOLOGY_ENABLING, network_state_handler_->GetTechnologyState(flimflam::kTypeWimax)); message_loop_.RunUntilIdle(); // Ensure we receive another manager changed callbacks when the technology // becomes enabled. - EXPECT_EQ(3u, test_observer_->manager_changed_count()); + EXPECT_EQ(initial_changed_count + 2, test_observer_->manager_changed_count()); EXPECT_EQ(NetworkStateHandler::TECHNOLOGY_ENABLED, network_state_handler_->GetTechnologyState(flimflam::kTypeWimax)); } @@ -285,6 +293,18 @@ TEST_F(NetworkStateHandlerTest, ServicePropertyChanged) { EXPECT_EQ(2, test_observer_->PropertyUpdatesForService(eth1)); } +TEST_F(NetworkStateHandlerTest, FavoriteState) { + // Set the profile entry of a service + const std::string wifi1 = kShillManagerClientStubDefaultWireless; + ShillProfileClient::TestInterface* profile_test = + DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface(); + EXPECT_TRUE(profile_test->AddService("/profile/default", wifi1)); + message_loop_.RunUntilIdle(); + network_state_handler_->UpdateManagerProperties(); + message_loop_.RunUntilIdle(); + EXPECT_EQ(1u, test_observer_->favorite_count()); +} + TEST_F(NetworkStateHandlerTest, NetworkConnectionStateChanged) { // Change a network state. ShillServiceClient::TestInterface* service_test = diff --git a/chromeos/network/shill_property_handler.cc b/chromeos/network/shill_property_handler.cc index 43483b8..f611813 100644 --- a/chromeos/network/shill_property_handler.cc +++ b/chromeos/network/shill_property_handler.cc @@ -14,6 +14,7 @@ #include "chromeos/dbus/shill_device_client.h" #include "chromeos/dbus/shill_ipconfig_client.h" #include "chromeos/dbus/shill_manager_client.h" +#include "chromeos/dbus/shill_profile_client.h" #include "chromeos/dbus/shill_service_client.h" #include "chromeos/network/network_event_log.h" #include "chromeos/network/network_state.h" @@ -113,10 +114,15 @@ ShillPropertyHandler::~ShillPropertyHandler() { } void ShillPropertyHandler::Init() { + UpdateManagerProperties(); + shill_manager_->AddPropertyChangedObserver(this); +} + +void ShillPropertyHandler::UpdateManagerProperties() { + NET_LOG_EVENT("UpdateManagerProperties", ""); shill_manager_->GetProperties( base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback, AsWeakPtr())); - shill_manager_->AddPropertyChangedObserver(this); } bool ShillPropertyHandler::IsTechnologyAvailable( @@ -151,7 +157,7 @@ void ShillPropertyHandler::SetTechnologyEnabled( base::Bind(&ShillPropertyHandler::EnableTechnologyFailed, AsWeakPtr(), technology, error_callback)); } else { - // Imediately clear locally from enabled and enabling lists. + // Immediately clear locally from enabled and enabling lists. enabled_technologies_.erase(technology); enabling_technologies_.erase(technology); shill_manager_->DisableTechnology( @@ -191,11 +197,13 @@ void ShillPropertyHandler::ConnectToBestServices() const { void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type, const std::string& path) { + VLOG(2) << "Request Properties: " << type << " : " << path; if (pending_updates_[type].find(path) != pending_updates_[type].end()) return; // Update already requested. pending_updates_[type].insert(path); - if (type == ManagedState::MANAGED_TYPE_NETWORK) { + if (type == ManagedState::MANAGED_TYPE_NETWORK || + type == ManagedState::MANAGED_TYPE_FAVORITE) { DBusThreadManager::Get()->GetShillServiceClient()->GetProperties( dbus::ObjectPath(path), base::Bind(&ShillPropertyHandler::GetPropertiesCallback, @@ -218,16 +226,7 @@ void ShillPropertyHandler::OnPropertyChanged(const std::string& key, NET_LOG_DEBUG("ManagerPropertyChanged", detail); listener_->NotifyManagerPropertyChanged(); } - // If the service or device list changed and there are no pending - // updates, signal the state list changed callback. - if ((key == flimflam::kServicesProperty) && - pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) { - listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK); - } - if (key == flimflam::kDevicesProperty && - pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) { - listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE); - } + CheckPendingStateListUpdates(key); } //------------------------------------------------------------------------------ @@ -243,29 +242,53 @@ void ShillPropertyHandler::ManagerPropertiesCallback( } NET_LOG_EVENT("ManagerPropertiesCallback", "Success"); bool notify = false; - bool update_service_list = false; + const base::Value* update_service_value = NULL; + const base::Value* update_service_complete_value = NULL; for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd(); iter.Advance()) { // Defer updating Services until all other properties have been updated. if (iter.key() == flimflam::kServicesProperty) - update_service_list = true; + update_service_value = &iter.value(); + else if (iter.key() == shill::kServiceCompleteListProperty) + update_service_complete_value = &iter.value(); else notify |= ManagerPropertyChanged(iter.key(), iter.value()); } - // Now update the service list which can safely assume other properties have - // been initially set. - if (update_service_list) { - const base::Value* value = NULL; - if (properties.GetWithoutPathExpansion(flimflam::kServicesProperty, &value)) - notify |= ManagerPropertyChanged(flimflam::kServicesProperty, *value); + // Update Services which can safely assume other properties have been set. + if (update_service_value) { + notify |= ManagerPropertyChanged(flimflam::kServicesProperty, + *update_service_value); + } + // Update ServiceCompleteList which skips entries that have already been + // requested for Services. + if (update_service_complete_value) { + notify |= ManagerPropertyChanged(shill::kServiceCompleteListProperty, + *update_service_complete_value); } + if (notify) listener_->NotifyManagerPropertyChanged(); - // If there are no pending updates, signal the state list changed callbacks. - if (pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) + CheckPendingStateListUpdates(""); +} + +void ShillPropertyHandler::CheckPendingStateListUpdates( + const std::string& key) { + // Once there are no pending updates, signal the state list changed callbacks. + if ((key.empty() || key == flimflam::kServicesProperty) && + pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) { listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK); - if (pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) + } + // Both Network update requests and Favorite update requests will affect + // the list of favorites, so wait for both to complete. + if ((key.empty() || key == shill::kServiceCompleteListProperty) && + pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0 && + pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) { + listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE); + } + if ((key.empty() || key == flimflam::kDevicesProperty) && + pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) { listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE); + } } bool ShillPropertyHandler::ManagerPropertyChanged(const std::string& key, @@ -275,16 +298,24 @@ bool ShillPropertyHandler::ManagerPropertyChanged(const std::string& key, const base::ListValue* vlist = GetListValue(key, value); if (vlist) { listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist); + UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist); // UpdateObserved used to use kServiceWatchListProperty for TYPE_NETWORK, // however that prevents us from receiving Strength updates from inactive // networks. The overhead for observing all services is not unreasonable // (and we limit the max number of observed services to kMaxObserved). UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist); } + } else if (key == shill::kServiceCompleteListProperty) { + const ListValue* vlist = GetListValue(key, value); + if (vlist) { + listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_FAVORITE, *vlist); + UpdateProperties(ManagedState::MANAGED_TYPE_FAVORITE, *vlist); + } } else if (key == flimflam::kDevicesProperty) { const base::ListValue* vlist = GetListValue(key, value); if (vlist) { listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist); + UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist); UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist); } } else if (key == flimflam::kAvailableTechnologiesProperty) { @@ -313,12 +344,39 @@ bool ShillPropertyHandler::ManagerPropertyChanged(const std::string& key, listener_->CheckPortalListChanged(check_portal_list); notify_manager_changed = true; } + } else { + VLOG(2) << "Ignored Manager Property: " << key; } return notify_manager_changed; } +void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type, + const base::ListValue& entries) { + std::set<std::string>& requested_updates = requested_updates_[type]; + std::set<std::string>& requested_service_updates = + requested_updates_[ManagedState::MANAGED_TYPE_NETWORK]; // For favorites + std::set<std::string> new_requested_updates; + VLOG(2) << "Update Properties: " << type << " Entries: " << entries.GetSize(); + for (base::ListValue::const_iterator iter = entries.begin(); + iter != entries.end(); ++iter) { + std::string path; + (*iter)->GetAsString(&path); + if (path.empty()) + continue; + if (type == ManagedState::MANAGED_TYPE_FAVORITE && + requested_service_updates.count(path) > 0) + continue; // Update already requested + if (requested_updates.find(path) == requested_updates.end()) + RequestProperties(type, path); + new_requested_updates.insert(path); + } + requested_updates.swap(new_requested_updates); +} + void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type, const base::ListValue& entries) { + DCHECK(type == ManagedState::MANAGED_TYPE_NETWORK || + type == ManagedState::MANAGED_TYPE_DEVICE); ShillPropertyObserverMap& observer_map = (type == ManagedState::MANAGED_TYPE_NETWORK) ? observed_networks_ : observed_devices_; @@ -333,8 +391,6 @@ void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type, if (iter2 != observer_map.end()) { new_observed[path] = iter2->second; } else { - // Request an update. - RequestProperties(type, path); // Create an observer for future updates. new_observed[path] = new ShillPropertyObserver( type, path, base::Bind( @@ -416,15 +472,19 @@ void ShillPropertyHandler::GetPropertiesCallback( VLOG(2) << "GetPropertiesCallback: " << type << " : " << path; pending_updates_[type].erase(path); if (call_status != DBUS_METHOD_CALL_SUCCESS) { - LOG(ERROR) << "Failed to get properties for: " << path - << ": " << call_status; + NET_LOG_ERROR("Failed to get properties", + base::StringPrintf("%s: %d", path.c_str(), call_status)); return; } listener_->UpdateManagedStateProperties(type, path, properties); - - if (properties.HasKey(shill::kIPConfigProperty)) { - // Since this is the first time we received properties for this network, - // also request its IPConfig parameters. + // Update Favorite properties for networks in the Services list. + if (type == ManagedState::MANAGED_TYPE_NETWORK) { + listener_->UpdateManagedStateProperties( + ManagedState::MANAGED_TYPE_FAVORITE, path, properties); + } + // Request IPConfig parameters for networks. + if (type == ManagedState::MANAGED_TYPE_NETWORK && + properties.HasKey(shill::kIPConfigProperty)) { std::string ip_config_path; if (properties.GetString(shill::kIPConfigProperty, &ip_config_path)) { DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties( @@ -435,8 +495,15 @@ void ShillPropertyHandler::GetPropertiesCallback( } // Notify the listener only when all updates for that type have completed. - if (pending_updates_[type].size() == 0) + if (pending_updates_[type].size() == 0) { listener_->ManagedStateListChanged(type); + // Notify that Favorites have changed when notifying for Networks if there + // are no additional Favorite updates pending. + if (type == ManagedState::MANAGED_TYPE_NETWORK && + pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) { + listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE); + } + } } void ShillPropertyHandler::PropertyChangedCallback( @@ -476,7 +543,9 @@ void ShillPropertyHandler::GetIPConfigCallback( DBusMethodCallStatus call_status, const base::DictionaryValue& properties) { if (call_status != DBUS_METHOD_CALL_SUCCESS) { - LOG(ERROR) << "Failed to get IP Config properties for: " << service_path; + NET_LOG_ERROR("Failed to get IP Config properties", + base::StringPrintf("%s: %d", + service_path.c_str(), call_status)); return; } const base::Value* ip_address; diff --git a/chromeos/network/shill_property_handler.h b/chromeos/network/shill_property_handler.h index 32f9f0a..bfb8eaa 100644 --- a/chromeos/network/shill_property_handler.h +++ b/chromeos/network/shill_property_handler.h @@ -91,9 +91,14 @@ class CHROMEOS_EXPORT ShillPropertyHandler explicit ShillPropertyHandler(Listener* listener); virtual ~ShillPropertyHandler(); - // Sends an initial property request and sets up the observer. + // Sets up the observer and calls UpdateManagerProperties(). void Init(); + // Requests all Manager properties. Called from Init() and any time + // properties that do not signal changes might have been updated (e.g. + // ServiceCompleteList). + void UpdateManagerProperties(); + // Returns true if |technology| is available, enabled, etc. bool IsTechnologyAvailable(const std::string& technology) const; bool IsTechnologyEnabled(const std::string& technology) const; @@ -101,7 +106,7 @@ class CHROMEOS_EXPORT ShillPropertyHandler bool IsTechnologyUninitialized(const std::string& technology) const; // Asynchronously sets the enabled state for |technology|. - // Note: Modifes Manager state. Calls |error_callback| on failure. + // Note: Modifies Manager state. Calls |error_callback| on failure. void SetTechnologyEnabled( const std::string& technology, bool enabled, @@ -125,14 +130,33 @@ class CHROMEOS_EXPORT ShillPropertyHandler const base::Value& value) OVERRIDE; private: + typedef std::map<ManagedState::ManagedType, std::set<std::string> > + TypeRequestMap; + // Callback for dbus method fetching properties. void ManagerPropertiesCallback(DBusMethodCallStatus call_status, const base::DictionaryValue& properties); + + // Notifies the listener when a ManagedStateList has changed and all pending + // updates have been received. |key| can either identify the list that + // has changed or an empty string if multiple lists may have changed. + void CheckPendingStateListUpdates(const std::string& key); + // Called form OnPropertyChanged() and ManagerPropertiesCallback(). // Returns true if observers should be notified. bool ManagerPropertyChanged(const std::string& key, const base::Value& value); + // Requests properties for new entries in the list for |type| as follows: + // * Any new Device objects for MANAGED_TYPE_DEVICE + // * Any new Service objects for MANAGED_TYPE_NETWORK + // * Additional new Service objects for MANAGED_TYPE_FAVORITE that were not + // requested for MANAGED_TYPE_NETWORK (i.e. only request objects once). + // For this to avoid duplicate requests, this must be called with + // MANAGED_TYPE_NETWORK before MANAGED_TYPE_FAVORITE. + void UpdateProperties(ManagedState::ManagedType type, + const base::ListValue& entries); + // Updates the Shill property observers to observe any entries for |type|. void UpdateObserved(ManagedState::ManagedType type, const base::ListValue& entries); @@ -164,9 +188,6 @@ class CHROMEOS_EXPORT ShillPropertyHandler void NetworkServicePropertyChangedCallback(const std::string& path, const std::string& key, const base::Value& value); - void NetworkDevicePropertyChangedCallback(const std::string& path, - const std::string& key, - const base::Value& value); // Callback for getting the IPConfig property of a Network. Handled here // instead of in NetworkState so that all asynchronous requests are done @@ -175,6 +196,10 @@ class CHROMEOS_EXPORT ShillPropertyHandler DBusMethodCallStatus call_status, const base::DictionaryValue& properties); + void NetworkDevicePropertyChangedCallback(const std::string& path, + const std::string& key, + const base::Value& value); + // Pointer to containing class (owns this) Listener* listener_; @@ -182,7 +207,11 @@ class CHROMEOS_EXPORT ShillPropertyHandler ShillManagerClient* shill_manager_; // Pending update list for each managed state type - std::map<ManagedState::ManagedType, std::set<std::string> > pending_updates_; + TypeRequestMap pending_updates_; + + // List of states for which properties have been requested, for each managed + // state type + TypeRequestMap requested_updates_; // List of network services with Shill property changed observers ShillPropertyObserverMap observed_networks_; diff --git a/chromeos/network/shill_property_handler_unittest.cc b/chromeos/network/shill_property_handler_unittest.cc index 362b219..9d5b55b 100644 --- a/chromeos/network/shill_property_handler_unittest.cc +++ b/chromeos/network/shill_property_handler_unittest.cc @@ -16,6 +16,7 @@ #include "chromeos/dbus/shill_device_client.h" #include "chromeos/dbus/shill_ipconfig_client.h" #include "chromeos/dbus/shill_manager_client.h" +#include "chromeos/dbus/shill_profile_client.h" #include "chromeos/dbus/shill_service_client.h" #include "dbus/object_path.h" #include "testing/gtest/include/gtest/gtest.h" @@ -47,7 +48,7 @@ class TestListener : public internal::ShillPropertyHandler::Listener { ManagedState::ManagedType type, const std::string& path, const base::DictionaryValue& properties) OVERRIDE { - AddPropertyUpdate(GetTypeString(type), path); + AddInitialPropertyUpdate(GetTypeString(type), path); } virtual void ProfileListChanged() OVERRIDE { @@ -86,6 +87,10 @@ class TestListener : public internal::ShillPropertyHandler::Listener { std::map<std::string, int>& property_updates(const std::string& type) { return property_updates_[type]; } + std::map<std::string, int>& initial_property_updates( + const std::string& type) { + return initial_property_updates_[type]; + } int list_updates(const std::string& type) { return list_updates_[type]; } int manager_updates() { return manager_updates_; } int errors() { return errors_; } @@ -94,6 +99,8 @@ class TestListener : public internal::ShillPropertyHandler::Listener { std::string GetTypeString(ManagedState::ManagedType type) { if (type == ManagedState::MANAGED_TYPE_NETWORK) { return flimflam::kServicesProperty; + } else if (type == ManagedState::MANAGED_TYPE_FAVORITE) { + return shill::kServiceCompleteListProperty; } else if (type == ManagedState::MANAGED_TYPE_DEVICE) { return flimflam::kDevicesProperty; } @@ -120,6 +127,13 @@ class TestListener : public internal::ShillPropertyHandler::Listener { property_updates(type)[path] += 1; } + void AddInitialPropertyUpdate(const std::string& type, + const std::string& path) { + if (type.empty()) + return; + initial_property_updates(type)[path] += 1; + } + void AddStateListUpdate(const std::string& type) { if (type.empty()) return; @@ -130,6 +144,7 @@ class TestListener : public internal::ShillPropertyHandler::Listener { std::map<std::string, std::vector<std::string> > entries_; // Map of list-type -> map of paths -> update counts std::map<std::string, std::map<std::string, int> > property_updates_; + std::map<std::string, std::map<std::string, int> > initial_property_updates_; // Map of list-type -> list update counts std::map<std::string, int > list_updates_; int manager_updates_; @@ -143,7 +158,8 @@ class ShillPropertyHandlerTest : public testing::Test { ShillPropertyHandlerTest() : manager_test_(NULL), device_test_(NULL), - service_test_(NULL) { + service_test_(NULL), + profile_test_(NULL) { } virtual ~ShillPropertyHandlerTest() { } @@ -162,6 +178,9 @@ class ShillPropertyHandlerTest : public testing::Test { service_test_ = DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface(); ASSERT_TRUE(service_test_); + profile_test_ = + DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface(); + ASSERT_TRUE(profile_test_); SetupShillPropertyHandler(); message_loop_.RunUntilIdle(); } @@ -187,7 +206,7 @@ class ShillPropertyHandlerTest : public testing::Test { bool add_to_watch_list) { ASSERT_TRUE(IsValidType(type)); service_test_->AddService(id, id, type, state, - add_to_watch_list); + true /* visible */, add_to_watch_list); } void AddServiceWithIPConfig(const std::string& type, @@ -197,7 +216,21 @@ class ShillPropertyHandlerTest : public testing::Test { bool add_to_watch_list) { ASSERT_TRUE(IsValidType(type)); service_test_->AddServiceWithIPConfig(id, id, type, state, - ipconfig_path, add_to_watch_list); + ipconfig_path, + true /* visible */, + add_to_watch_list); + } + + void AddServiceToProfile(const std::string& type, + const std::string& id, + bool visible) { + service_test_->AddService(id, id, type, flimflam::kStateIdle, + visible, false /* watch */); + std::vector<std::string> profiles; + profile_test_->GetProfilePaths(&profiles); + ASSERT_TRUE(profiles.size() > 0); + base::DictionaryValue properties; // Empty entry + profile_test_->AddService(profiles[0], id); } void RemoveService(const std::string& id) { @@ -246,6 +279,7 @@ class ShillPropertyHandlerTest : public testing::Test { ShillManagerClient::TestInterface* manager_test_; ShillDeviceClient::TestInterface* device_test_; ShillServiceClient::TestInterface* service_test_; + ShillProfileClient::TestInterface* profile_test_; private: DISALLOW_COPY_AND_ASSIGN(ShillPropertyHandlerTest); @@ -333,8 +367,8 @@ TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) { EXPECT_EQ(kNumShillManagerClientStubImplServices + 1, listener_->entries(flimflam::kServicesProperty).size()); // Service receives an initial property update. - EXPECT_EQ(1, listener_-> - property_updates(flimflam::kServicesProperty)[kTestServicePath]); + EXPECT_EQ(1, listener_->initial_property_updates( + flimflam::kServicesProperty)[kTestServicePath]); // Change a property. base::FundamentalValue scan_interval(3); DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( @@ -344,8 +378,8 @@ TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) { base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); message_loop_.RunUntilIdle(); // Property change triggers an update. - EXPECT_EQ(2, listener_-> - property_updates(flimflam::kServicesProperty)[kTestServicePath]); + EXPECT_EQ(1, listener_->property_updates( + flimflam::kServicesProperty)[kTestServicePath]); // Add the existing service to the watch list. AddService(flimflam::kTypeWifi, kTestServicePath, @@ -365,8 +399,8 @@ TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServicePropertyChanged) { base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); message_loop_.RunUntilIdle(); // Property change should trigger another update. - EXPECT_EQ(3, listener_-> - property_updates(flimflam::kServicesProperty)[kTestServicePath]); + EXPECT_EQ(2, listener_->property_updates( + flimflam::kServicesProperty)[kTestServicePath]); // Remove a service RemoveService(kTestServicePath); @@ -404,8 +438,8 @@ TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerIPConfigPropertyChanged) { flimflam::kStateIdle, true); message_loop_.RunUntilIdle(); // This is the initial property update. - EXPECT_EQ(1, listener_-> - property_updates(flimflam::kServicesProperty)[kTestServicePath1]); + EXPECT_EQ(1, listener_->initial_property_updates( + flimflam::kServicesProperty)[kTestServicePath1]); DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( dbus::ObjectPath(kTestServicePath1), shill::kIPConfigProperty, @@ -414,8 +448,8 @@ TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerIPConfigPropertyChanged) { message_loop_.RunUntilIdle(); // IPConfig property change on the service should trigger property updates for // IP Address and DNS. - EXPECT_EQ(3, listener_-> - property_updates(flimflam::kServicesProperty)[kTestServicePath1]); + EXPECT_EQ(2, listener_->property_updates( + flimflam::kServicesProperty)[kTestServicePath1]); // Now, Add a new watched service with the IPConfig already set. const std::string kTestServicePath2("test_wifi_service2"); @@ -424,8 +458,68 @@ TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerIPConfigPropertyChanged) { message_loop_.RunUntilIdle(); // A watched service with the IPConfig property already set must // trigger property updates for IP Address and DNS when added. - EXPECT_EQ(3, listener_-> - property_updates(flimflam::kServicesProperty)[kTestServicePath2]); + EXPECT_EQ(2, listener_->property_updates( + flimflam::kServicesProperty)[kTestServicePath2]); +} + +TEST_F(ShillPropertyHandlerTest, ShillPropertyHandlerServiceCompleteList) { + // Initial list updates. + EXPECT_EQ(1, listener_->list_updates(flimflam::kServicesProperty)); + EXPECT_EQ(1, listener_->list_updates(shill::kServiceCompleteListProperty)); + + // Add a new entry to the profile only; should trigger a single list update + // for both Services and ServiceCompleteList, and a single property update + // for ServiceCompleteList. + const std::string kTestServicePath1("stub_wifi_profile_only1"); + AddServiceToProfile(flimflam::kTypeWifi, kTestServicePath1, false); + shill_property_handler_->UpdateManagerProperties(); + message_loop_.RunUntilIdle(); + EXPECT_EQ(2, listener_->list_updates(flimflam::kServicesProperty)); + EXPECT_EQ(2, listener_->list_updates(shill::kServiceCompleteListProperty)); + EXPECT_EQ(0, listener_->initial_property_updates( + flimflam::kServicesProperty)[kTestServicePath1]); + EXPECT_EQ(1, listener_->initial_property_updates( + shill::kServiceCompleteListProperty)[kTestServicePath1]); + EXPECT_EQ(0, listener_->property_updates( + flimflam::kServicesProperty)[kTestServicePath1]); + EXPECT_EQ(0, listener_->property_updates( + shill::kServiceCompleteListProperty)[kTestServicePath1]); + + // Add a new entry to the services and the profile; should also trigger a + // single list update for both Services and ServiceCompleteList, and should + // trigger tow property updates for Services (one when the Profile propety + // changes, and one for the Request) and one ServiceCompleteList change for + // the Request. + const std::string kTestServicePath2("stub_wifi_profile_only2"); + AddServiceToProfile(flimflam::kTypeWifi, kTestServicePath2, true); + shill_property_handler_->UpdateManagerProperties(); + message_loop_.RunUntilIdle(); + EXPECT_EQ(3, listener_->list_updates(flimflam::kServicesProperty)); + EXPECT_EQ(3, listener_->list_updates(shill::kServiceCompleteListProperty)); + EXPECT_EQ(1, listener_->initial_property_updates( + flimflam::kServicesProperty)[kTestServicePath2]); + EXPECT_EQ(1, listener_->initial_property_updates( + shill::kServiceCompleteListProperty)[kTestServicePath2]); + // Expect one property update for the Profile property of the Network. + EXPECT_EQ(1, listener_->property_updates( + flimflam::kServicesProperty)[kTestServicePath2]); + EXPECT_EQ(0, listener_->property_updates( + shill::kServiceCompleteListProperty)[kTestServicePath2]); + + // Change a property of a Network in a Profile. + base::FundamentalValue scan_interval(3); + DBusThreadManager::Get()->GetShillServiceClient()->SetProperty( + dbus::ObjectPath(kTestServicePath2), + flimflam::kScanIntervalProperty, + scan_interval, + base::Bind(&base::DoNothing), base::Bind(&ErrorCallbackFunction)); + message_loop_.RunUntilIdle(); + // Property change should trigger an update for the Network only; no + // property updates pushed by Shill affect Favorites. + EXPECT_EQ(2, listener_->property_updates( + flimflam::kServicesProperty)[kTestServicePath2]); + EXPECT_EQ(0, listener_->property_updates( + shill::kServiceCompleteListProperty)[kTestServicePath2]); } } // namespace chromeos |