// Copyright (c) 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/network_profile_handler.h" #include #include #include "base/bind.h" #include "base/strings/string_util.h" #include "base/values.h" #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/shill_manager_client.h" #include "chromeos/dbus/shill_profile_client.h" #include "chromeos/network/network_profile_observer.h" #include "dbus/object_path.h" #include "third_party/cros_system_api/dbus/service_constants.h" namespace chromeos { namespace { bool ConvertListValueToStringVector(const base::ListValue& string_list, std::vector* result) { for (size_t i = 0; i < string_list.GetSize(); ++i) { std::string str; if (!string_list.GetString(i, &str)) return false; result->push_back(str); } return true; } void LogProfileRequestError(const std::string& profile_path, const std::string& error_name, const std::string& error_message) { LOG(ERROR) << "Error when requesting properties for profile " << profile_path << ": " << error_message; } class ProfilePathEquals { public: explicit ProfilePathEquals(const std::string& path) : path_(path) { } bool operator()(const NetworkProfile& profile) { return profile.path == path_; } private: std::string path_; }; } // namespace // static std::string NetworkProfileHandler::GetSharedProfilePath() { return ShillProfileClient::GetSharedProfilePath(); } void NetworkProfileHandler::AddObserver(NetworkProfileObserver* observer) { observers_.AddObserver(observer); } void NetworkProfileHandler::RemoveObserver(NetworkProfileObserver* observer) { observers_.RemoveObserver(observer); } void NetworkProfileHandler::GetManagerPropertiesCallback( DBusMethodCallStatus call_status, const base::DictionaryValue& properties) { if (DBUS_METHOD_CALL_FAILURE) { LOG(ERROR) << "Error when requesting manager properties."; return; } const base::Value* profiles = NULL; properties.GetWithoutPathExpansion(shill::kProfilesProperty, &profiles); if (!profiles) { LOG(ERROR) << "Manager properties returned from Shill don't contain " << "the field " << shill::kProfilesProperty; return; } OnPropertyChanged(shill::kProfilesProperty, *profiles); } void NetworkProfileHandler::OnPropertyChanged(const std::string& name, const base::Value& value) { if (name != shill::kProfilesProperty) return; const base::ListValue* profiles_value = NULL; value.GetAsList(&profiles_value); DCHECK(profiles_value); std::vector new_profile_paths; bool result = ConvertListValueToStringVector(*profiles_value, &new_profile_paths); DCHECK(result); VLOG(2) << "Profiles: " << profiles_.size(); // Search for removed profiles. std::vector removed_profile_paths; for (ProfileList::const_iterator it = profiles_.begin(); it != profiles_.end(); ++it) { if (std::find(new_profile_paths.begin(), new_profile_paths.end(), it->path) == new_profile_paths.end()) { removed_profile_paths.push_back(it->path); } } for (const std::string& profile_path : removed_profile_paths) { RemoveProfile(profile_path); // Also stop pending creations of this profile. pending_profile_creations_.erase(profile_path); } for (std::vector::const_iterator it = new_profile_paths.begin(); it != new_profile_paths.end(); ++it) { // Skip known profiles. The associated userhash should never change. if (GetProfileForPath(*it) || pending_profile_creations_.count(*it) > 0) continue; pending_profile_creations_.insert(*it); VLOG(2) << "Requesting properties of profile path " << *it << "."; DBusThreadManager::Get()->GetShillProfileClient()->GetProperties( dbus::ObjectPath(*it), base::Bind(&NetworkProfileHandler::GetProfilePropertiesCallback, weak_ptr_factory_.GetWeakPtr(), *it), base::Bind(&LogProfileRequestError, *it)); } } void NetworkProfileHandler::GetProfilePropertiesCallback( const std::string& profile_path, const base::DictionaryValue& properties) { if (pending_profile_creations_.erase(profile_path) == 0) { VLOG(1) << "Ignore received properties, profile was removed."; return; } if (GetProfileForPath(profile_path)) { VLOG(1) << "Ignore received properties, profile is already created."; return; } std::string userhash; properties.GetStringWithoutPathExpansion(shill::kUserHashProperty, &userhash); AddProfile(NetworkProfile(profile_path, userhash)); } void NetworkProfileHandler::AddProfile(const NetworkProfile& profile) { VLOG(2) << "Adding profile " << profile.ToDebugString() << "."; profiles_.push_back(profile); FOR_EACH_OBSERVER(NetworkProfileObserver, observers_, OnProfileAdded(profiles_.back())); } void NetworkProfileHandler::RemoveProfile(const std::string& profile_path) { VLOG(2) << "Removing profile for path " << profile_path << "."; ProfileList::iterator found = std::find_if(profiles_.begin(), profiles_.end(), ProfilePathEquals(profile_path)); if (found == profiles_.end()) return; NetworkProfile profile = *found; profiles_.erase(found); FOR_EACH_OBSERVER(NetworkProfileObserver, observers_, OnProfileRemoved(profile)); } const NetworkProfile* NetworkProfileHandler::GetProfileForPath( const std::string& profile_path) const { ProfileList::const_iterator found = std::find_if(profiles_.begin(), profiles_.end(), ProfilePathEquals(profile_path)); if (found == profiles_.end()) return NULL; return &*found; } const NetworkProfile* NetworkProfileHandler::GetProfileForUserhash( const std::string& userhash) const { for (NetworkProfileHandler::ProfileList::const_iterator it = profiles_.begin(); it != profiles_.end(); ++it) { if (it->userhash == userhash) return &*it; } return NULL; } const NetworkProfile* NetworkProfileHandler::GetDefaultUserProfile() const { for (NetworkProfileHandler::ProfileList::const_iterator it = profiles_.begin(); it != profiles_.end(); ++it) { if (!it->userhash.empty()) return &*it; } return NULL; } NetworkProfileHandler::NetworkProfileHandler() : weak_ptr_factory_(this) { } void NetworkProfileHandler::Init() { DBusThreadManager::Get()->GetShillManagerClient()-> AddPropertyChangedObserver(this); // Request the initial profile list. DBusThreadManager::Get()->GetShillManagerClient()->GetProperties( base::Bind(&NetworkProfileHandler::GetManagerPropertiesCallback, weak_ptr_factory_.GetWeakPtr())); } NetworkProfileHandler::~NetworkProfileHandler() { DBusThreadManager::Get()->GetShillManagerClient()-> RemovePropertyChangedObserver(this); } } // namespace chromeos