network_profile_handler.cc revision b2df76ea8fec9e32f6f3718986dba0d95315b29c
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/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 "dbus/object_path.h"
17#include "third_party/cros_system_api/dbus/service_constants.h"
18
19namespace chromeos {
20
21static NetworkProfileHandler* g_profile_handler_instance = NULL;
22
23namespace {
24
25bool ConvertListValueToStringVector(const base::ListValue& string_list,
26                                    std::vector<std::string>* result) {
27  for (size_t i = 0; i < string_list.GetSize(); ++i) {
28    std::string str;
29    if (!string_list.GetString(i, &str))
30      return false;
31    result->push_back(str);
32  }
33  return true;
34}
35
36void LogProfileRequestError(const std::string& profile_path,
37                            const std::string& error_name,
38                            const std::string& error_message) {
39  LOG(ERROR) << "Error when requesting properties for profile "
40             << profile_path << ": " << error_message;
41}
42
43class ProfilePathEquals {
44 public:
45  explicit ProfilePathEquals(const std::string& path)
46      : path_(path) {
47  }
48
49  bool operator()(const NetworkProfile& profile) {
50    return profile.path == path_;
51  }
52
53 private:
54  std::string path_;
55};
56
57class NetworkProfileHandlerImpl : public NetworkProfileHandler {
58 public:
59  NetworkProfileHandlerImpl() {
60    DBusThreadManager::Get()->GetShillManagerClient()->
61        AddPropertyChangedObserver(this);
62
63    // Request the initial profile list.
64    DBusThreadManager::Get()->GetShillManagerClient()->GetProperties(
65        base::Bind(&NetworkProfileHandler::GetManagerPropertiesCallback,
66                   weak_ptr_factory_.GetWeakPtr()));
67  }
68
69  virtual ~NetworkProfileHandlerImpl() {
70    DBusThreadManager::Get()->GetShillManagerClient()->
71        RemovePropertyChangedObserver(this);
72  }
73};
74
75}  // namespace
76
77// static
78NetworkProfileHandler* NetworkProfileHandler::Initialize() {
79  CHECK(!g_profile_handler_instance);
80  g_profile_handler_instance = new NetworkProfileHandlerImpl();
81  return g_profile_handler_instance;
82}
83
84// static
85bool NetworkProfileHandler::IsInitialized() {
86  return g_profile_handler_instance;
87}
88
89// static
90void NetworkProfileHandler::Shutdown() {
91  CHECK(g_profile_handler_instance);
92  delete g_profile_handler_instance;
93  g_profile_handler_instance = NULL;
94}
95
96// static
97NetworkProfileHandler* NetworkProfileHandler::Get() {
98  CHECK(g_profile_handler_instance);
99  return g_profile_handler_instance;
100}
101
102void NetworkProfileHandler::AddObserver(NetworkProfileObserver* observer) {
103  observers_.AddObserver(observer);
104}
105
106void NetworkProfileHandler::RemoveObserver(NetworkProfileObserver* observer) {
107  observers_.RemoveObserver(observer);
108}
109
110void NetworkProfileHandler::GetManagerPropertiesCallback(
111    DBusMethodCallStatus call_status,
112    const base::DictionaryValue& properties) {
113  if (DBUS_METHOD_CALL_FAILURE) {
114    LOG(ERROR) << "Error when requesting manager properties.";
115    return;
116  }
117
118  const base::Value* profiles = NULL;
119  properties.GetWithoutPathExpansion(flimflam::kProfilesProperty, &profiles);
120  if (!profiles) {
121    LOG(ERROR) << "Manager properties returned from Shill don't contain "
122               << "the field " << flimflam::kProfilesProperty;
123    return;
124  }
125  OnPropertyChanged(flimflam::kProfilesProperty, *profiles);
126}
127
128void NetworkProfileHandler::OnPropertyChanged(const std::string& name,
129                                              const base::Value& value) {
130  if (name != flimflam::kProfilesProperty)
131    return;
132
133  const base::ListValue* profiles_value = NULL;
134  value.GetAsList(&profiles_value);
135  DCHECK(profiles_value);
136
137  std::vector<std::string> new_profile_paths;
138  bool result = ConvertListValueToStringVector(*profiles_value,
139                                               &new_profile_paths);
140  DCHECK(result);
141
142  // Search for removed profiles.
143  std::vector<std::string> removed_profile_paths;
144  for (ProfileList::const_iterator it = profiles_.begin();
145       it != profiles_.end(); ++it) {
146    if (std::find(new_profile_paths.begin(),
147                  new_profile_paths.end(),
148                  it->path) == new_profile_paths.end()) {
149      removed_profile_paths.push_back(it->path);
150    }
151  }
152
153  for (std::vector<std::string>::const_iterator it =
154           removed_profile_paths.begin();
155       it != removed_profile_paths.end(); ++it) {
156    RemoveProfile(*it);
157  }
158
159  for (std::vector<std::string>::const_iterator it = new_profile_paths.begin();
160       it != new_profile_paths.end(); ++it) {
161    // Skip known profiles. The associated userhash should never change.
162    if (GetProfileForPath(*it))
163      continue;
164
165    VLOG(2) << "Requesting properties of profile path " << *it << ".";
166    DBusThreadManager::Get()->GetShillProfileClient()->GetProperties(
167        dbus::ObjectPath(*it),
168        base::Bind(&NetworkProfileHandler::GetProfilePropertiesCallback,
169                   weak_ptr_factory_.GetWeakPtr(),
170                   *it),
171        base::Bind(&LogProfileRequestError, *it));
172  }
173}
174
175void NetworkProfileHandler::GetProfilePropertiesCallback(
176    const std::string& profile_path,
177    const base::DictionaryValue& properties) {
178  std::string userhash;
179  properties.GetStringWithoutPathExpansion(shill::kUserHashProperty,
180                                           &userhash);
181
182  AddProfile(NetworkProfile(profile_path, userhash));
183}
184
185void NetworkProfileHandler::AddProfile(const NetworkProfile& profile) {
186  VLOG(2) << "Adding profile " << profile.ToDebugString() << ".";
187  profiles_.push_back(profile);
188  FOR_EACH_OBSERVER(NetworkProfileObserver, observers_,
189                    OnProfileAdded(profiles_.back()));
190}
191
192void NetworkProfileHandler::RemoveProfile(const std::string& profile_path) {
193  VLOG(2) << "Removing profile for path " << profile_path << ".";
194  ProfileList::iterator found = std::find_if(profiles_.begin(), profiles_.end(),
195                                             ProfilePathEquals(profile_path));
196  if (found == profiles_.end())
197    return;
198  NetworkProfile profile = *found;
199  profiles_.erase(found);
200  FOR_EACH_OBSERVER(NetworkProfileObserver, observers_,
201                    OnProfileRemoved(profile));
202}
203
204const NetworkProfile* NetworkProfileHandler::GetProfileForPath(
205    const std::string& profile_path) const {
206  ProfileList::const_iterator found =
207      std::find_if(profiles_.begin(), profiles_.end(),
208                   ProfilePathEquals(profile_path));
209
210  if (found == profiles_.end())
211    return NULL;
212  return &*found;
213}
214
215const NetworkProfile* NetworkProfileHandler::GetProfileForUserhash(
216    const std::string& userhash) const {
217  for (NetworkProfileHandler::ProfileList::const_iterator it =
218           profiles_.begin();
219       it != profiles_.end(); ++it) {
220    if (it->userhash == userhash)
221      return &*it;
222  }
223  return NULL;
224}
225
226NetworkProfileHandler::NetworkProfileHandler()
227    : weak_ptr_factory_(this) {
228}
229
230NetworkProfileHandler::~NetworkProfileHandler() {
231}
232
233}  // namespace chromeos
234