Use Persistent::Reset.
[chromium-blink-merge.git] / chromeos / network / shill_property_handler.cc
blobe6efd65920689a105bf81ded15f88d5fcdd28491
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.
5 #include "chromeos/network/shill_property_handler.h"
7 #include "base/bind.h"
8 #include "base/format_macros.h"
9 #include "base/stl_util.h"
10 #include "base/string_util.h"
11 #include "base/stringprintf.h"
12 #include "base/values.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_device_client.h"
15 #include "chromeos/dbus/shill_ipconfig_client.h"
16 #include "chromeos/dbus/shill_manager_client.h"
17 #include "chromeos/dbus/shill_service_client.h"
18 #include "chromeos/network/network_event_log.h"
19 #include "chromeos/network/network_state.h"
20 #include "dbus/object_path.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
23 namespace {
25 const char kLogModule[] = "ShillPropertyHandler";
27 // Limit the number of services or devices we observe. Since they are listed in
28 // priority order, it should be reasonable to ignore services past this.
29 const size_t kMaxObserved = 100;
31 const base::ListValue* GetListValue(const std::string& key,
32 const base::Value& value) {
33 const base::ListValue* vlist = NULL;
34 if (!value.GetAsList(&vlist)) {
35 LOG(ERROR) << "Error parsing key as list: " << key;
36 return NULL;
38 return vlist;
41 } // namespace
43 namespace chromeos {
44 namespace internal {
46 // Class to manage Shill service property changed observers. Observers are
47 // added on construction and removed on destruction. Runs the handler when
48 // OnPropertyChanged is called.
49 class ShillPropertyObserver : public ShillPropertyChangedObserver {
50 public:
51 typedef base::Callback<void(ManagedState::ManagedType type,
52 const std::string& service,
53 const std::string& name,
54 const base::Value& value)> Handler;
56 ShillPropertyObserver(ManagedState::ManagedType type,
57 const std::string& path,
58 const Handler& handler)
59 : type_(type),
60 path_(path),
61 handler_(handler) {
62 if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
63 DBusThreadManager::Get()->GetShillServiceClient()->
64 AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
65 } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
66 DBusThreadManager::Get()->GetShillDeviceClient()->
67 AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
68 } else {
69 NOTREACHED();
73 virtual ~ShillPropertyObserver() {
74 if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
75 DBusThreadManager::Get()->GetShillServiceClient()->
76 RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
77 } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
78 DBusThreadManager::Get()->GetShillDeviceClient()->
79 RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
80 } else {
81 NOTREACHED();
85 // ShillPropertyChangedObserver overrides.
86 virtual void OnPropertyChanged(const std::string& key,
87 const base::Value& value) OVERRIDE {
88 handler_.Run(type_, path_, key, value);
91 private:
92 ManagedState::ManagedType type_;
93 std::string path_;
94 Handler handler_;
96 DISALLOW_COPY_AND_ASSIGN(ShillPropertyObserver);
99 //------------------------------------------------------------------------------
100 // ShillPropertyHandler
102 ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
103 : listener_(listener),
104 shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()) {
107 ShillPropertyHandler::~ShillPropertyHandler() {
108 // Delete network service observers.
109 STLDeleteContainerPairSecondPointers(
110 observed_networks_.begin(), observed_networks_.end());
111 STLDeleteContainerPairSecondPointers(
112 observed_devices_.begin(), observed_devices_.end());
113 CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
114 shill_manager_->RemovePropertyChangedObserver(this);
117 void ShillPropertyHandler::Init() {
118 shill_manager_->GetProperties(
119 base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback,
120 AsWeakPtr()));
121 shill_manager_->AddPropertyChangedObserver(this);
124 bool ShillPropertyHandler::IsTechnologyAvailable(
125 const std::string& technology) const {
126 return available_technologies_.count(technology) != 0;
129 bool ShillPropertyHandler::IsTechnologyEnabled(
130 const std::string& technology) const {
131 return enabled_technologies_.count(technology) != 0;
134 bool ShillPropertyHandler::IsTechnologyEnabling(
135 const std::string& technology) const {
136 return enabling_technologies_.count(technology) != 0;
139 bool ShillPropertyHandler::IsTechnologyUninitialized(
140 const std::string& technology) const {
141 return uninitialized_technologies_.count(technology) != 0;
144 void ShillPropertyHandler::SetTechnologyEnabled(
145 const std::string& technology,
146 bool enabled,
147 const network_handler::ErrorCallback& error_callback) {
148 if (enabled) {
149 enabling_technologies_.insert(technology);
150 shill_manager_->EnableTechnology(
151 technology,
152 base::Bind(&base::DoNothing),
153 base::Bind(&ShillPropertyHandler::EnableTechnologyFailed,
154 AsWeakPtr(), technology, error_callback));
155 } else {
156 // Imediately clear locally from enabled and enabling lists.
157 enabled_technologies_.erase(technology);
158 enabling_technologies_.erase(technology);
159 shill_manager_->DisableTechnology(
160 technology,
161 base::Bind(&base::DoNothing),
162 base::Bind(&network_handler::ShillErrorCallbackFunction,
163 kLogModule, technology, error_callback));
167 void ShillPropertyHandler::RequestScan() const {
168 shill_manager_->RequestScan(
170 base::Bind(&base::DoNothing),
171 base::Bind(&network_handler::ShillErrorCallbackFunction,
172 kLogModule, "", network_handler::ErrorCallback()));
175 void ShillPropertyHandler::ConnectToBestServices() const {
176 network_event_log::AddEntry(kLogModule, "ConnectToBestServices", "");
177 shill_manager_->ConnectToBestServices(
178 base::Bind(&base::DoNothing),
179 base::Bind(&network_handler::ShillErrorCallbackFunction,
180 kLogModule, "", network_handler::ErrorCallback()));
183 void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
184 const std::string& path) {
185 if (pending_updates_[type].find(path) != pending_updates_[type].end())
186 return; // Update already requested.
188 pending_updates_[type].insert(path);
189 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
190 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
191 dbus::ObjectPath(path),
192 base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
193 AsWeakPtr(), type, path));
194 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
195 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
196 dbus::ObjectPath(path),
197 base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
198 AsWeakPtr(), type, path));
199 } else {
200 NOTREACHED();
204 void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
205 const base::Value& value) {
206 if (ManagerPropertyChanged(key, value))
207 listener_->ManagerPropertyChanged();
208 // If the service watch or device list changed and there are no pending
209 // updates, signal the state list changed callback.
210 if ((key == flimflam::kServiceWatchListProperty) &&
211 pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
212 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
214 if (key == flimflam::kDevicesProperty &&
215 pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
216 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
220 //------------------------------------------------------------------------------
221 // Private methods
223 void ShillPropertyHandler::ManagerPropertiesCallback(
224 DBusMethodCallStatus call_status,
225 const base::DictionaryValue& properties) {
226 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
227 LOG(ERROR) << "Failed to get Manager properties:" << call_status;
228 return;
230 bool notify = false;
231 bool update_service_list = false;
232 for (base::DictionaryValue::Iterator iter(properties);
233 !iter.IsAtEnd(); iter.Advance()) {
234 // Defer updating Services until all other properties have been updated.
235 if (iter.key() == flimflam::kServicesProperty)
236 update_service_list = true;
237 else
238 notify |= ManagerPropertyChanged(iter.key(), iter.value());
240 // Now update the service list which can safely assume other properties have
241 // been initially set.
242 if (update_service_list) {
243 const base::Value* value = NULL;
244 if (properties.GetWithoutPathExpansion(flimflam::kServicesProperty, &value))
245 notify |= ManagerPropertyChanged(flimflam::kServicesProperty, *value);
247 if (notify)
248 listener_->ManagerPropertyChanged();
249 // If there are no pending updates, signal the state list changed callbacks.
250 if (pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0)
251 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
252 if (pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0)
253 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
256 bool ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
257 const base::Value& value) {
258 bool notify_manager_changed = false;
259 if (key == flimflam::kServicesProperty) {
260 const base::ListValue* vlist = GetListValue(key, value);
261 if (vlist)
262 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
263 } else if (key == flimflam::kServiceWatchListProperty) {
264 const base::ListValue* vlist = GetListValue(key, value);
265 if (vlist) {
266 UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
268 } else if (key == flimflam::kDevicesProperty) {
269 const ListValue* vlist = GetListValue(key, value);
270 if (vlist) {
271 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
272 UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
274 } else if (key == flimflam::kAvailableTechnologiesProperty) {
275 const base::ListValue* vlist = GetListValue(key, value);
276 if (vlist) {
277 UpdateAvailableTechnologies(*vlist);
278 notify_manager_changed = true;
280 } else if (key == flimflam::kEnabledTechnologiesProperty) {
281 const base::ListValue* vlist = GetListValue(key, value);
282 if (vlist) {
283 UpdateEnabledTechnologies(*vlist);
284 notify_manager_changed = true;
286 } else if (key == shill::kUninitializedTechnologiesProperty) {
287 const base::ListValue* vlist = GetListValue(key, value);
288 if (vlist) {
289 UpdateUninitializedTechnologies(*vlist);
290 notify_manager_changed = true;
292 } else if (key == flimflam::kProfilesProperty) {
293 listener_->ProfileListChanged();
295 return notify_manager_changed;
298 void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
299 const base::ListValue& entries) {
300 ShillPropertyObserverMap& observer_map =
301 (type == ManagedState::MANAGED_TYPE_NETWORK)
302 ? observed_networks_ : observed_devices_;
303 ShillPropertyObserverMap new_observed;
304 for (base::ListValue::const_iterator iter1 = entries.begin();
305 iter1 != entries.end(); ++iter1) {
306 std::string path;
307 (*iter1)->GetAsString(&path);
308 if (path.empty())
309 continue;
310 ShillPropertyObserverMap::iterator iter2 = observer_map.find(path);
311 if (iter2 != observer_map.end()) {
312 new_observed[path] = iter2->second;
313 } else {
314 // Request an update.
315 RequestProperties(type, path);
316 // Create an observer for future updates.
317 new_observed[path] = new ShillPropertyObserver(
318 type, path, base::Bind(
319 &ShillPropertyHandler::PropertyChangedCallback, AsWeakPtr()));
320 network_event_log::AddEntry(kLogModule, "StartObserving", path);
322 observer_map.erase(path);
323 // Limit the number of observed services.
324 if (new_observed.size() >= kMaxObserved)
325 break;
327 // Delete network service observers still in observer_map.
328 for (ShillPropertyObserverMap::iterator iter = observer_map.begin();
329 iter != observer_map.end(); ++iter) {
330 network_event_log::AddEntry(kLogModule, "StopObserving", iter->first);
331 delete iter->second;
333 observer_map.swap(new_observed);
336 void ShillPropertyHandler::UpdateAvailableTechnologies(
337 const base::ListValue& technologies) {
338 available_technologies_.clear();
339 network_event_log::AddEntry(
340 kLogModule, "AvailableTechnologiesChanged",
341 base::StringPrintf("Size: %"PRIuS, technologies.GetSize()));
342 for (base::ListValue::const_iterator iter = technologies.begin();
343 iter != technologies.end(); ++iter) {
344 std::string technology;
345 (*iter)->GetAsString(&technology);
346 DCHECK(!technology.empty());
347 available_technologies_.insert(technology);
351 void ShillPropertyHandler::UpdateEnabledTechnologies(
352 const base::ListValue& technologies) {
353 enabled_technologies_.clear();
354 network_event_log::AddEntry(
355 kLogModule, "EnabledTechnologiesChanged",
356 base::StringPrintf("Size: %"PRIuS, technologies.GetSize()));
357 for (base::ListValue::const_iterator iter = technologies.begin();
358 iter != technologies.end(); ++iter) {
359 std::string technology;
360 (*iter)->GetAsString(&technology);
361 DCHECK(!technology.empty());
362 enabled_technologies_.insert(technology);
363 enabling_technologies_.erase(technology);
367 void ShillPropertyHandler::UpdateUninitializedTechnologies(
368 const base::ListValue& technologies) {
369 uninitialized_technologies_.clear();
370 network_event_log::AddEntry(
371 kLogModule, "UninitializedTechnologiesChanged",
372 base::StringPrintf("Size: %"PRIuS, technologies.GetSize()));
373 for (base::ListValue::const_iterator iter = technologies.begin();
374 iter != technologies.end(); ++iter) {
375 std::string technology;
376 (*iter)->GetAsString(&technology);
377 DCHECK(!technology.empty());
378 uninitialized_technologies_.insert(technology);
382 void ShillPropertyHandler::EnableTechnologyFailed(
383 const std::string& technology,
384 const network_handler::ErrorCallback& error_callback,
385 const std::string& error_name,
386 const std::string& error_message) {
387 enabling_technologies_.erase(technology);
388 network_handler::ShillErrorCallbackFunction(
389 kLogModule, technology, error_callback, error_name, error_message);
392 void ShillPropertyHandler::GetPropertiesCallback(
393 ManagedState::ManagedType type,
394 const std::string& path,
395 DBusMethodCallStatus call_status,
396 const base::DictionaryValue& properties) {
397 VLOG(2) << "GetPropertiesCallback: " << type << " : " << path;
398 pending_updates_[type].erase(path);
399 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
400 LOG(ERROR) << "Failed to get properties for: " << path
401 << ": " << call_status;
402 return;
404 listener_->UpdateManagedStateProperties(type, path, properties);
406 if (properties.HasKey(shill::kIPConfigProperty)) {
407 // Since this is the first time we received properties for this network,
408 // also request its IPConfig parameters.
409 std::string ip_config_path;
410 if (properties.GetString(shill::kIPConfigProperty, &ip_config_path)) {
411 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
412 dbus::ObjectPath(ip_config_path),
413 base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
414 AsWeakPtr(), path));
418 // Notify the listener only when all updates for that type have completed.
419 if (pending_updates_[type].size() == 0)
420 listener_->ManagedStateListChanged(type);
423 void ShillPropertyHandler::PropertyChangedCallback(
424 ManagedState::ManagedType type,
425 const std::string& path,
426 const std::string& key,
427 const base::Value& value) {
428 if (type == ManagedState::MANAGED_TYPE_NETWORK)
429 NetworkServicePropertyChangedCallback(path, key, value);
430 else if (type == ManagedState::MANAGED_TYPE_DEVICE)
431 NetworkDevicePropertyChangedCallback(path, key, value);
432 else
433 NOTREACHED();
436 void ShillPropertyHandler::NetworkServicePropertyChangedCallback(
437 const std::string& path,
438 const std::string& key,
439 const base::Value& value) {
440 if (key == shill::kIPConfigProperty) {
441 // Request the IPConfig for the network and update network properties
442 // when the request completes.
443 std::string ip_config_path;
444 value.GetAsString(&ip_config_path);
445 DCHECK(!ip_config_path.empty());
446 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
447 dbus::ObjectPath(ip_config_path),
448 base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
449 AsWeakPtr(), path));
450 } else {
451 listener_->UpdateNetworkServiceProperty(path, key, value);
455 void ShillPropertyHandler::GetIPConfigCallback(
456 const std::string& service_path,
457 DBusMethodCallStatus call_status,
458 const base::DictionaryValue& properties) {
459 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
460 LOG(ERROR) << "Failed to get IP Config properties for: " << service_path;
461 return;
463 const base::Value* ip_address;
464 if (!properties.GetWithoutPathExpansion(flimflam::kAddressProperty,
465 &ip_address)) {
466 LOG(ERROR) << "Failed to get IP Address property for: " << service_path;
467 return;
469 listener_->UpdateNetworkServiceProperty(
470 service_path,
471 NetworkState::IPConfigProperty(flimflam::kAddressProperty),
472 *ip_address);
474 const base::Value* dns_servers = NULL;
475 if (!properties.GetWithoutPathExpansion(
476 flimflam::kNameServersProperty, &dns_servers)) {
477 LOG(ERROR) << "Failed to get Name servers property for: " << service_path;
478 return;
480 listener_->UpdateNetworkServiceProperty(
481 service_path,
482 NetworkState::IPConfigProperty(flimflam::kNameServersProperty),
483 *dns_servers);
486 void ShillPropertyHandler::NetworkDevicePropertyChangedCallback(
487 const std::string& path,
488 const std::string& key,
489 const base::Value& value) {
490 listener_->UpdateDeviceProperty(path, key, value);
493 } // namespace internal
494 } // namespace chromeos