1 // Copyright 2013 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/dbus/fake_shill_manager_client.h"
8 #include "base/command_line.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/values.h"
11 #include "chromeos/chromeos_switches.h"
12 #include "chromeos/dbus/dbus_thread_manager.h"
13 #include "chromeos/dbus/shill_device_client.h"
14 #include "chromeos/dbus/shill_profile_client.h"
15 #include "chromeos/dbus/shill_property_changed_observer.h"
16 #include "chromeos/dbus/shill_service_client.h"
18 #include "dbus/message.h"
19 #include "dbus/object_path.h"
20 #include "dbus/values_util.h"
21 #include "third_party/cros_system_api/dbus/service_constants.h"
27 // Used to compare values for finding entries to erase in a ListValue.
28 // (ListValue only implements a const_iterator version of Find).
30 explicit ValueEquals(const base::Value* first) : first_(first) {}
31 bool operator()(const base::Value* second) const {
32 return first_->Equals(second);
34 const base::Value* first_;
37 // Appends string entries from |service_list_in| whose entries in ServiceClient
38 // have Type |match_type| to either an active list or an inactive list
39 // based on the entry's State.
40 void AppendServicesForType(
41 const base::ListValue* service_list_in,
42 const char* match_type,
43 std::vector<std::string>* active_service_list_out,
44 std::vector<std::string>* inactive_service_list_out) {
45 ShillServiceClient::TestInterface* service_client =
46 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
47 for (base::ListValue::const_iterator iter = service_list_in->begin();
48 iter != service_list_in->end(); ++iter) {
49 std::string service_path;
50 if (!(*iter)->GetAsString(&service_path))
52 const base::DictionaryValue* properties =
53 service_client->GetServiceProperties(service_path);
55 LOG(ERROR) << "Properties not found for service: " << service_path;
59 properties->GetString(shill::kTypeProperty, &type);
60 if (type != match_type)
63 properties->GetString(shill::kStateProperty, &state);
64 if (state == shill::kStateOnline ||
65 state == shill::kStateAssociation ||
66 state == shill::kStateConfiguration ||
67 state == shill::kStatePortal ||
68 state == shill::kStateReady) {
69 active_service_list_out->push_back(service_path);
71 inactive_service_list_out->push_back(service_path);
78 FakeShillManagerClient::FakeShillManagerClient()
79 : weak_ptr_factory_(this) {
82 FakeShillManagerClient::~FakeShillManagerClient() {}
84 // ShillManagerClient overrides.
86 void FakeShillManagerClient::Init(dbus::Bus* bus) {}
88 void FakeShillManagerClient::AddPropertyChangedObserver(
89 ShillPropertyChangedObserver* observer) {
90 observer_list_.AddObserver(observer);
93 void FakeShillManagerClient::RemovePropertyChangedObserver(
94 ShillPropertyChangedObserver* observer) {
95 observer_list_.RemoveObserver(observer);
98 void FakeShillManagerClient::GetProperties(
99 const DictionaryValueCallback& callback) {
100 base::MessageLoop::current()->PostTask(
101 FROM_HERE, base::Bind(
102 &FakeShillManagerClient::PassStubProperties,
103 weak_ptr_factory_.GetWeakPtr(),
107 void FakeShillManagerClient::GetNetworksForGeolocation(
108 const DictionaryValueCallback& callback) {
109 base::MessageLoop::current()->PostTask(
110 FROM_HERE, base::Bind(
111 &FakeShillManagerClient::PassStubGeoNetworks,
112 weak_ptr_factory_.GetWeakPtr(),
116 void FakeShillManagerClient::SetProperty(const std::string& name,
117 const base::Value& value,
118 const base::Closure& callback,
119 const ErrorCallback& error_callback) {
120 stub_properties_.SetWithoutPathExpansion(name, value.DeepCopy());
121 CallNotifyObserversPropertyChanged(name, 0);
122 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
125 void FakeShillManagerClient::RequestScan(const std::string& type,
126 const base::Closure& callback,
127 const ErrorCallback& error_callback) {
128 // For Stub purposes, default to a Wifi scan.
129 std::string device_type = shill::kTypeWifi;
132 ShillDeviceClient::TestInterface* device_client =
133 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface();
134 std::string device_path = device_client->GetDevicePathForType(device_type);
135 if (!device_path.empty()) {
136 device_client->SetDeviceProperty(device_path,
137 shill::kScanningProperty,
138 base::FundamentalValue(true));
140 const int kScanDurationSeconds = 3;
141 int scan_duration_seconds = kScanDurationSeconds;
142 if (!CommandLine::ForCurrentProcess()->HasSwitch(
143 chromeos::switches::kEnableStubInteractive)) {
144 scan_duration_seconds = 0;
146 base::MessageLoop::current()->PostDelayedTask(
148 base::Bind(&FakeShillManagerClient::ScanCompleted,
149 weak_ptr_factory_.GetWeakPtr(), device_path, callback),
150 base::TimeDelta::FromSeconds(scan_duration_seconds));
153 void FakeShillManagerClient::EnableTechnology(
154 const std::string& type,
155 const base::Closure& callback,
156 const ErrorCallback& error_callback) {
157 base::ListValue* enabled_list = NULL;
158 if (!stub_properties_.GetListWithoutPathExpansion(
159 shill::kEnabledTechnologiesProperty, &enabled_list)) {
160 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
161 base::MessageLoop::current()->PostTask(
163 base::Bind(error_callback, "StubError", "Property not found"));
166 if (CommandLine::ForCurrentProcess()->HasSwitch(
167 chromeos::switches::kEnableStubInteractive)) {
168 const int kEnableTechnologyDelaySeconds = 3;
169 base::MessageLoop::current()->PostDelayedTask(
171 base::Bind(&FakeShillManagerClient::SetTechnologyEnabled,
172 weak_ptr_factory_.GetWeakPtr(), type, callback, true),
173 base::TimeDelta::FromSeconds(kEnableTechnologyDelaySeconds));
175 SetTechnologyEnabled(type, callback, true);
179 void FakeShillManagerClient::DisableTechnology(
180 const std::string& type,
181 const base::Closure& callback,
182 const ErrorCallback& error_callback) {
183 base::ListValue* enabled_list = NULL;
184 if (!stub_properties_.GetListWithoutPathExpansion(
185 shill::kEnabledTechnologiesProperty, &enabled_list)) {
186 base::MessageLoop::current()->PostTask(
188 base::Bind(error_callback, "StubError", "Property not found"));
191 if (CommandLine::ForCurrentProcess()->HasSwitch(
192 chromeos::switches::kEnableStubInteractive)) {
193 const int kDisableTechnologyDelaySeconds = 3;
194 base::MessageLoop::current()->PostDelayedTask(
196 base::Bind(&FakeShillManagerClient::SetTechnologyEnabled,
197 weak_ptr_factory_.GetWeakPtr(), type, callback, false),
198 base::TimeDelta::FromSeconds(kDisableTechnologyDelaySeconds));
200 SetTechnologyEnabled(type, callback, false);
204 void FakeShillManagerClient::ConfigureService(
205 const base::DictionaryValue& properties,
206 const ObjectPathCallback& callback,
207 const ErrorCallback& error_callback) {
208 ShillServiceClient::TestInterface* service_client =
209 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
213 if (!properties.GetString(shill::kGuidProperty, &guid) ||
214 !properties.GetString(shill::kTypeProperty, &type)) {
215 LOG(ERROR) << "ConfigureService requies GUID and Type to be defined";
216 // If the properties aren't filled out completely, then just return an empty
218 base::MessageLoop::current()->PostTask(
219 FROM_HERE, base::Bind(callback, dbus::ObjectPath()));
223 // For the purposes of this stub, we're going to assume that the GUID property
224 // is set to the service path because we don't want to re-implement Shill's
225 // property matching magic here.
226 std::string service_path = guid;
228 std::string ipconfig_path;
229 properties.GetString(shill::kIPConfigProperty, &ipconfig_path);
231 // Merge the new properties with existing properties, if any.
232 const base::DictionaryValue* existing_properties =
233 service_client->GetServiceProperties(service_path);
234 if (!existing_properties) {
235 // Add a new service to the service client stub because none exists, yet.
236 // This calls AddManagerService.
237 service_client->AddServiceWithIPConfig(service_path, guid, type,
238 shill::kStateIdle, ipconfig_path,
241 existing_properties = service_client->GetServiceProperties(service_path);
244 scoped_ptr<base::DictionaryValue> merged_properties(
245 existing_properties->DeepCopy());
246 merged_properties->MergeDictionary(&properties);
248 // Now set all the properties.
249 for (base::DictionaryValue::Iterator iter(*merged_properties);
250 !iter.IsAtEnd(); iter.Advance()) {
251 service_client->SetServiceProperty(service_path, iter.key(), iter.value());
254 // If the Profile property is set, add it to ProfileClient.
255 std::string profile_path;
256 merged_properties->GetStringWithoutPathExpansion(shill::kProfileProperty,
258 if (!profile_path.empty()) {
259 DBusThreadManager::Get()->GetShillProfileClient()->GetTestInterface()->
260 AddService(profile_path, service_path);
263 base::MessageLoop::current()->PostTask(
264 FROM_HERE, base::Bind(callback, dbus::ObjectPath(service_path)));
267 void FakeShillManagerClient::ConfigureServiceForProfile(
268 const dbus::ObjectPath& profile_path,
269 const base::DictionaryValue& properties,
270 const ObjectPathCallback& callback,
271 const ErrorCallback& error_callback) {
272 std::string profile_property;
273 properties.GetStringWithoutPathExpansion(shill::kProfileProperty,
275 CHECK(profile_property == profile_path.value());
276 ConfigureService(properties, callback, error_callback);
280 void FakeShillManagerClient::GetService(
281 const base::DictionaryValue& properties,
282 const ObjectPathCallback& callback,
283 const ErrorCallback& error_callback) {
284 base::MessageLoop::current()->PostTask(
285 FROM_HERE, base::Bind(callback, dbus::ObjectPath()));
288 void FakeShillManagerClient::VerifyDestination(
289 const VerificationProperties& properties,
290 const BooleanCallback& callback,
291 const ErrorCallback& error_callback) {
292 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind(callback, true));
295 void FakeShillManagerClient::VerifyAndEncryptCredentials(
296 const VerificationProperties& properties,
297 const std::string& service_path,
298 const StringCallback& callback,
299 const ErrorCallback& error_callback) {
300 base::MessageLoop::current()->PostTask(
301 FROM_HERE, base::Bind(callback, "encrypted_credentials"));
304 void FakeShillManagerClient::VerifyAndEncryptData(
305 const VerificationProperties& properties,
306 const std::string& data,
307 const StringCallback& callback,
308 const ErrorCallback& error_callback) {
309 base::MessageLoop::current()->PostTask(FROM_HERE,
310 base::Bind(callback, "encrypted_data"));
313 void FakeShillManagerClient::ConnectToBestServices(
314 const base::Closure& callback,
315 const ErrorCallback& error_callback) {
318 ShillManagerClient::TestInterface* FakeShillManagerClient::GetTestInterface() {
322 // ShillManagerClient::TestInterface overrides.
324 void FakeShillManagerClient::AddDevice(const std::string& device_path) {
325 if (GetListProperty(shill::kDevicesProperty)->AppendIfNotPresent(
326 base::Value::CreateStringValue(device_path))) {
327 CallNotifyObserversPropertyChanged(shill::kDevicesProperty, 0);
331 void FakeShillManagerClient::RemoveDevice(const std::string& device_path) {
332 base::StringValue device_path_value(device_path);
333 if (GetListProperty(shill::kDevicesProperty)->Remove(
334 device_path_value, NULL)) {
335 CallNotifyObserversPropertyChanged(shill::kDevicesProperty, 0);
339 void FakeShillManagerClient::ClearDevices() {
340 GetListProperty(shill::kDevicesProperty)->Clear();
341 CallNotifyObserversPropertyChanged(shill::kDevicesProperty, 0);
344 void FakeShillManagerClient::AddTechnology(const std::string& type,
346 if (GetListProperty(shill::kAvailableTechnologiesProperty)->
347 AppendIfNotPresent(base::Value::CreateStringValue(type))) {
348 CallNotifyObserversPropertyChanged(
349 shill::kAvailableTechnologiesProperty, 0);
352 GetListProperty(shill::kEnabledTechnologiesProperty)->
353 AppendIfNotPresent(base::Value::CreateStringValue(type))) {
354 CallNotifyObserversPropertyChanged(
355 shill::kEnabledTechnologiesProperty, 0);
359 void FakeShillManagerClient::RemoveTechnology(const std::string& type) {
360 base::StringValue type_value(type);
361 if (GetListProperty(shill::kAvailableTechnologiesProperty)->Remove(
363 CallNotifyObserversPropertyChanged(
364 shill::kAvailableTechnologiesProperty, 0);
366 if (GetListProperty(shill::kEnabledTechnologiesProperty)->Remove(
368 CallNotifyObserversPropertyChanged(
369 shill::kEnabledTechnologiesProperty, 0);
373 void FakeShillManagerClient::SetTechnologyInitializing(const std::string& type,
376 if (GetListProperty(shill::kUninitializedTechnologiesProperty)->
377 AppendIfNotPresent(base::Value::CreateStringValue(type))) {
378 CallNotifyObserversPropertyChanged(
379 shill::kUninitializedTechnologiesProperty, 0);
382 if (GetListProperty(shill::kUninitializedTechnologiesProperty)->Remove(
383 base::StringValue(type), NULL)) {
384 CallNotifyObserversPropertyChanged(
385 shill::kUninitializedTechnologiesProperty, 0);
390 void FakeShillManagerClient::ClearProperties() {
391 stub_properties_.Clear();
394 void FakeShillManagerClient::AddManagerService(const std::string& service_path,
395 bool add_to_visible_list,
396 bool add_to_watch_list) {
397 // Always add to ServiceCompleteListProperty.
398 GetListProperty(shill::kServiceCompleteListProperty)->AppendIfNotPresent(
399 base::Value::CreateStringValue(service_path));
400 // If visible, add to Services and notify if new.
401 if (add_to_visible_list &&
402 GetListProperty(shill::kServicesProperty)->AppendIfNotPresent(
403 base::Value::CreateStringValue(service_path))) {
404 CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
406 if (add_to_watch_list)
407 AddServiceToWatchList(service_path);
410 void FakeShillManagerClient::RemoveManagerService(
411 const std::string& service_path) {
412 base::StringValue service_path_value(service_path);
413 if (GetListProperty(shill::kServicesProperty)->Remove(
414 service_path_value, NULL)) {
415 CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
417 GetListProperty(shill::kServiceCompleteListProperty)->Remove(
418 service_path_value, NULL);
419 if (GetListProperty(shill::kServiceWatchListProperty)->Remove(
420 service_path_value, NULL)) {
421 CallNotifyObserversPropertyChanged(
422 shill::kServiceWatchListProperty, 0);
426 void FakeShillManagerClient::ClearManagerServices() {
427 GetListProperty(shill::kServicesProperty)->Clear();
428 GetListProperty(shill::kServiceCompleteListProperty)->Clear();
429 GetListProperty(shill::kServiceWatchListProperty)->Clear();
430 CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
431 CallNotifyObserversPropertyChanged(shill::kServiceWatchListProperty, 0);
434 void FakeShillManagerClient::SortManagerServices() {
435 static const char* ordered_types[] = {
436 shill::kTypeEthernet,
438 shill::kTypeCellular,
442 base::ListValue* service_list = GetListProperty(shill::kServicesProperty);
443 if (!service_list || service_list->empty())
445 std::vector<std::string> active_services;
446 std::vector<std::string> inactive_services;
447 for (size_t i = 0; i < arraysize(ordered_types); ++i) {
448 AppendServicesForType(service_list, ordered_types[i],
449 &active_services, &inactive_services);
451 service_list->Clear();
452 for (size_t i = 0; i < active_services.size(); ++i)
453 service_list->AppendString(active_services[i]);
454 for (size_t i = 0; i < inactive_services.size(); ++i)
455 service_list->AppendString(inactive_services[i]);
457 CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
460 void FakeShillManagerClient::AddGeoNetwork(
461 const std::string& technology,
462 const base::DictionaryValue& network) {
463 base::ListValue* list_value = NULL;
464 if (!stub_geo_networks_.GetListWithoutPathExpansion(
465 technology, &list_value)) {
466 list_value = new base::ListValue;
467 stub_geo_networks_.SetWithoutPathExpansion(technology, list_value);
469 list_value->Append(network.DeepCopy());
472 void FakeShillManagerClient::AddProfile(const std::string& profile_path) {
473 const char* key = shill::kProfilesProperty;
474 if (GetListProperty(key)->AppendIfNotPresent(
475 new base::StringValue(profile_path))) {
476 CallNotifyObserversPropertyChanged(key, 0);
480 void FakeShillManagerClient::AddServiceToWatchList(
481 const std::string& service_path) {
482 // Remove and insert the service, moving it to the front of the watch list.
483 GetListProperty(shill::kServiceWatchListProperty)->Remove(
484 base::StringValue(service_path), NULL);
485 GetListProperty(shill::kServiceWatchListProperty)->Insert(
486 0, base::Value::CreateStringValue(service_path));
487 CallNotifyObserversPropertyChanged(
488 shill::kServiceWatchListProperty, 0);
491 void FakeShillManagerClient::PassStubProperties(
492 const DictionaryValueCallback& callback) const {
493 scoped_ptr<base::DictionaryValue> stub_properties(
494 stub_properties_.DeepCopy());
495 // Remove disabled services from the list.
496 stub_properties->SetWithoutPathExpansion(
497 shill::kServicesProperty,
498 GetEnabledServiceList(shill::kServicesProperty));
499 stub_properties->SetWithoutPathExpansion(
500 shill::kServiceWatchListProperty,
501 GetEnabledServiceList(shill::kServiceWatchListProperty));
502 callback.Run(DBUS_METHOD_CALL_SUCCESS, *stub_properties);
505 void FakeShillManagerClient::PassStubGeoNetworks(
506 const DictionaryValueCallback& callback) const {
507 callback.Run(DBUS_METHOD_CALL_SUCCESS, stub_geo_networks_);
510 void FakeShillManagerClient::CallNotifyObserversPropertyChanged(
511 const std::string& property,
513 // Avoid unnecessary delayed task if we have no observers (e.g. during
515 if (!observer_list_.might_have_observers())
517 if (!CommandLine::ForCurrentProcess()->HasSwitch(
518 chromeos::switches::kEnableStubInteractive)) {
521 base::MessageLoop::current()->PostDelayedTask(
523 base::Bind(&FakeShillManagerClient::NotifyObserversPropertyChanged,
524 weak_ptr_factory_.GetWeakPtr(),
526 base::TimeDelta::FromMilliseconds(delay_ms));
529 void FakeShillManagerClient::NotifyObserversPropertyChanged(
530 const std::string& property) {
531 if (property == shill::kServicesProperty ||
532 property == shill::kServiceWatchListProperty) {
533 scoped_ptr<base::ListValue> services(GetEnabledServiceList(property));
534 FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
536 OnPropertyChanged(property, *(services.get())));
539 if (property == shill::kDevicesProperty) {
540 base::ListValue* devices = NULL;
541 if (stub_properties_.GetListWithoutPathExpansion(
542 shill::kDevicesProperty, &devices)) {
543 FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
545 OnPropertyChanged(property, *devices));
549 base::Value* value = NULL;
550 if (!stub_properties_.GetWithoutPathExpansion(property, &value)) {
551 LOG(ERROR) << "Notify for unknown property: " << property;
554 FOR_EACH_OBSERVER(ShillPropertyChangedObserver,
556 OnPropertyChanged(property, *value));
559 base::ListValue* FakeShillManagerClient::GetListProperty(
560 const std::string& property) {
561 base::ListValue* list_property = NULL;
562 if (!stub_properties_.GetListWithoutPathExpansion(
563 property, &list_property)) {
564 list_property = new base::ListValue;
565 stub_properties_.SetWithoutPathExpansion(property, list_property);
567 return list_property;
570 bool FakeShillManagerClient::TechnologyEnabled(const std::string& type) const {
571 if (type == shill::kTypeVPN)
572 return true; // VPN is always "enabled" since there is no associated device
573 bool enabled = false;
574 const base::ListValue* technologies;
575 if (stub_properties_.GetListWithoutPathExpansion(
576 shill::kEnabledTechnologiesProperty, &technologies)) {
577 base::StringValue type_value(type);
578 if (technologies->Find(type_value) != technologies->end())
584 void FakeShillManagerClient::SetTechnologyEnabled(
585 const std::string& type,
586 const base::Closure& callback,
588 base::ListValue* enabled_list = NULL;
589 stub_properties_.GetListWithoutPathExpansion(
590 shill::kEnabledTechnologiesProperty, &enabled_list);
591 DCHECK(enabled_list);
593 enabled_list->AppendIfNotPresent(new base::StringValue(type));
595 enabled_list->Remove(base::StringValue(type), NULL);
596 CallNotifyObserversPropertyChanged(
597 shill::kEnabledTechnologiesProperty, 0 /* already delayed */);
598 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
599 // May affect available services
600 CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
601 CallNotifyObserversPropertyChanged(shill::kServiceWatchListProperty, 0);
604 base::ListValue* FakeShillManagerClient::GetEnabledServiceList(
605 const std::string& property) const {
606 base::ListValue* new_service_list = new base::ListValue;
607 const base::ListValue* service_list;
608 if (stub_properties_.GetListWithoutPathExpansion(property, &service_list)) {
609 ShillServiceClient::TestInterface* service_client =
610 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
611 for (base::ListValue::const_iterator iter = service_list->begin();
612 iter != service_list->end(); ++iter) {
613 std::string service_path;
614 if (!(*iter)->GetAsString(&service_path))
616 const base::DictionaryValue* properties =
617 service_client->GetServiceProperties(service_path);
619 LOG(ERROR) << "Properties not found for service: " << service_path;
623 properties->GetString(shill::kNameProperty, &name);
625 properties->GetString(shill::kTypeProperty, &type);
626 if (TechnologyEnabled(type))
627 new_service_list->Append((*iter)->DeepCopy());
630 return new_service_list;
633 void FakeShillManagerClient::ScanCompleted(const std::string& device_path,
634 const base::Closure& callback) {
635 if (!device_path.empty()) {
636 DBusThreadManager::Get()->GetShillDeviceClient()->GetTestInterface()->
637 SetDeviceProperty(device_path,
638 shill::kScanningProperty,
639 base::FundamentalValue(false));
641 CallNotifyObserversPropertyChanged(shill::kServicesProperty, 0);
642 CallNotifyObserversPropertyChanged(shill::kServiceWatchListProperty, 0);
643 base::MessageLoop::current()->PostTask(FROM_HERE, callback);
646 } // namespace chromeos