network_profile_handler.cc revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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
59const char NetworkProfileHandler::kSharedProfilePath[] = "/profile/default";
60
61void NetworkProfileHandler::AddObserver(NetworkProfileObserver* observer) {
62  observers_.AddObserver(observer);
63}
64
65void NetworkProfileHandler::RemoveObserver(NetworkProfileObserver* observer) {
66  observers_.RemoveObserver(observer);
67}
68
69void 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(shill::kProfilesProperty, &profiles);
79  if (!profiles) {
80    LOG(ERROR) << "Manager properties returned from Shill don't contain "
81               << "the field " << shill::kProfilesProperty;
82    return;
83  }
84  OnPropertyChanged(shill::kProfilesProperty, *profiles);
85}
86
87void NetworkProfileHandler::OnPropertyChanged(const std::string& name,
88                                              const base::Value& value) {
89  if (name != shill::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
140void NetworkProfileHandler::GetProfilePropertiesCallback(
141    const std::string& profile_path,
142    const base::DictionaryValue& properties) {
143  std::string userhash;
144  properties.GetStringWithoutPathExpansion(shill::kUserHashProperty, &userhash);
145
146  AddProfile(NetworkProfile(profile_path, userhash));
147}
148
149void NetworkProfileHandler::AddProfile(const NetworkProfile& profile) {
150  VLOG(2) << "Adding profile " << profile.ToDebugString() << ".";
151  profiles_.push_back(profile);
152  FOR_EACH_OBSERVER(NetworkProfileObserver, observers_,
153                    OnProfileAdded(profiles_.back()));
154}
155
156void NetworkProfileHandler::RemoveProfile(const std::string& profile_path) {
157  VLOG(2) << "Removing profile for path " << profile_path << ".";
158  ProfileList::iterator found = std::find_if(profiles_.begin(), profiles_.end(),
159                                             ProfilePathEquals(profile_path));
160  if (found == profiles_.end())
161    return;
162  NetworkProfile profile = *found;
163  profiles_.erase(found);
164  FOR_EACH_OBSERVER(NetworkProfileObserver, observers_,
165                    OnProfileRemoved(profile));
166}
167
168const NetworkProfile* NetworkProfileHandler::GetProfileForPath(
169    const std::string& profile_path) const {
170  ProfileList::const_iterator found =
171      std::find_if(profiles_.begin(), profiles_.end(),
172                   ProfilePathEquals(profile_path));
173
174  if (found == profiles_.end())
175    return NULL;
176  return &*found;
177}
178
179const NetworkProfile* NetworkProfileHandler::GetProfileForUserhash(
180    const std::string& userhash) const {
181  for (NetworkProfileHandler::ProfileList::const_iterator it =
182           profiles_.begin();
183       it != profiles_.end(); ++it) {
184    if (it->userhash == userhash)
185      return &*it;
186  }
187  return NULL;
188}
189
190const NetworkProfile* NetworkProfileHandler::GetDefaultUserProfile() const {
191  for (NetworkProfileHandler::ProfileList::const_iterator it =
192           profiles_.begin();
193       it != profiles_.end(); ++it) {
194    if (!it->userhash.empty())
195      return &*it;
196  }
197  return NULL;
198}
199
200NetworkProfileHandler::NetworkProfileHandler()
201    : network_state_handler_(NULL),
202      weak_ptr_factory_(this) {
203}
204
205void NetworkProfileHandler::Init(NetworkStateHandler* network_state_handler) {
206  network_state_handler_ = network_state_handler;
207
208  DBusThreadManager::Get()->GetShillManagerClient()->
209      AddPropertyChangedObserver(this);
210
211  // Request the initial profile list.
212  DBusThreadManager::Get()->GetShillManagerClient()->GetProperties(
213      base::Bind(&NetworkProfileHandler::GetManagerPropertiesCallback,
214                 weak_ptr_factory_.GetWeakPtr()));
215}
216
217NetworkProfileHandler::~NetworkProfileHandler() {
218  DBusThreadManager::Get()->GetShillManagerClient()->
219      RemovePropertyChangedObserver(this);
220}
221
222}  // namespace chromeos
223