shill_property_handler.cc revision effb81e5f8246d0db0270817048dc992db66e9fb
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/network/shill_property_handler.h"
6a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/format_macros.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/stl_util.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/string_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/strings/stringprintf.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/dbus_thread_manager.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/shill_device_client.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/shill_ipconfig_client.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/shill_manager_client.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/shill_profile_client.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/dbus/shill_service_client.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/network/network_event_log.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chromeos/network/network_state.h"
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "dbus/object_path.h"
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "third_party/cros_system_api/dbus/service_constants.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Limit the number of services or devices we observe. Since they are listed in
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// priority order, it should be reasonable to ignore services past this.
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const size_t kMaxObserved = 100;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const base::ListValue* GetListValue(const std::string& key,
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                    const base::Value& value) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const base::ListValue* vlist = NULL;
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!value.GetAsList(&vlist)) {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    LOG(ERROR) << "Error parsing key as list: " << key;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return NULL;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return vlist;
38a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}
39a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
40a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch}  // namespace
41a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace chromeos {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace internal {
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Class to manage Shill service property changed observers. Observers are
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// added on construction and removed on destruction. Runs the handler when
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OnPropertyChanged is called.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ShillPropertyObserver : public ShillPropertyChangedObserver {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  typedef base::Callback<void(ManagedState::ManagedType type,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const std::string& service,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const std::string& name,
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                              const base::Value& value)> Handler;
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShillPropertyObserver(ManagedState::ManagedType type,
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const std::string& path,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        const Handler& handler)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      : type_(type),
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        path_(path),
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        handler_(handler) {
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DBusThreadManager::Get()->GetShillServiceClient()->
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DBusThreadManager::Get()->GetShillDeviceClient()->
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~ShillPropertyObserver() {
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DBusThreadManager::Get()->GetShillServiceClient()->
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      DBusThreadManager::Get()->GetShillDeviceClient()->
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // ShillPropertyChangedObserver overrides.
85  virtual void OnPropertyChanged(const std::string& key,
86                                 const base::Value& value) OVERRIDE {
87    handler_.Run(type_, path_, key, value);
88  }
89
90 private:
91  ManagedState::ManagedType type_;
92  std::string path_;
93  Handler handler_;
94
95  DISALLOW_COPY_AND_ASSIGN(ShillPropertyObserver);
96};
97
98//------------------------------------------------------------------------------
99// ShillPropertyHandler
100
101ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
102    : listener_(listener),
103      shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()) {
104}
105
106ShillPropertyHandler::~ShillPropertyHandler() {
107  // Delete network service observers.
108  STLDeleteContainerPairSecondPointers(
109      observed_networks_.begin(), observed_networks_.end());
110  STLDeleteContainerPairSecondPointers(
111      observed_devices_.begin(), observed_devices_.end());
112  CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
113  shill_manager_->RemovePropertyChangedObserver(this);
114}
115
116void ShillPropertyHandler::Init() {
117  UpdateManagerProperties();
118  shill_manager_->AddPropertyChangedObserver(this);
119}
120
121void ShillPropertyHandler::UpdateManagerProperties() {
122  NET_LOG_EVENT("UpdateManagerProperties", "");
123  shill_manager_->GetProperties(
124      base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback,
125                 AsWeakPtr()));
126}
127
128bool ShillPropertyHandler::IsTechnologyAvailable(
129    const std::string& technology) const {
130  return available_technologies_.count(technology) != 0;
131}
132
133bool ShillPropertyHandler::IsTechnologyEnabled(
134    const std::string& technology) const {
135  return enabled_technologies_.count(technology) != 0;
136}
137
138bool ShillPropertyHandler::IsTechnologyEnabling(
139    const std::string& technology) const {
140  return enabling_technologies_.count(technology) != 0;
141}
142
143bool ShillPropertyHandler::IsTechnologyUninitialized(
144    const std::string& technology) const {
145  return uninitialized_technologies_.count(technology) != 0;
146}
147
148void ShillPropertyHandler::SetTechnologyEnabled(
149    const std::string& technology,
150    bool enabled,
151    const network_handler::ErrorCallback& error_callback) {
152  if (enabled) {
153    enabling_technologies_.insert(technology);
154    shill_manager_->EnableTechnology(
155        technology,
156        base::Bind(&base::DoNothing),
157        base::Bind(&ShillPropertyHandler::EnableTechnologyFailed,
158                   AsWeakPtr(), technology, error_callback));
159  } else {
160    // Immediately clear locally from enabled and enabling lists.
161    enabled_technologies_.erase(technology);
162    enabling_technologies_.erase(technology);
163    shill_manager_->DisableTechnology(
164        technology,
165        base::Bind(&base::DoNothing),
166        base::Bind(&network_handler::ShillErrorCallbackFunction,
167                   "SetTechnologyEnabled Failed",
168                   technology, error_callback));
169  }
170}
171
172void ShillPropertyHandler::SetCheckPortalList(
173    const std::string& check_portal_list) {
174  base::StringValue value(check_portal_list);
175  shill_manager_->SetProperty(
176      shill::kCheckPortalListProperty,
177      value,
178      base::Bind(&base::DoNothing),
179      base::Bind(&network_handler::ShillErrorCallbackFunction,
180                 "SetCheckPortalList Failed",
181                 "", network_handler::ErrorCallback()));
182}
183
184void ShillPropertyHandler::RequestScan() const {
185  shill_manager_->RequestScan(
186      "",
187      base::Bind(&base::DoNothing),
188      base::Bind(&network_handler::ShillErrorCallbackFunction,
189                 "RequestScan Failed",
190                 "", network_handler::ErrorCallback()));
191}
192
193void ShillPropertyHandler::ConnectToBestServices() const {
194  NET_LOG_EVENT("ConnectToBestServices", "");
195  shill_manager_->ConnectToBestServices(
196      base::Bind(&base::DoNothing),
197      base::Bind(&network_handler::ShillErrorCallbackFunction,
198                 "ConnectToBestServices Failed",
199                 "", network_handler::ErrorCallback()));
200}
201
202void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
203                                             const std::string& path) {
204  if (pending_updates_[type].find(path) != pending_updates_[type].end())
205    return;  // Update already requested.
206
207  NET_LOG_DEBUG("Request Properties", path);
208  pending_updates_[type].insert(path);
209  if (type == ManagedState::MANAGED_TYPE_NETWORK ||
210      type == ManagedState::MANAGED_TYPE_FAVORITE) {
211    DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
212        dbus::ObjectPath(path),
213        base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
214                   AsWeakPtr(), type, path));
215  } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
216    DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
217        dbus::ObjectPath(path),
218        base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
219                   AsWeakPtr(), type, path));
220  } else {
221    NOTREACHED();
222  }
223}
224
225void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
226                                             const base::Value& value) {
227  ManagerPropertyChanged(key, value);
228  CheckPendingStateListUpdates(key);
229}
230
231//------------------------------------------------------------------------------
232// Private methods
233
234void ShillPropertyHandler::ManagerPropertiesCallback(
235    DBusMethodCallStatus call_status,
236    const base::DictionaryValue& properties) {
237  if (call_status != DBUS_METHOD_CALL_SUCCESS) {
238    NET_LOG_ERROR("ManagerPropertiesCallback",
239                  base::StringPrintf("Failed: %d", call_status));
240    return;
241  }
242  NET_LOG_EVENT("ManagerPropertiesCallback", "Success");
243  const base::Value* update_service_value = NULL;
244  const base::Value* update_service_complete_value = NULL;
245  for (base::DictionaryValue::Iterator iter(properties);
246       !iter.IsAtEnd(); iter.Advance()) {
247    // Defer updating Services until all other properties have been updated.
248    if (iter.key() == shill::kServicesProperty)
249      update_service_value = &iter.value();
250    else if (iter.key() == shill::kServiceCompleteListProperty)
251      update_service_complete_value = &iter.value();
252    else
253      ManagerPropertyChanged(iter.key(), iter.value());
254  }
255  // Update Services which can safely assume other properties have been set.
256  if (update_service_value)
257    ManagerPropertyChanged(shill::kServicesProperty, *update_service_value);
258  // Update ServiceCompleteList which skips entries that have already been
259  // requested for Services.
260  if (update_service_complete_value) {
261    ManagerPropertyChanged(shill::kServiceCompleteListProperty,
262                           *update_service_complete_value);
263  }
264
265  CheckPendingStateListUpdates("");
266}
267
268void ShillPropertyHandler::CheckPendingStateListUpdates(
269    const std::string& key) {
270  // Once there are no pending updates, signal the state list changed callbacks.
271  if ((key.empty() || key == shill::kServicesProperty) &&
272      pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
273    listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
274  }
275  // Both Network update requests and Favorite update requests will affect
276  // the list of favorites, so wait for both to complete.
277  if ((key.empty() || key == shill::kServiceCompleteListProperty) &&
278      pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0 &&
279      pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) {
280    listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE);
281  }
282  if ((key.empty() || key == shill::kDevicesProperty) &&
283      pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
284    listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
285  }
286}
287
288void ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
289                                                  const base::Value& value) {
290  if (key == shill::kDefaultServiceProperty) {
291    std::string service_path;
292    value.GetAsString(&service_path);
293    listener_->DefaultNetworkServiceChanged(service_path);
294  } else if (key == shill::kServicesProperty) {
295    const base::ListValue* vlist = GetListValue(key, value);
296    if (vlist) {
297      listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
298      UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
299      // UpdateObserved used to use kServiceWatchListProperty for TYPE_NETWORK,
300      // however that prevents us from receiving Strength updates from inactive
301      // networks. The overhead for observing all services is not unreasonable
302      // (and we limit the max number of observed services to kMaxObserved).
303      UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
304    }
305  } else if (key == shill::kServiceCompleteListProperty) {
306    const base::ListValue* vlist = GetListValue(key, value);
307    if (vlist) {
308      listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_FAVORITE, *vlist);
309      UpdateProperties(ManagedState::MANAGED_TYPE_FAVORITE, *vlist);
310    }
311  } else if (key == shill::kDevicesProperty) {
312    const base::ListValue* vlist = GetListValue(key, value);
313    if (vlist) {
314      listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
315      UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
316      UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
317    }
318  } else if (key == shill::kAvailableTechnologiesProperty) {
319    const base::ListValue* vlist = GetListValue(key, value);
320    if (vlist)
321      UpdateAvailableTechnologies(*vlist);
322  } else if (key == shill::kEnabledTechnologiesProperty) {
323    const base::ListValue* vlist = GetListValue(key, value);
324    if (vlist)
325      UpdateEnabledTechnologies(*vlist);
326  } else if (key == shill::kUninitializedTechnologiesProperty) {
327    const base::ListValue* vlist = GetListValue(key, value);
328    if (vlist)
329      UpdateUninitializedTechnologies(*vlist);
330  } else if (key == shill::kProfilesProperty) {
331    listener_->ProfileListChanged();
332  } else if (key == shill::kCheckPortalListProperty) {
333    std::string check_portal_list;
334    if (value.GetAsString(&check_portal_list))
335      listener_->CheckPortalListChanged(check_portal_list);
336  } else {
337    VLOG(2) << "Ignored Manager Property: " << key;
338  }
339}
340
341void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type,
342                                            const base::ListValue& entries) {
343  std::set<std::string>& requested_updates = requested_updates_[type];
344  std::set<std::string>& requested_service_updates =
345      requested_updates_[ManagedState::MANAGED_TYPE_NETWORK];  // For favorites
346  std::set<std::string> new_requested_updates;
347  NET_LOG_DEBUG(
348      base::StringPrintf("UpdateProperties: %" PRIuS, entries.GetSize()),
349      ManagedState::TypeToString(type));
350  for (base::ListValue::const_iterator iter = entries.begin();
351       iter != entries.end(); ++iter) {
352    std::string path;
353    (*iter)->GetAsString(&path);
354    if (path.empty())
355      continue;
356    if (type == ManagedState::MANAGED_TYPE_FAVORITE &&
357        requested_service_updates.count(path) > 0)
358      continue;  // Update already requested
359
360    // We add a special case for devices here to work around an issue in shill
361    // that prevents it from sending property changed signals for cellular
362    // devices (see crbug.com/321854).
363    if (type == ManagedState::MANAGED_TYPE_DEVICE ||
364        requested_updates.find(path) == requested_updates.end())
365      RequestProperties(type, path);
366    new_requested_updates.insert(path);
367  }
368  requested_updates.swap(new_requested_updates);
369}
370
371void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
372                                          const base::ListValue& entries) {
373  DCHECK(type == ManagedState::MANAGED_TYPE_NETWORK ||
374         type == ManagedState::MANAGED_TYPE_DEVICE);
375  ShillPropertyObserverMap& observer_map =
376      (type == ManagedState::MANAGED_TYPE_NETWORK)
377      ? observed_networks_ : observed_devices_;
378  ShillPropertyObserverMap new_observed;
379  for (base::ListValue::const_iterator iter1 = entries.begin();
380       iter1 != entries.end(); ++iter1) {
381    std::string path;
382    (*iter1)->GetAsString(&path);
383    if (path.empty())
384      continue;
385    ShillPropertyObserverMap::iterator iter2 = observer_map.find(path);
386    if (iter2 != observer_map.end()) {
387      new_observed[path] = iter2->second;
388    } else {
389      // Create an observer for future updates.
390      new_observed[path] = new ShillPropertyObserver(
391          type, path, base::Bind(
392              &ShillPropertyHandler::PropertyChangedCallback, AsWeakPtr()));
393    }
394    observer_map.erase(path);
395    // Limit the number of observed services.
396    if (new_observed.size() >= kMaxObserved)
397      break;
398  }
399  // Delete network service observers still in observer_map.
400  for (ShillPropertyObserverMap::iterator iter =  observer_map.begin();
401       iter != observer_map.end(); ++iter) {
402    delete iter->second;
403  }
404  observer_map.swap(new_observed);
405}
406
407void ShillPropertyHandler::UpdateAvailableTechnologies(
408    const base::ListValue& technologies) {
409  available_technologies_.clear();
410  NET_LOG_EVENT("AvailableTechnologiesChanged",
411                base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
412  for (base::ListValue::const_iterator iter = technologies.begin();
413       iter != technologies.end(); ++iter) {
414    std::string technology;
415    (*iter)->GetAsString(&technology);
416    DCHECK(!technology.empty());
417    available_technologies_.insert(technology);
418  }
419  listener_->TechnologyListChanged();
420}
421
422void ShillPropertyHandler::UpdateEnabledTechnologies(
423    const base::ListValue& technologies) {
424  enabled_technologies_.clear();
425  NET_LOG_EVENT("EnabledTechnologiesChanged",
426                base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
427  for (base::ListValue::const_iterator iter = technologies.begin();
428       iter != technologies.end(); ++iter) {
429    std::string technology;
430    (*iter)->GetAsString(&technology);
431    DCHECK(!technology.empty());
432    enabled_technologies_.insert(technology);
433    enabling_technologies_.erase(technology);
434  }
435  listener_->TechnologyListChanged();
436}
437
438void ShillPropertyHandler::UpdateUninitializedTechnologies(
439    const base::ListValue& technologies) {
440  uninitialized_technologies_.clear();
441  NET_LOG_EVENT("UninitializedTechnologiesChanged",
442                base::StringPrintf("Size: %" PRIuS, technologies.GetSize()));
443  for (base::ListValue::const_iterator iter = technologies.begin();
444       iter != technologies.end(); ++iter) {
445    std::string technology;
446    (*iter)->GetAsString(&technology);
447    DCHECK(!technology.empty());
448    uninitialized_technologies_.insert(technology);
449  }
450  listener_->TechnologyListChanged();
451}
452
453void ShillPropertyHandler::EnableTechnologyFailed(
454    const std::string& technology,
455    const network_handler::ErrorCallback& error_callback,
456    const std::string& dbus_error_name,
457    const std::string& dbus_error_message) {
458  enabling_technologies_.erase(technology);
459  network_handler::ShillErrorCallbackFunction(
460      "EnableTechnology Failed",
461      technology, error_callback,
462      dbus_error_name, dbus_error_message);
463}
464
465void ShillPropertyHandler::GetPropertiesCallback(
466    ManagedState::ManagedType type,
467    const std::string& path,
468    DBusMethodCallStatus call_status,
469    const base::DictionaryValue& properties) {
470  NET_LOG_DEBUG("GetPropertiesCallback: " + ManagedState::TypeToString(type),
471                path);
472  pending_updates_[type].erase(path);
473  if (call_status != DBUS_METHOD_CALL_SUCCESS) {
474    // The shill service no longer exists.  This can happen when a network
475    // has been removed.
476    NET_LOG_DEBUG("Failed to get properties",
477                  base::StringPrintf("%s: %d", path.c_str(), call_status));
478    return;
479  }
480  // Update Favorite properties for networks in the Services list.
481  if (type == ManagedState::MANAGED_TYPE_NETWORK) {
482    // Only networks with a ProfilePath set are Favorites.
483    std::string profile_path;
484    properties.GetStringWithoutPathExpansion(
485        shill::kProfileProperty, &profile_path);
486    if (!profile_path.empty()) {
487      listener_->UpdateManagedStateProperties(
488          ManagedState::MANAGED_TYPE_FAVORITE, path, properties);
489    }
490  }
491  listener_->UpdateManagedStateProperties(type, path, properties);
492  // Request IPConfig parameters for networks.
493  if (type == ManagedState::MANAGED_TYPE_NETWORK &&
494      properties.HasKey(shill::kIPConfigProperty)) {
495    std::string ip_config_path;
496    if (properties.GetString(shill::kIPConfigProperty, &ip_config_path)) {
497      DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
498          dbus::ObjectPath(ip_config_path),
499          base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
500                     AsWeakPtr(), path));
501    }
502  }
503
504  // Notify the listener only when all updates for that type have completed.
505  if (pending_updates_[type].size() == 0) {
506    listener_->ManagedStateListChanged(type);
507    // Notify that Favorites have changed when notifying for Networks if there
508    // are no additional Favorite updates pending.
509    if (type == ManagedState::MANAGED_TYPE_NETWORK &&
510        pending_updates_[ManagedState::MANAGED_TYPE_FAVORITE].size() == 0) {
511      listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_FAVORITE);
512    }
513  }
514}
515
516void ShillPropertyHandler::PropertyChangedCallback(
517    ManagedState::ManagedType type,
518    const std::string& path,
519    const std::string& key,
520    const base::Value& value) {
521  if (type == ManagedState::MANAGED_TYPE_NETWORK)
522    NetworkServicePropertyChangedCallback(path, key, value);
523  else if (type == ManagedState::MANAGED_TYPE_DEVICE)
524    NetworkDevicePropertyChangedCallback(path, key, value);
525  else
526    NOTREACHED();
527}
528
529void ShillPropertyHandler::NetworkServicePropertyChangedCallback(
530    const std::string& path,
531    const std::string& key,
532    const base::Value& value) {
533  if (key == shill::kIPConfigProperty) {
534    // Request the IPConfig for the network and update network properties
535    // when the request completes.
536    std::string ip_config_path;
537    value.GetAsString(&ip_config_path);
538    DCHECK(!ip_config_path.empty());
539    DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
540        dbus::ObjectPath(ip_config_path),
541        base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
542                   AsWeakPtr(), path));
543  } else {
544    listener_->UpdateNetworkServiceProperty(path, key, value);
545  }
546}
547
548void ShillPropertyHandler::GetIPConfigCallback(
549    const std::string& service_path,
550    DBusMethodCallStatus call_status,
551    const base::DictionaryValue& properties)  {
552  if (call_status != DBUS_METHOD_CALL_SUCCESS) {
553    NET_LOG_ERROR("Failed to get IP Config properties",
554                  base::StringPrintf("%s: %d",
555                                     service_path.c_str(), call_status));
556    return;
557  }
558  UpdateIPConfigProperty(service_path, properties, shill::kAddressProperty);
559  UpdateIPConfigProperty(service_path, properties, shill::kNameServersProperty);
560  UpdateIPConfigProperty(service_path, properties, shill::kPrefixlenProperty);
561  UpdateIPConfigProperty(service_path, properties, shill::kGatewayProperty);
562  UpdateIPConfigProperty(service_path, properties,
563                         shill::kWebProxyAutoDiscoveryUrlProperty);
564}
565
566void ShillPropertyHandler::UpdateIPConfigProperty(
567    const std::string& service_path,
568    const base::DictionaryValue& properties,
569    const char* property) {
570  const base::Value* value;
571  if (!properties.GetWithoutPathExpansion(property, &value)) {
572    LOG(ERROR) << "Failed to get IPConfig property: " << property
573               << ", for: " << service_path;
574    return;
575  }
576  listener_->UpdateNetworkServiceProperty(
577      service_path, NetworkState::IPConfigProperty(property), *value);
578}
579
580void ShillPropertyHandler::NetworkDevicePropertyChangedCallback(
581    const std::string& path,
582    const std::string& key,
583    const base::Value& value) {
584  listener_->UpdateDeviceProperty(path, key, value);
585}
586
587}  // namespace internal
588}  // namespace chromeos
589