Fixed incorrect call of updateContextMenuActionItems.
[chromium-blink-merge.git] / chromeos / network / shill_property_handler.cc
blob8f8329a3820505be90d2fb30b64581a2928c9854
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 virtual ~ShillPropertyObserver() {
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 virtual 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::ConnectToBestServices() const {
211 NET_LOG_EVENT("ConnectToBestServices", "");
212 shill_manager_->ConnectToBestServices(
213 base::Bind(&base::DoNothing),
214 base::Bind(&network_handler::ShillErrorCallbackFunction,
215 "ConnectToBestServices Failed",
216 "", network_handler::ErrorCallback()));
219 void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
220 const std::string& path) {
221 if (pending_updates_[type].find(path) != pending_updates_[type].end())
222 return; // Update already requested.
224 NET_LOG_DEBUG("Request Properties: " + ManagedState::TypeToString(type),
225 path);
226 pending_updates_[type].insert(path);
227 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
228 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
229 dbus::ObjectPath(path),
230 base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
231 AsWeakPtr(), type, path));
232 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
233 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
234 dbus::ObjectPath(path),
235 base::Bind(&ShillPropertyHandler::GetPropertiesCallback,
236 AsWeakPtr(), type, path));
237 } else {
238 NOTREACHED();
242 void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
243 const base::Value& value) {
244 ManagerPropertyChanged(key, value);
245 CheckPendingStateListUpdates(key);
248 //------------------------------------------------------------------------------
249 // Private methods
251 void ShillPropertyHandler::ManagerPropertiesCallback(
252 DBusMethodCallStatus call_status,
253 const base::DictionaryValue& properties) {
254 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
255 NET_LOG_ERROR("ManagerPropertiesCallback",
256 base::StringPrintf("Failed: %d", call_status));
257 return;
259 NET_LOG_EVENT("ManagerPropertiesCallback", "Success");
260 for (base::DictionaryValue::Iterator iter(properties);
261 !iter.IsAtEnd(); iter.Advance()) {
262 ManagerPropertyChanged(iter.key(), iter.value());
265 CheckPendingStateListUpdates("");
268 void 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::kServiceCompleteListProperty) &&
272 pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
273 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
275 if ((key.empty() || key == shill::kDevicesProperty) &&
276 pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
277 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
281 void ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
282 const base::Value& value) {
283 NET_LOG_DEBUG("ManagerPropertyChanged", key);
284 if (key == shill::kDefaultServiceProperty) {
285 std::string service_path;
286 value.GetAsString(&service_path);
287 listener_->DefaultNetworkServiceChanged(service_path);
288 } else if (key == shill::kServiceCompleteListProperty) {
289 const base::ListValue* vlist = GetListValue(key, value);
290 if (vlist) {
291 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
292 UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
293 UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
295 } else if (key == shill::kDevicesProperty) {
296 const base::ListValue* vlist = GetListValue(key, value);
297 if (vlist) {
298 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
299 UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
300 UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
302 } else if (key == shill::kAvailableTechnologiesProperty) {
303 const base::ListValue* vlist = GetListValue(key, value);
304 if (vlist)
305 UpdateAvailableTechnologies(*vlist);
306 } else if (key == shill::kEnabledTechnologiesProperty) {
307 const base::ListValue* vlist = GetListValue(key, value);
308 if (vlist)
309 UpdateEnabledTechnologies(*vlist);
310 } else if (key == shill::kUninitializedTechnologiesProperty) {
311 const base::ListValue* vlist = GetListValue(key, value);
312 if (vlist)
313 UpdateUninitializedTechnologies(*vlist);
314 } else if (key == shill::kProfilesProperty) {
315 listener_->ProfileListChanged();
316 } else if (key == shill::kCheckPortalListProperty) {
317 std::string check_portal_list;
318 if (value.GetAsString(&check_portal_list))
319 listener_->CheckPortalListChanged(check_portal_list);
320 } else {
321 VLOG(2) << "Ignored Manager Property: " << key;
325 void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type,
326 const base::ListValue& entries) {
327 std::set<std::string>& requested_updates = requested_updates_[type];
328 std::set<std::string> new_requested_updates;
329 NET_LOG_DEBUG("UpdateProperties: " + ManagedState::TypeToString(type),
330 base::StringPrintf("%" PRIuS, entries.GetSize()));
331 for (base::ListValue::const_iterator iter = entries.begin();
332 iter != entries.end(); ++iter) {
333 std::string path;
334 (*iter)->GetAsString(&path);
335 if (path.empty())
336 continue;
338 // We add a special case for devices here to work around an issue in shill
339 // that prevents it from sending property changed signals for cellular
340 // devices (see crbug.com/321854).
341 if (type == ManagedState::MANAGED_TYPE_DEVICE ||
342 requested_updates.find(path) == requested_updates.end()) {
343 RequestProperties(type, path);
345 new_requested_updates.insert(path);
347 requested_updates.swap(new_requested_updates);
350 void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
351 const base::ListValue& entries) {
352 ShillPropertyObserverMap& observer_map =
353 (type == ManagedState::MANAGED_TYPE_NETWORK)
354 ? observed_networks_ : observed_devices_;
355 ShillPropertyObserverMap new_observed;
356 for (auto* entry: entries) {
357 std::string path;
358 entry->GetAsString(&path);
359 if (path.empty())
360 continue;
361 auto iter = observer_map.find(path);
362 ShillPropertyObserver* observer;
363 if (iter != observer_map.end()) {
364 observer = iter->second;
365 } else {
366 // Create an observer for future updates.
367 observer = new ShillPropertyObserver(
368 type, path, base::Bind(
369 &ShillPropertyHandler::PropertyChangedCallback, AsWeakPtr()));
371 auto result = new_observed.insert(std::make_pair(path, observer));
372 if (!result.second) {
373 LOG(ERROR) << path << " is duplicated in the list.";
374 delete observer;
376 observer_map.erase(path);
377 // Limit the number of observed services.
378 if (new_observed.size() >= kMaxObserved)
379 break;
381 // Delete network service observers still in observer_map.
382 for (auto& observer: observer_map) {
383 delete observer.second;
385 observer_map.swap(new_observed);
388 void ShillPropertyHandler::UpdateAvailableTechnologies(
389 const base::ListValue& technologies) {
390 std::stringstream technologies_str;
391 technologies_str << technologies;
392 NET_LOG_EVENT("AvailableTechnologies:", technologies_str.str());
393 available_technologies_.clear();
394 for (base::ListValue::const_iterator iter = technologies.begin();
395 iter != technologies.end(); ++iter) {
396 std::string technology;
397 (*iter)->GetAsString(&technology);
398 DCHECK(!technology.empty());
399 available_technologies_.insert(technology);
401 listener_->TechnologyListChanged();
404 void ShillPropertyHandler::UpdateEnabledTechnologies(
405 const base::ListValue& technologies) {
406 std::stringstream technologies_str;
407 technologies_str << technologies;
408 NET_LOG_EVENT("EnabledTechnologies:", technologies_str.str());
409 enabled_technologies_.clear();
410 for (base::ListValue::const_iterator iter = technologies.begin();
411 iter != technologies.end(); ++iter) {
412 std::string technology;
413 (*iter)->GetAsString(&technology);
414 DCHECK(!technology.empty());
415 enabled_technologies_.insert(technology);
416 enabling_technologies_.erase(technology);
418 listener_->TechnologyListChanged();
421 void ShillPropertyHandler::UpdateUninitializedTechnologies(
422 const base::ListValue& technologies) {
423 std::stringstream technologies_str;
424 technologies_str << technologies;
425 NET_LOG_EVENT("UninitializedTechnologies:", technologies_str.str());
426 uninitialized_technologies_.clear();
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 uninitialized_technologies_.insert(technology);
434 listener_->TechnologyListChanged();
437 void ShillPropertyHandler::EnableTechnologyFailed(
438 const std::string& technology,
439 const network_handler::ErrorCallback& error_callback,
440 const std::string& dbus_error_name,
441 const std::string& dbus_error_message) {
442 enabling_technologies_.erase(technology);
443 network_handler::ShillErrorCallbackFunction(
444 "EnableTechnology Failed",
445 technology, error_callback,
446 dbus_error_name, dbus_error_message);
449 void ShillPropertyHandler::GetPropertiesCallback(
450 ManagedState::ManagedType type,
451 const std::string& path,
452 DBusMethodCallStatus call_status,
453 const base::DictionaryValue& properties) {
454 NET_LOG_DEBUG("GetPropertiesCallback: " + ManagedState::TypeToString(type),
455 path);
456 pending_updates_[type].erase(path);
457 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
458 // The shill service no longer exists. This can happen when a network
459 // has been removed.
460 NET_LOG_DEBUG("Failed to get properties",
461 base::StringPrintf("%s: %d", path.c_str(), call_status));
462 return;
464 listener_->UpdateManagedStateProperties(type, path, properties);
466 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
467 // Request IPConfig properties.
468 const base::Value* value;
469 if (properties.GetWithoutPathExpansion(shill::kIPConfigProperty, &value))
470 RequestIPConfig(type, path, *value);
471 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
472 // Clear and request IPConfig properties for each entry in IPConfigs.
473 const base::Value* value;
474 if (properties.GetWithoutPathExpansion(shill::kIPConfigsProperty, &value))
475 RequestIPConfigsList(type, path, *value);
478 // Notify the listener only when all updates for that type have completed.
479 if (pending_updates_[type].size() == 0)
480 listener_->ManagedStateListChanged(type);
483 void ShillPropertyHandler::PropertyChangedCallback(
484 ManagedState::ManagedType type,
485 const std::string& path,
486 const std::string& key,
487 const base::Value& value) {
488 if (type == ManagedState::MANAGED_TYPE_NETWORK &&
489 key == shill::kIPConfigProperty) {
490 RequestIPConfig(type, path, value);
491 } else if (type == ManagedState::MANAGED_TYPE_DEVICE &&
492 key == shill::kIPConfigsProperty) {
493 RequestIPConfigsList(type, path, value);
496 if (type == ManagedState::MANAGED_TYPE_NETWORK)
497 listener_->UpdateNetworkServiceProperty(path, key, value);
498 else if (type == ManagedState::MANAGED_TYPE_DEVICE)
499 listener_->UpdateDeviceProperty(path, key, value);
500 else
501 NOTREACHED();
504 void ShillPropertyHandler::RequestIPConfig(
505 ManagedState::ManagedType type,
506 const std::string& path,
507 const base::Value& ip_config_path_value) {
508 std::string ip_config_path;
509 if (!ip_config_path_value.GetAsString(&ip_config_path) ||
510 ip_config_path.empty()) {
511 NET_LOG_ERROR("Invalid IPConfig", path);
512 return;
514 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
515 dbus::ObjectPath(ip_config_path),
516 base::Bind(&ShillPropertyHandler::GetIPConfigCallback,
517 AsWeakPtr(), type, path, ip_config_path));
520 void ShillPropertyHandler::RequestIPConfigsList(
521 ManagedState::ManagedType type,
522 const std::string& path,
523 const base::Value& ip_config_list_value) {
524 const base::ListValue* ip_configs;
525 if (!ip_config_list_value.GetAsList(&ip_configs))
526 return;
527 for (base::ListValue::const_iterator iter = ip_configs->begin();
528 iter != ip_configs->end(); ++iter) {
529 RequestIPConfig(type, path, **iter);
533 void ShillPropertyHandler::GetIPConfigCallback(
534 ManagedState::ManagedType type,
535 const std::string& path,
536 const std::string& ip_config_path,
537 DBusMethodCallStatus call_status,
538 const base::DictionaryValue& properties) {
539 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
540 // IP Config properties not availabe. Shill will emit a property change
541 // when they are.
542 NET_LOG_EVENT(
543 base::StringPrintf("Failed to get IP Config properties: %s: %d",
544 ip_config_path.c_str(), call_status), path);
545 return;
547 NET_LOG_EVENT("IP Config properties received", path);
548 listener_->UpdateIPConfigProperties(type, path, ip_config_path, properties);
551 } // namespace internal
552 } // namespace chromeos