ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chromeos / network / shill_property_handler.cc
blob39d161dde46d9a578017a93d5aa282338577b833
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 <sstream>
9 #include "base/bind.h"
10 #include "base/format_macros.h"
11 #include "base/stl_util.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/values.h"
15 #include "chromeos/dbus/dbus_thread_manager.h"
16 #include "chromeos/dbus/shill_device_client.h"
17 #include "chromeos/dbus/shill_ipconfig_client.h"
18 #include "chromeos/dbus/shill_manager_client.h"
19 #include "chromeos/dbus/shill_profile_client.h"
20 #include "chromeos/dbus/shill_service_client.h"
21 #include "chromeos/network/network_event_log.h"
22 #include "chromeos/network/network_state.h"
23 #include "dbus/object_path.h"
24 #include "third_party/cros_system_api/dbus/service_constants.h"
26 namespace {
28 // Limit the number of services or devices we observe. Since they are listed in
29 // priority order, it should be reasonable to ignore services past this.
30 const size_t kMaxObserved = 100;
32 const 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;
39 return vlist;
42 } // namespace
44 namespace chromeos {
45 namespace internal {
47 // Class to manage Shill service property changed observers. Observers are
48 // added on construction and removed on destruction. Runs the handler when
49 // OnPropertyChanged is called.
50 class ShillPropertyObserver : public ShillPropertyChangedObserver {
51 public:
52 typedef base::Callback<void(ManagedState::ManagedType type,
53 const std::string& service,
54 const std::string& name,
55 const base::Value& value)> Handler;
57 ShillPropertyObserver(ManagedState::ManagedType type,
58 const std::string& path,
59 const Handler& handler)
60 : type_(type),
61 path_(path),
62 handler_(handler) {
63 if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
64 DVLOG(2) << "ShillPropertyObserver: Network: " << path;
65 DBusThreadManager::Get()->GetShillServiceClient()->
66 AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
67 } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
68 DVLOG(2) << "ShillPropertyObserver: Device: " << path;
69 DBusThreadManager::Get()->GetShillDeviceClient()->
70 AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
71 } else {
72 NOTREACHED();
76 ~ShillPropertyObserver() override {
77 if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
78 DBusThreadManager::Get()->GetShillServiceClient()->
79 RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
80 } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
81 DBusThreadManager::Get()->GetShillDeviceClient()->
82 RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
83 } else {
84 NOTREACHED();
88 // ShillPropertyChangedObserver overrides.
89 void OnPropertyChanged(const std::string& key,
90 const base::Value& value) override {
91 handler_.Run(type_, path_, key, value);
94 private:
95 ManagedState::ManagedType type_;
96 std::string path_;
97 Handler handler_;
99 DISALLOW_COPY_AND_ASSIGN(ShillPropertyObserver);
102 //------------------------------------------------------------------------------
103 // ShillPropertyHandler
105 ShillPropertyHandler::ShillPropertyHandler(Listener* listener)
106 : listener_(listener),
107 shill_manager_(DBusThreadManager::Get()->GetShillManagerClient()) {
110 ShillPropertyHandler::~ShillPropertyHandler() {
111 // Delete network service observers.
112 STLDeleteContainerPairSecondPointers(
113 observed_networks_.begin(), observed_networks_.end());
114 STLDeleteContainerPairSecondPointers(
115 observed_devices_.begin(), observed_devices_.end());
116 CHECK(shill_manager_ == DBusThreadManager::Get()->GetShillManagerClient());
117 shill_manager_->RemovePropertyChangedObserver(this);
120 void ShillPropertyHandler::Init() {
121 UpdateManagerProperties();
122 shill_manager_->AddPropertyChangedObserver(this);
125 void ShillPropertyHandler::UpdateManagerProperties() {
126 NET_LOG_EVENT("UpdateManagerProperties", "");
127 shill_manager_->GetProperties(
128 base::Bind(&ShillPropertyHandler::ManagerPropertiesCallback,
129 AsWeakPtr()));
132 bool ShillPropertyHandler::IsTechnologyAvailable(
133 const std::string& technology) const {
134 return available_technologies_.count(technology) != 0;
137 bool ShillPropertyHandler::IsTechnologyEnabled(
138 const std::string& technology) const {
139 return enabled_technologies_.count(technology) != 0;
142 bool ShillPropertyHandler::IsTechnologyEnabling(
143 const std::string& technology) const {
144 return enabling_technologies_.count(technology) != 0;
147 bool ShillPropertyHandler::IsTechnologyUninitialized(
148 const std::string& technology) const {
149 return uninitialized_technologies_.count(technology) != 0;
152 void ShillPropertyHandler::SetTechnologyEnabled(
153 const std::string& technology,
154 bool enabled,
155 const network_handler::ErrorCallback& error_callback) {
156 if (enabled) {
157 enabling_technologies_.insert(technology);
158 shill_manager_->EnableTechnology(
159 technology,
160 base::Bind(&base::DoNothing),
161 base::Bind(&ShillPropertyHandler::EnableTechnologyFailed,
162 AsWeakPtr(), technology, error_callback));
163 } else {
164 // Immediately clear locally from enabled and enabling lists.
165 enabled_technologies_.erase(technology);
166 enabling_technologies_.erase(technology);
167 shill_manager_->DisableTechnology(
168 technology,
169 base::Bind(&base::DoNothing),
170 base::Bind(&network_handler::ShillErrorCallbackFunction,
171 "SetTechnologyEnabled Failed",
172 technology, error_callback));
176 void ShillPropertyHandler::SetCheckPortalList(
177 const std::string& check_portal_list) {
178 base::StringValue value(check_portal_list);
179 shill_manager_->SetProperty(
180 shill::kCheckPortalListProperty,
181 value,
182 base::Bind(&base::DoNothing),
183 base::Bind(&network_handler::ShillErrorCallbackFunction,
184 "SetCheckPortalList Failed",
185 "Manager",
186 network_handler::ErrorCallback()));
189 void ShillPropertyHandler::SetWakeOnLanEnabled(bool enabled) {
190 base::FundamentalValue value(enabled);
191 shill_manager_->SetProperty(
192 shill::kWakeOnLanEnabledProperty,
193 value,
194 base::Bind(&base::DoNothing),
195 base::Bind(&network_handler::ShillErrorCallbackFunction,
196 "SetWakeOnLanEnabled Failed",
197 "Manager",
198 network_handler::ErrorCallback()));
201 void ShillPropertyHandler::RequestScan() const {
202 shill_manager_->RequestScan(
204 base::Bind(&base::DoNothing),
205 base::Bind(&network_handler::ShillErrorCallbackFunction,
206 "RequestScan Failed",
207 "", network_handler::ErrorCallback()));
210 void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
211 const std::string& path) {
212 if (pending_updates_[type].find(path) != pending_updates_[type].end())
213 return; // Update already requested.
215 NET_LOG_DEBUG("Request Properties: " + ManagedState::TypeToString(type),
216 path);
217 pending_updates_[type].insert(path);
218 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
219 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
220 dbus::ObjectPath(path),
221 base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
222 AsWeakPtr(), type, path));
223 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
224 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
225 dbus::ObjectPath(path),
226 base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
227 AsWeakPtr(), type, path));
228 } else {
229 NOTREACHED();
233 void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
234 const base::Value& value) {
235 ManagerPropertyChanged(key, value);
236 CheckPendingStateListUpdates(key);
239 //------------------------------------------------------------------------------
240 // Private methods
242 void ShillPropertyHandler::ManagerPropertiesCallback(
243 DBusMethodCallStatus call_status,
244 const base::DictionaryValue& properties) {
245 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
246 NET_LOG_ERROR("ManagerPropertiesCallback",
247 base::StringPrintf("Failed: %d", call_status));
248 return;
250 NET_LOG_EVENT("ManagerPropertiesCallback", "Success");
251 for (base::DictionaryValue::Iterator iter(properties);
252 !iter.IsAtEnd(); iter.Advance()) {
253 ManagerPropertyChanged(iter.key(), iter.value());
256 CheckPendingStateListUpdates("");
259 void ShillPropertyHandler::CheckPendingStateListUpdates(
260 const std::string& key) {
261 // Once there are no pending updates, signal the state list changed callbacks.
262 if ((key.empty() || key == shill::kServiceCompleteListProperty) &&
263 pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
264 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
266 if ((key.empty() || key == shill::kDevicesProperty) &&
267 pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
268 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
272 void ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
273 const base::Value& value) {
274 NET_LOG_DEBUG("ManagerPropertyChanged", key);
275 if (key == shill::kDefaultServiceProperty) {
276 std::string service_path;
277 value.GetAsString(&service_path);
278 listener_->DefaultNetworkServiceChanged(service_path);
279 } else if (key == shill::kServiceCompleteListProperty) {
280 const base::ListValue* vlist = GetListValue(key, value);
281 if (vlist) {
282 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
283 UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
284 UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
286 } else if (key == shill::kDevicesProperty) {
287 const base::ListValue* vlist = GetListValue(key, value);
288 if (vlist) {
289 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
290 UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
291 UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
293 } else if (key == shill::kAvailableTechnologiesProperty) {
294 const base::ListValue* vlist = GetListValue(key, value);
295 if (vlist)
296 UpdateAvailableTechnologies(*vlist);
297 } else if (key == shill::kEnabledTechnologiesProperty) {
298 const base::ListValue* vlist = GetListValue(key, value);
299 if (vlist)
300 UpdateEnabledTechnologies(*vlist);
301 } else if (key == shill::kUninitializedTechnologiesProperty) {
302 const base::ListValue* vlist = GetListValue(key, value);
303 if (vlist)
304 UpdateUninitializedTechnologies(*vlist);
305 } else if (key == shill::kProfilesProperty) {
306 listener_->ProfileListChanged();
307 } else if (key == shill::kCheckPortalListProperty) {
308 std::string check_portal_list;
309 if (value.GetAsString(&check_portal_list))
310 listener_->CheckPortalListChanged(check_portal_list);
311 } else {
312 VLOG(2) << "Ignored Manager Property: " << key;
316 void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type,
317 const base::ListValue& entries) {
318 std::set<std::string>& requested_updates = requested_updates_[type];
319 std::set<std::string> new_requested_updates;
320 NET_LOG_DEBUG("UpdateProperties: " + ManagedState::TypeToString(type),
321 base::StringPrintf("%" PRIuS, entries.GetSize()));
322 for (base::ListValue::const_iterator iter = entries.begin();
323 iter != entries.end(); ++iter) {
324 std::string path;
325 (*iter)->GetAsString(&path);
326 if (path.empty())
327 continue;
329 // We add a special case for devices here to work around an issue in shill
330 // that prevents it from sending property changed signals for cellular
331 // devices (see crbug.com/321854).
332 if (type == ManagedState::MANAGED_TYPE_DEVICE ||
333 requested_updates.find(path) == requested_updates.end()) {
334 RequestProperties(type, path);
336 new_requested_updates.insert(path);
338 requested_updates.swap(new_requested_updates);
341 void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
342 const base::ListValue& entries) {
343 ShillPropertyObserverMap& observer_map =
344 (type == ManagedState::MANAGED_TYPE_NETWORK)
345 ? observed_networks_ : observed_devices_;
346 ShillPropertyObserverMap new_observed;
347 for (auto* entry: entries) {
348 std::string path;
349 entry->GetAsString(&path);
350 if (path.empty())
351 continue;
352 auto iter = observer_map.find(path);
353 ShillPropertyObserver* observer;
354 if (iter != observer_map.end()) {
355 observer = iter->second;
356 } else {
357 // Create an observer for future updates.
358 observer = new ShillPropertyObserver(
359 type, path, base::Bind(
360 &ShillPropertyHandler::PropertyChangedCallback, AsWeakPtr()));
362 auto result = new_observed.insert(std::make_pair(path, observer));
363 if (!result.second) {
364 LOG(ERROR) << path << " is duplicated in the list.";
365 delete observer;
367 observer_map.erase(path);
368 // Limit the number of observed services.
369 if (new_observed.size() >= kMaxObserved)
370 break;
372 // Delete network service observers still in observer_map.
373 for (auto& observer: observer_map) {
374 delete observer.second;
376 observer_map.swap(new_observed);
379 void ShillPropertyHandler::UpdateAvailableTechnologies(
380 const base::ListValue& technologies) {
381 std::stringstream technologies_str;
382 technologies_str << technologies;
383 NET_LOG_EVENT("AvailableTechnologies:", technologies_str.str());
384 available_technologies_.clear();
385 for (base::ListValue::const_iterator iter = technologies.begin();
386 iter != technologies.end(); ++iter) {
387 std::string technology;
388 (*iter)->GetAsString(&technology);
389 DCHECK(!technology.empty());
390 available_technologies_.insert(technology);
392 listener_->TechnologyListChanged();
395 void ShillPropertyHandler::UpdateEnabledTechnologies(
396 const base::ListValue& technologies) {
397 std::stringstream technologies_str;
398 technologies_str << technologies;
399 NET_LOG_EVENT("EnabledTechnologies:", technologies_str.str());
400 enabled_technologies_.clear();
401 for (base::ListValue::const_iterator iter = technologies.begin();
402 iter != technologies.end(); ++iter) {
403 std::string technology;
404 (*iter)->GetAsString(&technology);
405 DCHECK(!technology.empty());
406 enabled_technologies_.insert(technology);
407 enabling_technologies_.erase(technology);
409 listener_->TechnologyListChanged();
412 void ShillPropertyHandler::UpdateUninitializedTechnologies(
413 const base::ListValue& technologies) {
414 std::stringstream technologies_str;
415 technologies_str << technologies;
416 NET_LOG_EVENT("UninitializedTechnologies:", technologies_str.str());
417 uninitialized_technologies_.clear();
418 for (base::ListValue::const_iterator iter = technologies.begin();
419 iter != technologies.end(); ++iter) {
420 std::string technology;
421 (*iter)->GetAsString(&technology);
422 DCHECK(!technology.empty());
423 uninitialized_technologies_.insert(technology);
425 listener_->TechnologyListChanged();
428 void ShillPropertyHandler::EnableTechnologyFailed(
429 const std::string& technology,
430 const network_handler::ErrorCallback& error_callback,
431 const std::string& dbus_error_name,
432 const std::string& dbus_error_message) {
433 enabling_technologies_.erase(technology);
434 network_handler::ShillErrorCallbackFunction(
435 "EnableTechnology Failed",
436 technology, error_callback,
437 dbus_error_name, dbus_error_message);
440 void ShillPropertyHandler::GetPropertiesCallback(
441 ManagedState::ManagedType type,
442 const std::string& path,
443 DBusMethodCallStatus call_status,
444 const base::DictionaryValue& properties) {
445 NET_LOG_DEBUG("GetPropertiesCallback: " + ManagedState::TypeToString(type),
446 path);
447 pending_updates_[type].erase(path);
448 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
449 // The shill service no longer exists. This can happen when a network
450 // has been removed.
451 NET_LOG_DEBUG("Failed to get properties",
452 base::StringPrintf("%s: %d", path.c_str(), call_status));
453 return;
455 listener_->UpdateManagedStateProperties(type, path, properties);
457 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
458 // Request IPConfig properties.
459 const base::Value* value;
460 if (properties.GetWithoutPathExpansion(shill::kIPConfigProperty, &value))
461 RequestIPConfig(type, path, *value);
462 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
463 // Clear and request IPConfig properties for each entry in IPConfigs.
464 const base::Value* value;
465 if (properties.GetWithoutPathExpansion(shill::kIPConfigsProperty, &value))
466 RequestIPConfigsList(type, path, *value);
469 // Notify the listener only when all updates for that type have completed.
470 if (pending_updates_[type].size() == 0)
471 listener_->ManagedStateListChanged(type);
474 void ShillPropertyHandler::PropertyChangedCallback(
475 ManagedState::ManagedType type,
476 const std::string& path,
477 const std::string& key,
478 const base::Value& value) {
479 if (type == ManagedState::MANAGED_TYPE_NETWORK &&
480 key == shill::kIPConfigProperty) {
481 RequestIPConfig(type, path, value);
482 } else if (type == ManagedState::MANAGED_TYPE_DEVICE &&
483 key == shill::kIPConfigsProperty) {
484 RequestIPConfigsList(type, path, value);
487 if (type == ManagedState::MANAGED_TYPE_NETWORK)
488 listener_->UpdateNetworkServiceProperty(path, key, value);
489 else if (type == ManagedState::MANAGED_TYPE_DEVICE)
490 listener_->UpdateDeviceProperty(path, key, value);
491 else
492 NOTREACHED();
495 void ShillPropertyHandler::RequestIPConfig(
496 ManagedState::ManagedType type,
497 const std::string& path,
498 const base::Value& ip_config_path_value) {
499 std::string ip_config_path;
500 if (!ip_config_path_value.GetAsString(&ip_config_path) ||
501 ip_config_path.empty()) {
502 NET_LOG_ERROR("Invalid IPConfig", path);
503 return;
505 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
506 dbus::ObjectPath(ip_config_path),
507 base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
508 AsWeakPtr(), type, path, ip_config_path));
511 void ShillPropertyHandler::RequestIPConfigsList(
512 ManagedState::ManagedType type,
513 const std::string& path,
514 const base::Value& ip_config_list_value) {
515 const base::ListValue* ip_configs;
516 if (!ip_config_list_value.GetAsList(&ip_configs))
517 return;
518 for (base::ListValue::const_iterator iter = ip_configs->begin();
519 iter != ip_configs->end(); ++iter) {
520 RequestIPConfig(type, path, **iter);
524 void ShillPropertyHandler::GetIPConfigCallback(
525 ManagedState::ManagedType type,
526 const std::string& path,
527 const std::string& ip_config_path,
528 DBusMethodCallStatus call_status,
529 const base::DictionaryValue& properties) {
530 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
531 // IP Config properties not availabe. Shill will emit a property change
532 // when they are.
533 NET_LOG_EVENT(
534 base::StringPrintf("Failed to get IP Config properties: %s: %d",
535 ip_config_path.c_str(), call_status), path);
536 return;
538 NET_LOG_EVENT("IP Config properties received", path);
539 listener_->UpdateIPConfigProperties(type, path, ip_config_path, properties);
542 } // namespace internal
543 } // namespace chromeos