1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chromeos/network/network_profile_handler.h" 6 7 #include <algorithm> 8 9 #include "base/bind.h" 10 #include "base/strings/string_util.h" 11 #include "base/values.h" 12 #include "chromeos/dbus/dbus_thread_manager.h" 13 #include "chromeos/dbus/shill_manager_client.h" 14 #include "chromeos/dbus/shill_profile_client.h" 15 #include "chromeos/network/network_profile_observer.h" 16 #include "chromeos/network/network_state_handler.h" 17 #include "dbus/object_path.h" 18 #include "third_party/cros_system_api/dbus/service_constants.h" 19 20 namespace chromeos { 21 22 namespace { 23 24 bool ConvertListValueToStringVector(const base::ListValue& string_list, 25 std::vector<std::string>* result) { 26 for (size_t i = 0; i < string_list.GetSize(); ++i) { 27 std::string str; 28 if (!string_list.GetString(i, &str)) 29 return false; 30 result->push_back(str); 31 } 32 return true; 33 } 34 35 void LogProfileRequestError(const std::string& profile_path, 36 const std::string& error_name, 37 const std::string& error_message) { 38 LOG(ERROR) << "Error when requesting properties for profile " 39 << profile_path << ": " << error_message; 40 } 41 42 class ProfilePathEquals { 43 public: 44 explicit ProfilePathEquals(const std::string& path) 45 : path_(path) { 46 } 47 48 bool operator()(const NetworkProfile& profile) { 49 return profile.path == path_; 50 } 51 52 private: 53 std::string path_; 54 }; 55 56 } // namespace 57 58 // static 59 const char NetworkProfileHandler::kSharedProfilePath[] = "/profile/default"; 60 61 void NetworkProfileHandler::AddObserver(NetworkProfileObserver* observer) { 62 observers_.AddObserver(observer); 63 } 64 65 void NetworkProfileHandler::RemoveObserver(NetworkProfileObserver* observer) { 66 observers_.RemoveObserver(observer); 67 } 68 69 void NetworkProfileHandler::GetManagerPropertiesCallback( 70 DBusMethodCallStatus call_status, 71 const base::DictionaryValue& properties) { 72 if (DBUS_METHOD_CALL_FAILURE) { 73 LOG(ERROR) << "Error when requesting manager properties."; 74 return; 75 } 76 77 const base::Value* profiles = NULL; 78 properties.GetWithoutPathExpansion(flimflam::kProfilesProperty, &profiles); 79 if (!profiles) { 80 LOG(ERROR) << "Manager properties returned from Shill don't contain " 81 << "the field " << flimflam::kProfilesProperty; 82 return; 83 } 84 OnPropertyChanged(flimflam::kProfilesProperty, *profiles); 85 } 86 87 void NetworkProfileHandler::OnPropertyChanged(const std::string& name, 88 const base::Value& value) { 89 if (name != flimflam::kProfilesProperty) 90 return; 91 92 const base::ListValue* profiles_value = NULL; 93 value.GetAsList(&profiles_value); 94 DCHECK(profiles_value); 95 96 std::vector<std::string> new_profile_paths; 97 bool result = ConvertListValueToStringVector(*profiles_value, 98 &new_profile_paths); 99 DCHECK(result); 100 101 VLOG(2) << "Profiles: " << profiles_.size(); 102 // Search for removed profiles. 103 std::vector<std::string> removed_profile_paths; 104 for (ProfileList::const_iterator it = profiles_.begin(); 105 it != profiles_.end(); ++it) { 106 if (std::find(new_profile_paths.begin(), 107 new_profile_paths.end(), 108 it->path) == new_profile_paths.end()) { 109 removed_profile_paths.push_back(it->path); 110 } 111 } 112 113 for (std::vector<std::string>::const_iterator it = 114 removed_profile_paths.begin(); 115 it != removed_profile_paths.end(); ++it) { 116 RemoveProfile(*it); 117 } 118 119 for (std::vector<std::string>::const_iterator it = new_profile_paths.begin(); 120 it != new_profile_paths.end(); ++it) { 121 // Skip known profiles. The associated userhash should never change. 122 if (GetProfileForPath(*it)) 123 continue; 124 125 VLOG(2) << "Requesting properties of profile path " << *it << "."; 126 DBusThreadManager::Get()->GetShillProfileClient()->GetProperties( 127 dbus::ObjectPath(*it), 128 base::Bind(&NetworkProfileHandler::GetProfilePropertiesCallback, 129 weak_ptr_factory_.GetWeakPtr(), 130 *it), 131 base::Bind(&LogProfileRequestError, *it)); 132 } 133 134 // When the profile list changes, ServiceCompleteList may also change, so 135 // trigger a Manager update to request the updated list. 136 if (network_state_handler_) 137 network_state_handler_->UpdateManagerProperties(); 138 } 139 140 void NetworkProfileHandler::GetProfilePropertiesCallback( 141 const std::string& profile_path, 142 const base::DictionaryValue& properties) { 143 std::string userhash; 144 properties.GetStringWithoutPathExpansion(shill::kUserHashProperty, 145 &userhash); 146 147 AddProfile(NetworkProfile(profile_path, userhash)); 148 } 149 150 void NetworkProfileHandler::AddProfile(const NetworkProfile& profile) { 151 VLOG(2) << "Adding profile " << profile.ToDebugString() << "."; 152 profiles_.push_back(profile); 153 FOR_EACH_OBSERVER(NetworkProfileObserver, observers_, 154 OnProfileAdded(profiles_.back())); 155 } 156 157 void NetworkProfileHandler::RemoveProfile(const std::string& profile_path) { 158 VLOG(2) << "Removing profile for path " << profile_path << "."; 159 ProfileList::iterator found = std::find_if(profiles_.begin(), profiles_.end(), 160 ProfilePathEquals(profile_path)); 161 if (found == profiles_.end()) 162 return; 163 NetworkProfile profile = *found; 164 profiles_.erase(found); 165 FOR_EACH_OBSERVER(NetworkProfileObserver, observers_, 166 OnProfileRemoved(profile)); 167 } 168 169 const NetworkProfile* NetworkProfileHandler::GetProfileForPath( 170 const std::string& profile_path) const { 171 ProfileList::const_iterator found = 172 std::find_if(profiles_.begin(), profiles_.end(), 173 ProfilePathEquals(profile_path)); 174 175 if (found == profiles_.end()) 176 return NULL; 177 return &*found; 178 } 179 180 const NetworkProfile* NetworkProfileHandler::GetProfileForUserhash( 181 const std::string& userhash) const { 182 for (NetworkProfileHandler::ProfileList::const_iterator it = 183 profiles_.begin(); 184 it != profiles_.end(); ++it) { 185 if (it->userhash == userhash) 186 return &*it; 187 } 188 return NULL; 189 } 190 191 const NetworkProfile* NetworkProfileHandler::GetDefaultUserProfile() const { 192 for (NetworkProfileHandler::ProfileList::const_iterator it = 193 profiles_.begin(); 194 it != profiles_.end(); ++it) { 195 if (!it->userhash.empty()) 196 return &*it; 197 } 198 return NULL; 199 } 200 201 NetworkProfileHandler::NetworkProfileHandler() 202 : network_state_handler_(NULL), 203 weak_ptr_factory_(this) { 204 } 205 206 void NetworkProfileHandler::Init(NetworkStateHandler* network_state_handler) { 207 network_state_handler_ = network_state_handler; 208 209 DBusThreadManager::Get()->GetShillManagerClient()-> 210 AddPropertyChangedObserver(this); 211 212 // Request the initial profile list. 213 DBusThreadManager::Get()->GetShillManagerClient()->GetProperties( 214 base::Bind(&NetworkProfileHandler::GetManagerPropertiesCallback, 215 weak_ptr_factory_.GetWeakPtr())); 216 } 217 218 NetworkProfileHandler::~NetworkProfileHandler() { 219 DBusThreadManager::Get()->GetShillManagerClient()-> 220 RemovePropertyChangedObserver(this); 221 } 222 223 } // namespace chromeos 224