Upstream changes for NetworkQualityProvider
[chromium-blink-merge.git] / chromeos / network / shill_property_handler.cc
blob02b620d38e6e2895d65b0cccbf3752c4a1bbd5ca
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/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_profile_client.h"
18 #include "chromeos/dbus/shill_service_client.h"
19 #include "chromeos/network/network_state.h"
20 #include "components/device_event_log/device_event_log.h"
21 #include "dbus/object_path.h"
22 #include "third_party/cros_system_api/dbus/service_constants.h"
24 namespace {
26 // Limit the number of services or devices we observe. Since they are listed in
27 // priority order, it should be reasonable to ignore services past this.
28 const size_t kMaxObserved = 100;
30 const base::ListValue* GetListValue(const std::string& key,
31 const base::Value& value) {
32 const base::ListValue* vlist = NULL;
33 if (!value.GetAsList(&vlist)) {
34 LOG(ERROR) << "Error parsing key as list: " << key;
35 return NULL;
37 return vlist;
40 } // namespace
42 namespace chromeos {
43 namespace internal {
45 // Class to manage Shill service property changed observers. Observers are
46 // added on construction and removed on destruction. Runs the handler when
47 // OnPropertyChanged is called.
48 class ShillPropertyObserver : public ShillPropertyChangedObserver {
49 public:
50 typedef base::Callback<void(ManagedState::ManagedType type,
51 const std::string& service,
52 const std::string& name,
53 const base::Value& value)> Handler;
55 ShillPropertyObserver(ManagedState::ManagedType type,
56 const std::string& path,
57 const Handler& handler)
58 : type_(type), path_(path), handler_(handler) {
59 if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
60 DVLOG(2) << "ShillPropertyObserver: Network: " << path;
61 DBusThreadManager::Get()
62 ->GetShillServiceClient()
63 ->AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
64 } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
65 DVLOG(2) << "ShillPropertyObserver: Device: " << path;
66 DBusThreadManager::Get()
67 ->GetShillDeviceClient()
68 ->AddPropertyChangedObserver(dbus::ObjectPath(path_), this);
69 } else {
70 NOTREACHED();
74 ~ShillPropertyObserver() override {
75 if (type_ == ManagedState::MANAGED_TYPE_NETWORK) {
76 DBusThreadManager::Get()
77 ->GetShillServiceClient()
78 ->RemovePropertyChangedObserver(dbus::ObjectPath(path_), this);
79 } else if (type_ == ManagedState::MANAGED_TYPE_DEVICE) {
80 DBusThreadManager::Get()
81 ->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(observed_networks_.begin(),
113 observed_networks_.end());
114 STLDeleteContainerPairSecondPointers(observed_devices_.begin(),
115 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(base::Bind(
128 &ShillPropertyHandler::ManagerPropertiesCallback, AsWeakPtr()));
131 bool ShillPropertyHandler::IsTechnologyAvailable(
132 const std::string& technology) const {
133 return available_technologies_.count(technology) != 0;
136 bool ShillPropertyHandler::IsTechnologyEnabled(
137 const std::string& technology) const {
138 return enabled_technologies_.count(technology) != 0;
141 bool ShillPropertyHandler::IsTechnologyEnabling(
142 const std::string& technology) const {
143 return enabling_technologies_.count(technology) != 0;
146 bool ShillPropertyHandler::IsTechnologyUninitialized(
147 const std::string& technology) const {
148 return uninitialized_technologies_.count(technology) != 0;
151 void ShillPropertyHandler::SetTechnologyEnabled(
152 const std::string& technology,
153 bool enabled,
154 const network_handler::ErrorCallback& error_callback) {
155 if (enabled) {
156 enabling_technologies_.insert(technology);
157 shill_manager_->EnableTechnology(
158 technology, base::Bind(&base::DoNothing),
159 base::Bind(&ShillPropertyHandler::EnableTechnologyFailed, AsWeakPtr(),
160 technology, error_callback));
161 } else {
162 // Immediately clear locally from enabled and enabling lists.
163 enabled_technologies_.erase(technology);
164 enabling_technologies_.erase(technology);
165 shill_manager_->DisableTechnology(
166 technology, base::Bind(&base::DoNothing),
167 base::Bind(&network_handler::ShillErrorCallbackFunction,
168 "SetTechnologyEnabled Failed", technology, error_callback));
172 void ShillPropertyHandler::SetCheckPortalList(
173 const std::string& check_portal_list) {
174 base::StringValue value(check_portal_list);
175 shill_manager_->SetProperty(
176 shill::kCheckPortalListProperty, value, base::Bind(&base::DoNothing),
177 base::Bind(&network_handler::ShillErrorCallbackFunction,
178 "SetCheckPortalList Failed", "Manager",
179 network_handler::ErrorCallback()));
182 void ShillPropertyHandler::SetWakeOnLanEnabled(bool enabled) {
183 base::FundamentalValue value(enabled);
184 shill_manager_->SetProperty(
185 shill::kWakeOnLanEnabledProperty, value, base::Bind(&base::DoNothing),
186 base::Bind(&network_handler::ShillErrorCallbackFunction,
187 "SetWakeOnLanEnabled Failed", "Manager",
188 network_handler::ErrorCallback()));
191 void ShillPropertyHandler::RequestScan() const {
192 shill_manager_->RequestScan(
193 "", base::Bind(&base::DoNothing),
194 base::Bind(&network_handler::ShillErrorCallbackFunction,
195 "RequestScan Failed", "", network_handler::ErrorCallback()));
198 void ShillPropertyHandler::RequestProperties(ManagedState::ManagedType type,
199 const std::string& path) {
200 if (pending_updates_[type].find(path) != pending_updates_[type].end())
201 return; // Update already requested.
203 NET_LOG(DEBUG) << "Request Properties: " << ManagedState::TypeToString(type)
204 << " For: " << path;
205 pending_updates_[type].insert(path);
206 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
207 DBusThreadManager::Get()->GetShillServiceClient()->GetProperties(
208 dbus::ObjectPath(path),
209 base::Bind(&ShillPropertyHandler::GetPropertiesCallback, AsWeakPtr(),
210 type, path));
211 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
212 DBusThreadManager::Get()->GetShillDeviceClient()->GetProperties(
213 dbus::ObjectPath(path),
214 base::Bind(&ShillPropertyHandler::GetPropertiesCallback, AsWeakPtr(),
215 type, path));
216 } else {
217 NOTREACHED();
221 void ShillPropertyHandler::OnPropertyChanged(const std::string& key,
222 const base::Value& value) {
223 ManagerPropertyChanged(key, value);
224 CheckPendingStateListUpdates(key);
227 //------------------------------------------------------------------------------
228 // Private methods
230 void ShillPropertyHandler::ManagerPropertiesCallback(
231 DBusMethodCallStatus call_status,
232 const base::DictionaryValue& properties) {
233 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
234 NET_LOG(ERROR) << "ManagerPropertiesCallback Failed: " << call_status;
235 return;
237 NET_LOG(EVENT) << "ManagerPropertiesCallback: Success";
238 for (base::DictionaryValue::Iterator iter(properties); !iter.IsAtEnd();
239 iter.Advance()) {
240 ManagerPropertyChanged(iter.key(), iter.value());
243 CheckPendingStateListUpdates("");
246 void ShillPropertyHandler::CheckPendingStateListUpdates(
247 const std::string& key) {
248 // Once there are no pending updates, signal the state list changed callbacks.
249 if ((key.empty() || key == shill::kServiceCompleteListProperty) &&
250 pending_updates_[ManagedState::MANAGED_TYPE_NETWORK].size() == 0) {
251 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_NETWORK);
253 if ((key.empty() || key == shill::kDevicesProperty) &&
254 pending_updates_[ManagedState::MANAGED_TYPE_DEVICE].size() == 0) {
255 listener_->ManagedStateListChanged(ManagedState::MANAGED_TYPE_DEVICE);
259 void ShillPropertyHandler::ManagerPropertyChanged(const std::string& key,
260 const base::Value& value) {
261 if (key == shill::kDefaultServiceProperty) {
262 std::string service_path;
263 value.GetAsString(&service_path);
264 NET_LOG(EVENT) << "Manager.DefaultService = " << service_path;
265 listener_->DefaultNetworkServiceChanged(service_path);
266 return;
268 NET_LOG(DEBUG) << "ManagerPropertyChanged: " << key;
269 if (key == shill::kServiceCompleteListProperty) {
270 const base::ListValue* vlist = GetListValue(key, value);
271 if (vlist) {
272 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
273 UpdateProperties(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
274 UpdateObserved(ManagedState::MANAGED_TYPE_NETWORK, *vlist);
276 } else if (key == shill::kDevicesProperty) {
277 const base::ListValue* vlist = GetListValue(key, value);
278 if (vlist) {
279 listener_->UpdateManagedList(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
280 UpdateProperties(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
281 UpdateObserved(ManagedState::MANAGED_TYPE_DEVICE, *vlist);
283 } else if (key == shill::kAvailableTechnologiesProperty) {
284 const base::ListValue* vlist = GetListValue(key, value);
285 if (vlist)
286 UpdateAvailableTechnologies(*vlist);
287 } else if (key == shill::kEnabledTechnologiesProperty) {
288 const base::ListValue* vlist = GetListValue(key, value);
289 if (vlist)
290 UpdateEnabledTechnologies(*vlist);
291 } else if (key == shill::kUninitializedTechnologiesProperty) {
292 const base::ListValue* vlist = GetListValue(key, value);
293 if (vlist)
294 UpdateUninitializedTechnologies(*vlist);
295 } else if (key == shill::kProfilesProperty) {
296 listener_->ProfileListChanged();
297 } else if (key == shill::kCheckPortalListProperty) {
298 std::string check_portal_list;
299 if (value.GetAsString(&check_portal_list))
300 listener_->CheckPortalListChanged(check_portal_list);
301 } else {
302 VLOG(2) << "Ignored Manager Property: " << key;
306 void ShillPropertyHandler::UpdateProperties(ManagedState::ManagedType type,
307 const base::ListValue& entries) {
308 std::set<std::string>& requested_updates = requested_updates_[type];
309 std::set<std::string> new_requested_updates;
310 NET_LOG(DEBUG) << "UpdateProperties: " << ManagedState::TypeToString(type)
311 << ": " << entries.GetSize();
312 for (base::ListValue::const_iterator iter = entries.begin();
313 iter != entries.end(); ++iter) {
314 std::string path;
315 (*iter)->GetAsString(&path);
316 if (path.empty())
317 continue;
319 // We add a special case for devices here to work around an issue in shill
320 // that prevents it from sending property changed signals for cellular
321 // devices (see crbug.com/321854).
322 if (type == ManagedState::MANAGED_TYPE_DEVICE ||
323 requested_updates.find(path) == requested_updates.end()) {
324 RequestProperties(type, path);
326 new_requested_updates.insert(path);
328 requested_updates.swap(new_requested_updates);
331 void ShillPropertyHandler::UpdateObserved(ManagedState::ManagedType type,
332 const base::ListValue& entries) {
333 ShillPropertyObserverMap& observer_map =
334 (type == ManagedState::MANAGED_TYPE_NETWORK) ? observed_networks_
335 : observed_devices_;
336 ShillPropertyObserverMap new_observed;
337 for (auto* entry : entries) {
338 std::string path;
339 entry->GetAsString(&path);
340 if (path.empty())
341 continue;
342 auto iter = observer_map.find(path);
343 ShillPropertyObserver* observer;
344 if (iter != observer_map.end()) {
345 observer = iter->second;
346 } else {
347 // Create an observer for future updates.
348 observer = new ShillPropertyObserver(
349 type, path, base::Bind(&ShillPropertyHandler::PropertyChangedCallback,
350 AsWeakPtr()));
352 auto result = new_observed.insert(std::make_pair(path, observer));
353 if (!result.second) {
354 LOG(ERROR) << path << " is duplicated in the list.";
355 delete observer;
357 observer_map.erase(path);
358 // Limit the number of observed services.
359 if (new_observed.size() >= kMaxObserved)
360 break;
362 // Delete network service observers still in observer_map.
363 for (auto& observer : observer_map) {
364 delete observer.second;
366 observer_map.swap(new_observed);
369 void ShillPropertyHandler::UpdateAvailableTechnologies(
370 const base::ListValue& technologies) {
371 NET_LOG(EVENT) << "AvailableTechnologies:" << technologies;
372 available_technologies_.clear();
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 available_technologies_.insert(technology);
380 listener_->TechnologyListChanged();
383 void ShillPropertyHandler::UpdateEnabledTechnologies(
384 const base::ListValue& technologies) {
385 NET_LOG(EVENT) << "EnabledTechnologies:" << technologies;
386 enabled_technologies_.clear();
387 for (base::ListValue::const_iterator iter = technologies.begin();
388 iter != technologies.end(); ++iter) {
389 std::string technology;
390 (*iter)->GetAsString(&technology);
391 DCHECK(!technology.empty());
392 enabled_technologies_.insert(technology);
393 enabling_technologies_.erase(technology);
395 listener_->TechnologyListChanged();
398 void ShillPropertyHandler::UpdateUninitializedTechnologies(
399 const base::ListValue& technologies) {
400 NET_LOG(EVENT) << "UninitializedTechnologies:" << technologies;
401 uninitialized_technologies_.clear();
402 for (base::ListValue::const_iterator iter = technologies.begin();
403 iter != technologies.end(); ++iter) {
404 std::string technology;
405 (*iter)->GetAsString(&technology);
406 DCHECK(!technology.empty());
407 uninitialized_technologies_.insert(technology);
409 listener_->TechnologyListChanged();
412 void ShillPropertyHandler::EnableTechnologyFailed(
413 const std::string& technology,
414 const network_handler::ErrorCallback& error_callback,
415 const std::string& dbus_error_name,
416 const std::string& dbus_error_message) {
417 enabling_technologies_.erase(technology);
418 network_handler::ShillErrorCallbackFunction(
419 "EnableTechnology Failed", technology, error_callback, dbus_error_name,
420 dbus_error_message);
423 void ShillPropertyHandler::GetPropertiesCallback(
424 ManagedState::ManagedType type,
425 const std::string& path,
426 DBusMethodCallStatus call_status,
427 const base::DictionaryValue& properties) {
428 NET_LOG(DEBUG) << "GetPropertiesCallback: "
429 << ManagedState::TypeToString(type) << " For: " << path;
430 pending_updates_[type].erase(path);
431 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
432 // The shill service no longer exists. This can happen when a network
433 // has been removed.
434 NET_LOG(DEBUG) << "Failed to get properties for: " << path << ": "
435 << call_status;
436 return;
438 listener_->UpdateManagedStateProperties(type, path, properties);
440 if (type == ManagedState::MANAGED_TYPE_NETWORK) {
441 // Request IPConfig properties.
442 const base::Value* value;
443 if (properties.GetWithoutPathExpansion(shill::kIPConfigProperty, &value))
444 RequestIPConfig(type, path, *value);
445 } else if (type == ManagedState::MANAGED_TYPE_DEVICE) {
446 // Clear and request IPConfig properties for each entry in IPConfigs.
447 const base::Value* value;
448 if (properties.GetWithoutPathExpansion(shill::kIPConfigsProperty, &value))
449 RequestIPConfigsList(type, path, *value);
452 // Notify the listener only when all updates for that type have completed.
453 if (pending_updates_[type].size() == 0)
454 listener_->ManagedStateListChanged(type);
457 void ShillPropertyHandler::PropertyChangedCallback(
458 ManagedState::ManagedType type,
459 const std::string& path,
460 const std::string& key,
461 const base::Value& value) {
462 if (type == ManagedState::MANAGED_TYPE_NETWORK &&
463 key == shill::kIPConfigProperty) {
464 RequestIPConfig(type, path, value);
465 } else if (type == ManagedState::MANAGED_TYPE_DEVICE &&
466 key == shill::kIPConfigsProperty) {
467 RequestIPConfigsList(type, path, value);
470 if (type == ManagedState::MANAGED_TYPE_NETWORK)
471 listener_->UpdateNetworkServiceProperty(path, key, value);
472 else if (type == ManagedState::MANAGED_TYPE_DEVICE)
473 listener_->UpdateDeviceProperty(path, key, value);
474 else
475 NOTREACHED();
478 void ShillPropertyHandler::RequestIPConfig(
479 ManagedState::ManagedType type,
480 const std::string& path,
481 const base::Value& ip_config_path_value) {
482 std::string ip_config_path;
483 if (!ip_config_path_value.GetAsString(&ip_config_path) ||
484 ip_config_path.empty()) {
485 NET_LOG(ERROR) << "Invalid IPConfig: " << path;
486 return;
488 DBusThreadManager::Get()->GetShillIPConfigClient()->GetProperties(
489 dbus::ObjectPath(ip_config_path),
490 base::Bind(&ShillPropertyHandler::GetIPConfigCallback, AsWeakPtr(), type,
491 path, ip_config_path));
494 void ShillPropertyHandler::RequestIPConfigsList(
495 ManagedState::ManagedType type,
496 const std::string& path,
497 const base::Value& ip_config_list_value) {
498 const base::ListValue* ip_configs;
499 if (!ip_config_list_value.GetAsList(&ip_configs))
500 return;
501 for (base::ListValue::const_iterator iter = ip_configs->begin();
502 iter != ip_configs->end(); ++iter) {
503 RequestIPConfig(type, path, **iter);
507 void ShillPropertyHandler::GetIPConfigCallback(
508 ManagedState::ManagedType type,
509 const std::string& path,
510 const std::string& ip_config_path,
511 DBusMethodCallStatus call_status,
512 const base::DictionaryValue& properties) {
513 if (call_status != DBUS_METHOD_CALL_SUCCESS) {
514 // IP Config properties not availabe. Shill will emit a property change
515 // when they are.
516 NET_LOG(EVENT) << "Failed to get IP Config properties: " << ip_config_path
517 << ": " << call_status << ", For: " << path;
518 return;
520 NET_LOG(EVENT) << "IP Config properties received: " << path;
521 listener_->UpdateIPConfigProperties(type, path, ip_config_path, properties);
524 } // namespace internal
525 } // namespace chromeos