network_profile_handler.cc revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
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
20namespace chromeos {
21
22namespace {
23
24bool 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
35void 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
42class 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
59std::string NetworkProfileHandler::GetSharedProfilePath() {
60  return ShillProfileClient::GetSharedProfilePath();
61}
62
63void NetworkProfileHandler::AddObserver(NetworkProfileObserver* observer) {
64  observers_.AddObserver(observer);
65}
66
67void NetworkProfileHandler::RemoveObserver(NetworkProfileObserver* observer) {
68  observers_.RemoveObserver(observer);
69}
70
71void NetworkProfileHandler::GetManagerPropertiesCallback(
72    DBusMethodCallStatus call_status,
73    const base::DictionaryValue& properties) {
74  if (DBUS_METHOD_CALL_FAILURE) {
75    LOG(ERROR) << "Error when requesting manager properties.";
76    return;
77  }
78
79  const base::Value* profiles = NULL;
80  properties.GetWithoutPathExpansion(shill::kProfilesProperty, &profiles);
81  if (!profiles) {
82    LOG(ERROR) << "Manager properties returned from Shill don't contain "
83               << "the field " << shill::kProfilesProperty;
84    return;
85  }
86  OnPropertyChanged(shill::kProfilesProperty, *profiles);
87}
88
89void NetworkProfileHandler::OnPropertyChanged(const std::string& name,
90                                              const base::Value& value) {
91  if (name != shill::kProfilesProperty)
92    return;
93
94  const base::ListValue* profiles_value = NULL;
95  value.GetAsList(&profiles_value);
96  DCHECK(profiles_value);
97
98  std::vector<std::string> new_profile_paths;
99  bool result = ConvertListValueToStringVector(*profiles_value,
100                                               &new_profile_paths);
101  DCHECK(result);
102
103  VLOG(2) << "Profiles: " << profiles_.size();
104  // Search for removed profiles.
105  std::vector<std::string> removed_profile_paths;
106  for (ProfileList::const_iterator it = profiles_.begin();
107       it != profiles_.end(); ++it) {
108    if (std::find(new_profile_paths.begin(),
109                  new_profile_paths.end(),
110                  it->path) == new_profile_paths.end()) {
111      removed_profile_paths.push_back(it->path);
112    }
113  }
114
115  for (std::vector<std::string>::const_iterator it =
116           removed_profile_paths.begin();
117       it != removed_profile_paths.end(); ++it) {
118    RemoveProfile(*it);
119  }
120
121  for (std::vector<std::string>::const_iterator it = new_profile_paths.begin();
122       it != new_profile_paths.end(); ++it) {
123    // Skip known profiles. The associated userhash should never change.
124    if (GetProfileForPath(*it))
125      continue;
126
127    VLOG(2) << "Requesting properties of profile path " << *it << ".";
128    DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
129        dbus::ObjectPath(*it),
130        base::Bind(&NetworkProfileHandler::GetProfilePropertiesCallback,
131                   weak_ptr_factory_.GetWeakPtr(),
132                   *it),
133        base::Bind(&LogProfileRequestError, *it));
134  }
135
136  // When the profile list changes, ServiceCompleteList may also change, so
137  // trigger a Manager update to request the updated list.
138  if (network_state_handler_)
139    network_state_handler_->UpdateManagerProperties();
140}
141
142void NetworkProfileHandler::GetProfilePropertiesCallback(
143    const std::string& profile_path,
144    const base::DictionaryValue& properties) {
145  std::string userhash;
146  properties.GetStringWithoutPathExpansion(shill::kUserHashProperty, &userhash);
147
148  AddProfile(NetworkProfile(profile_path, userhash));
149}
150
151void NetworkProfileHandler::AddProfile(const NetworkProfile& profile) {
152  VLOG(2) << "Adding profile " << profile.ToDebugString() << ".";
153  profiles_.push_back(profile);
154  FOR_EACH_OBSERVER(NetworkProfileObserver, observers_,
155                    OnProfileAdded(profiles_.back()));
156}
157
158void NetworkProfileHandler::RemoveProfile(const std::string& profile_path) {
159  VLOG(2) << "Removing profile for path " << profile_path << ".";
160  ProfileList::iterator found = std::find_if(profiles_.begin(), profiles_.end(),
161                                             ProfilePathEquals(profile_path));
162  if (found == profiles_.end())
163    return;
164  NetworkProfile profile = *found;
165  profiles_.erase(found);
166  FOR_EACH_OBSERVER(NetworkProfileObserver, observers_,
167                    OnProfileRemoved(profile));
168}
169
170const NetworkProfile* NetworkProfileHandler::GetProfileForPath(
171    const std::string& profile_path) const {
172  ProfileList::const_iterator found =
173      std::find_if(profiles_.begin(), profiles_.end(),
174                   ProfilePathEquals(profile_path));
175
176  if (found == profiles_.end())
177    return NULL;
178  return &*found;
179}
180
181const NetworkProfile* NetworkProfileHandler::GetProfileForUserhash(
182    const std::string& userhash) const {
183  for (NetworkProfileHandler::ProfileList::const_iterator it =
184           profiles_.begin();
185       it != profiles_.end(); ++it) {
186    if (it->userhash == userhash)
187      return &*it;
188  }
189  return NULL;
190}
191
192const NetworkProfile* NetworkProfileHandler::GetDefaultUserProfile() const {
193  for (NetworkProfileHandler::ProfileList::const_iterator it =
194           profiles_.begin();
195       it != profiles_.end(); ++it) {
196    if (!it->userhash.empty())
197      return &*it;
198  }
199  return NULL;
200}
201
202NetworkProfileHandler::NetworkProfileHandler()
203    : network_state_handler_(NULL),
204      weak_ptr_factory_(this) {
205}
206
207void NetworkProfileHandler::Init(NetworkStateHandler* network_state_handler) {
208  network_state_handler_ = network_state_handler;
209
210  DBusThreadManager::Get()->GetShillManagerClient()->
211      AddPropertyChangedObserver(this);
212
213  // Request the initial profile list.
214  DBusThreadManager::Get()->GetShillManagerClient()->GetProperties(
215      base::Bind(&NetworkProfileHandler::GetManagerPropertiesCallback,
216                 weak_ptr_factory_.GetWeakPtr()));
217}
218
219NetworkProfileHandler::~NetworkProfileHandler() {
220  DBusThreadManager::Get()->GetShillManagerClient()->
221      RemovePropertyChangedObserver(this);
222}
223
224}  // namespace chromeos
225