shill_property_handler.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
1// Copyright (c) 2012 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/shill_property_handler.h"
6
7#include "base/bind.h"
8#include "base/stl_util.h"
9#include "base/string_util.h"
10#include "base/values.h"
11#include "chromeos/dbus/dbus_thread_manager.h"
12#include "chromeos/dbus/shill_device_client.h"
13#include "chromeos/dbus/shill_ipconfig_client.h"
14#include "chromeos/dbus/shill_manager_client.h"
15#include "chromeos/dbus/shill_service_client.h"
16#include "chromeos/network/shill_service_observer.h"
17#include "dbus/object_path.h"
18#include "third_party/cros_system_api/dbus/service_constants.h"
19
20namespace {
21
22// Limit the number of services we observe. Since they are listed in priority
23// order, it should be reasonable to ignore services past this.
24const size_t kMaxObservedServices = 100;
25
26void ErrorCallbackFunction(const std::string& error_name,
27                           const std::string& error_message) {
28  // TODO(stevenjb): Add error logging.
29  LOG(ERROR) << "Shill Error: " << error_name << " : " << error_message;
30}
31
32const base::ListValue* GetListValue(const std::string& key,
33                                    const base::Value& value) {
34  const base::ListValue* vlist = NULL;
35  if (!value.GetAsList(&vlist)) {
36    LOG(ERROR) << "Error parsing key as list: " << key;
37    return NULL;
38  }
39  return vlist;
40}
41
42}  // namespace
43
44namespace chromeos {
45namespace internal {
46
47ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
48    : listener_(listener),
49      shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()),
50      weak_ptr_factory_(ALLOW_THIS_IN_INITIALIZER_LIST(this)) {
51}
52
53ShillPropertyHandler::~ShillPropertyHandler() {
54  // Delete network service observers.
55  STLDeleteContainerPairSecondPointers(
56      observed_networks_.begin(), observed_networks_.end());
57  CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
58  shill_manager_->RemovePropertyChangedObserver(this);
59}
60
61void ShillPropertyHandler::Init() {
62  shill_manager_->GetProperties(
63      base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback,
64                 weak_ptr_factory_.GetWeakPtr()));
65  shill_manager_->AddPropertyChangedObserver(this);
66}
67
68void ShillPropertyHandler::SetTechnologyEnabled(
69    const std::string& technology,
70    bool enabled) {
71  if (enabled) {
72    shill_manager_->EnableTechnology(technology,
73                                     base::Bind(&base::DoNothing),
74                                     base::Bind(&ErrorCallbackFunction));
75  } else {
76    shill_manager_->DisableTechnology(technology,
77                                      base::Bind(&base::DoNothing),
78                                      base::Bind(&ErrorCallbackFunction));
79  }
80}
81
82void ShillPropertyHandler::RequestScan() const {
83  shill_manager_->RequestScan("",
84                              base::Bind(&base::DoNothing),
85                              base::Bind(&ErrorCallbackFunction));
86}
87
88void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
89                                             const std::string& path) {
90  ++pending_updates_[type];
91  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
92    DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
93        dbus::ObjectPath(path),
94        base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
95                   weak_ptr_factory_.GetWeakPtr(), type, path));
96  } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
97    DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
98        dbus::ObjectPath(path),
99        base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
100                   weak_ptr_factory_.GetWeakPtr(), type, path));
101  } else {
102    NOTREACHED();
103  }
104}
105
106void ShillPropertyHandler::RequestIPConfig(
107    const std::string& service_path,
108    const std::string& ip_config_path) {
109  DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
110      dbus::ObjectPath(ip_config_path),
111      base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
112                 weak_ptr_factory_.GetWeakPtr(),
113                 service_path));
114}
115
116void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
117                                             const base::Value& value) {
118  if (ManagerPropertyChanged(key, value))
119    listener_->ManagerPropertyChanged();
120}
121
122//------------------------------------------------------------------------------
123// Private methods
124
125void ShillPropertyHandler::ManagerPropertiesCallback(
126    DBusMethodCallStatus call_status,
127    const base::DictionaryValue& properties) {
128  if (call_status != DBUS_METHOD_CALL_SUCCESS) {
129    LOG(ERROR) << "Failed to get Manager properties:" << call_status;
130    return;
131  }
132  bool notify = false;
133  bool update_service_list = false;
134  for (base::DictionaryValue::Iterator iter(properties);
135       iter.HasNext(); iter.Advance()) {
136    // Defer updating Services until all other properties have been updated.
137    if (iter.key() == flimflam::kServicesProperty)
138      update_service_list = true;
139    else
140      notify |= ManagerPropertyChanged(iter.key(), iter.value());
141  }
142  // Now update the service list which can safely assume other properties have
143  // been initially set.
144  if (update_service_list) {
145    const base::Value* value = NULL;
146    if (properties.GetWithoutPathExpansion(flimflam::kServicesProperty, &value))
147      notify |= ManagerPropertyChanged(flimflam::kServicesProperty, *value);
148  }
149  if (notify)
150    listener_->ManagerPropertyChanged();
151}
152
153bool ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
154                                                  const base::Value& value) {
155  bool notify_manager_changed = false;
156  if (key == flimflam::kServicesProperty) {
157    const base::ListValue* vlist = GetListValue(key, value);
158    if (vlist)
159      UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
160  } else if (key == flimflam::kServiceWatchListProperty) {
161    const base::ListValue* vlist = GetListValue(key, value);
162    if (vlist) {
163      UpdateObservedNetworkServices(*vlist);
164    }
165  } else if (key == flimflam::kDevicesProperty) {
166    const ListValue* vlist = GetListValue(key, value);
167    if (vlist)
168      UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
169  } else if (key == flimflam::kAvailableTechnologiesProperty) {
170    const base::ListValue* vlist = GetListValue(key, value);
171    if (vlist ) {
172      listener_->UpdateAvailableTechnologies(*vlist);
173      notify_manager_changed = true;
174    }
175  } else if (key == flimflam::kEnabledTechnologiesProperty) {
176    const base::ListValue* vlist = GetListValue(key, value);
177    if (vlist) {
178      listener_->UpdateEnabledTechnologies(*vlist);
179      notify_manager_changed = true;
180    }
181  }
182  return notify_manager_changed;
183}
184
185void ShillPropertyHandler::UpdateManagedList(ManagedState::ManagedType type,
186                                             const base::ListValue& entries) {
187  listener_->UpdateManagedList(type, entries);
188  // Do not send a ManagerPropertyChanged notification to the Listener if
189  // RequestProperties has been called (ManagedStateListChanged will be
190  // called when the update requests have completed). If no requests
191  // have been made, call ManagedStateListChanged to indicate that the
192  // order of the list has changed.
193  if (pending_updates_[type] == 0)
194    listener_->ManagedStateListChanged(type);
195}
196
197void ShillPropertyHandler::UpdateObservedNetworkServices(
198    const base::ListValue& entries) {
199  // Watch all networks in the watch list.
200  ShillServiceObserverMap new_observed;
201  for (base::ListValue::const_iterator iter1 = entries.begin();
202       iter1 != entries.end(); ++iter1) {
203    std::string path;
204    (*iter1)->GetAsString(&path);
205    if (path.empty())
206      continue;
207    ShillServiceObserverMap::iterator iter2 = observed_networks_.find(path);
208    if (iter2 != observed_networks_.end()) {
209      new_observed[path] = observed_networks_[path];
210    } else {
211      new_observed[path] = new ShillServiceObserver(
212          path, base::Bind(
213              &ShillPropertyHandler::NetworkServicePropertyChangedCallback,
214              weak_ptr_factory_.GetWeakPtr()));
215    }
216    observed_networks_.erase(path);
217    // Limit the number of observed services.
218    if (new_observed.size() >= kMaxObservedServices)
219      break;
220  }
221  VLOG(2) << "UpdateObservedNetworkServices, new observed: "
222          << new_observed.size();
223  // Delete network service observers still in observed_networks_.
224  STLDeleteContainerPairSecondPointers(
225      observed_networks_.begin(), observed_networks_.end());
226  observed_networks_.swap(new_observed);
227}
228
229void ShillPropertyHandler::GetPropertiesCallback(
230    ManagedState::ManagedType type,
231    const std::string& path,
232    DBusMethodCallStatus call_status,
233    const base::DictionaryValue& properties) {
234  VLOG(2) << "GetPropertiesCallback: " << type << " : " << path;
235  --pending_updates_[type];
236  if (call_status != DBUS_METHOD_CALL_SUCCESS) {
237    LOG(ERROR) << "Failed to get properties for: " << path
238               << ": " << call_status;
239    return;
240  }
241  listener_->UpdateManagedStateProperties(type, path, properties);
242  // Notify the listener only when all updates for that type have completed.
243  if (pending_updates_[type] == 0)
244    listener_->ManagedStateListChanged(type);
245}
246
247void ShillPropertyHandler::NetworkServicePropertyChangedCallback(
248    const std::string& path,
249    const std::string& key,
250    const base::Value& value) {
251  listener_->UpdateNetworkServiceProperty(path, key, value);
252}
253
254void ShillPropertyHandler::GetIPConfigCallback(
255    const std::string& service_path,
256    DBusMethodCallStatus call_status,
257    const base::DictionaryValue& properties)  {
258  if (call_status != DBUS_METHOD_CALL_SUCCESS) {
259    LOG(ERROR) << "Failed to get IP properties for: " << service_path;
260    return;
261  }
262  std::string ip_address;
263  if (!properties.GetStringWithoutPathExpansion(flimflam::kAddressProperty,
264                                                &ip_address)) {
265    LOG(ERROR) << "Failed to get IP Address property for: " << service_path;
266    return;
267  }
268  listener_->UpdateNetworkServiceIPAddress(service_path, ip_address);
269}
270
271}  // namespace internal
272}  // namespace chromeos
273