1 // Copyright (c) 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/shill_manager_client_stub.h"
8 #include "base/chromeos/chromeos_version.h"
9 #include "base/command_line.h"
10 #include "base/message_loop.h"
11 #include "base/values.h"
12 #include "chromeos/chromeos_switches.h"
13 #include "chromeos/dbus/dbus_thread_manager.h"
14 #include "chromeos/dbus/shill_property_changed_observer.h"
15 #include "chromeos/dbus/shill_service_client.h"
17 #include "dbus/message.h"
18 #include "dbus/object_path.h"
19 #include "dbus/object_proxy.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 Value
* first
) : first_(first
) {}
31 bool operator()(const Value
* second
) const {
32 return first_
->Equals(second
);
39 ShillManagerClientStub::ShillManagerClientStub()
40 : weak_ptr_factory_(this) {
41 SetDefaultProperties();
44 ShillManagerClientStub::~ShillManagerClientStub() {}
46 // ShillManagerClient overrides.
48 void ShillManagerClientStub::AddPropertyChangedObserver(
49 ShillPropertyChangedObserver
* observer
) {
50 observer_list_
.AddObserver(observer
);
53 void ShillManagerClientStub::RemovePropertyChangedObserver(
54 ShillPropertyChangedObserver
* observer
) {
55 observer_list_
.RemoveObserver(observer
);
58 void ShillManagerClientStub::GetProperties(
59 const DictionaryValueCallback
& callback
) {
60 if (callback
.is_null())
62 MessageLoop::current()->PostTask(
63 FROM_HERE
, base::Bind(
64 &ShillManagerClientStub::PassStubProperties
,
65 weak_ptr_factory_
.GetWeakPtr(),
69 base::DictionaryValue
* ShillManagerClientStub::CallGetPropertiesAndBlock() {
70 return stub_properties_
.DeepCopy();
73 void ShillManagerClientStub::GetNetworksForGeolocation(
74 const DictionaryValueCallback
& callback
) {
75 if (callback
.is_null())
77 MessageLoop::current()->PostTask(
78 FROM_HERE
, base::Bind(
79 &ShillManagerClientStub::PassStubGeoNetworks
,
80 weak_ptr_factory_
.GetWeakPtr(),
84 void ShillManagerClientStub::SetProperty(const std::string
& name
,
85 const base::Value
& value
,
86 const base::Closure
& callback
,
87 const ErrorCallback
& error_callback
) {
88 stub_properties_
.SetWithoutPathExpansion(name
, value
.DeepCopy());
89 if (callback
.is_null())
91 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
94 void ShillManagerClientStub::RequestScan(const std::string
& type
,
95 const base::Closure
& callback
,
96 const ErrorCallback
& error_callback
) {
97 const int kScanDelayMilliseconds
= 3000;
98 CallNotifyObserversPropertyChanged(
99 flimflam::kServicesProperty
, kScanDelayMilliseconds
);
100 if (callback
.is_null())
102 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
105 void ShillManagerClientStub::EnableTechnology(
106 const std::string
& type
,
107 const base::Closure
& callback
,
108 const ErrorCallback
& error_callback
) {
109 base::ListValue
* enabled_list
= NULL
;
110 if (!stub_properties_
.GetListWithoutPathExpansion(
111 flimflam::kEnabledTechnologiesProperty
, &enabled_list
)) {
112 if (!error_callback
.is_null()) {
113 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
114 MessageLoop::current()->PostTask(
116 base::Bind(error_callback
, "StubError", "Property not found"));
120 enabled_list
->AppendIfNotPresent(new base::StringValue(type
));
121 CallNotifyObserversPropertyChanged(
122 flimflam::kEnabledTechnologiesProperty
, 0);
123 if (!callback
.is_null())
124 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
125 // May affect available services
126 CallNotifyObserversPropertyChanged(flimflam::kServicesProperty
, 0);
127 CallNotifyObserversPropertyChanged(flimflam::kServiceWatchListProperty
, 0);
130 void ShillManagerClientStub::DisableTechnology(
131 const std::string
& type
,
132 const base::Closure
& callback
,
133 const ErrorCallback
& error_callback
) {
134 base::ListValue
* enabled_list
= NULL
;
135 if (!stub_properties_
.GetListWithoutPathExpansion(
136 flimflam::kEnabledTechnologiesProperty
, &enabled_list
)) {
137 if (!error_callback
.is_null()) {
138 MessageLoop::current()->PostTask(
140 base::Bind(error_callback
, "StubError", "Property not found"));
144 base::StringValue
type_value(type
);
145 enabled_list
->Remove(type_value
, NULL
);
146 CallNotifyObserversPropertyChanged(
147 flimflam::kEnabledTechnologiesProperty
, 0);
148 if (!callback
.is_null())
149 MessageLoop::current()->PostTask(FROM_HERE
, callback
);
150 // May affect available services
151 CallNotifyObserversPropertyChanged(flimflam::kServicesProperty
, 0);
152 CallNotifyObserversPropertyChanged(flimflam::kServiceWatchListProperty
, 0);
155 void ShillManagerClientStub::ConfigureService(
156 const base::DictionaryValue
& properties
,
157 const ObjectPathCallback
& callback
,
158 const ErrorCallback
& error_callback
) {
159 if (callback
.is_null())
162 // For the purposes of this stub, we're going to assume that the GUID property
163 // is set to the service path because we don't want to re-implement Shill's
164 // property matching magic here.
165 ShillServiceClient::TestInterface
* service_client
=
166 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
170 if (!properties
.GetString(flimflam::kGuidProperty
, &guid
) ||
171 !properties
.GetString(flimflam::kTypeProperty
, &type
)) {
172 // If the properties aren't filled out completely, then just return an empty
174 MessageLoop::current()->PostTask(
175 FROM_HERE
, base::Bind(callback
, dbus::ObjectPath()));
179 std::string ipconfig_path
;
180 properties
.GetString(shill::kIPConfigProperty
, &ipconfig_path
);
182 // Add the service to the service client stub if not already there.
183 service_client
->AddServiceWithIPConfig(guid
, guid
, type
, flimflam::kStateIdle
,
184 ipconfig_path
, true);
186 // Merge the new properties with existing properties, if any.
187 scoped_ptr
<base::DictionaryValue
> merged_properties
;
188 const base::DictionaryValue
* existing_properties
=
189 service_client
->GetServiceProperties(guid
);
190 if (existing_properties
) {
191 merged_properties
.reset(existing_properties
->DeepCopy());
193 merged_properties
.reset(new base::DictionaryValue
);
195 merged_properties
->MergeDictionary(&properties
);
197 // Now set all the properties.
198 for (base::DictionaryValue::Iterator
iter(*merged_properties
);
199 !iter
.IsAtEnd(); iter
.Advance()) {
200 service_client
->SetServiceProperty(guid
, iter
.key(), iter
.value());
203 MessageLoop::current()->PostTask(
204 FROM_HERE
, base::Bind(callback
, dbus::ObjectPath(guid
)));
207 void ShillManagerClientStub::GetService(
208 const base::DictionaryValue
& properties
,
209 const ObjectPathCallback
& callback
,
210 const ErrorCallback
& error_callback
) {
211 if (callback
.is_null())
213 MessageLoop::current()->PostTask(
214 FROM_HERE
, base::Bind(callback
, dbus::ObjectPath()));
217 void ShillManagerClientStub::VerifyDestination(
218 const std::string
& certificate
,
219 const std::string
& public_key
,
220 const std::string
& nonce
,
221 const std::string
& signed_data
,
222 const std::string
& device_serial
,
223 const BooleanCallback
& callback
,
224 const ErrorCallback
& error_callback
) {
225 if (callback
.is_null())
227 MessageLoop::current()->PostTask(
228 FROM_HERE
, base::Bind(callback
, true));
231 void ShillManagerClientStub::VerifyAndEncryptCredentials(
232 const std::string
& certificate
,
233 const std::string
& public_key
,
234 const std::string
& nonce
,
235 const std::string
& signed_data
,
236 const std::string
& device_serial
,
237 const std::string
& service_path
,
238 const StringCallback
& callback
,
239 const ErrorCallback
& error_callback
) {
240 if (callback
.is_null())
242 MessageLoop::current()->PostTask(
243 FROM_HERE
, base::Bind(callback
, "encrypted_credentials"));
246 void ShillManagerClientStub::VerifyAndEncryptData(
247 const std::string
& certificate
,
248 const std::string
& public_key
,
249 const std::string
& nonce
,
250 const std::string
& signed_data
,
251 const std::string
& device_serial
,
252 const std::string
& data
,
253 const StringCallback
& callback
,
254 const ErrorCallback
& error_callback
) {
255 if (callback
.is_null())
257 MessageLoop::current()->PostTask(
258 FROM_HERE
, base::Bind(callback
, "encrypted_data"));
261 void ShillManagerClientStub::ConnectToBestServices(
262 const base::Closure
& callback
,
263 const ErrorCallback
& error_callback
) {
266 ShillManagerClient::TestInterface
* ShillManagerClientStub::GetTestInterface() {
270 // ShillManagerClient::TestInterface overrides.
272 void ShillManagerClientStub::AddDevice(const std::string
& device_path
) {
273 if (GetListProperty(flimflam::kDevicesProperty
)->AppendIfNotPresent(
274 base::Value::CreateStringValue(device_path
))) {
275 CallNotifyObserversPropertyChanged(flimflam::kDevicesProperty
, 0);
279 void ShillManagerClientStub::RemoveDevice(const std::string
& device_path
) {
280 base::StringValue
device_path_value(device_path
);
281 if (GetListProperty(flimflam::kDevicesProperty
)->Remove(
282 device_path_value
, NULL
)) {
283 CallNotifyObserversPropertyChanged(flimflam::kDevicesProperty
, 0);
287 void ShillManagerClientStub::ClearDevices() {
288 stub_properties_
.Remove(flimflam::kDevicesProperty
, NULL
);
291 void ShillManagerClientStub::ClearServices() {
292 stub_properties_
.Remove(flimflam::kServicesProperty
, NULL
);
293 stub_properties_
.Remove(flimflam::kServiceWatchListProperty
, NULL
);
296 void ShillManagerClientStub::AddService(const std::string
& service_path
,
297 bool add_to_watch_list
) {
298 if (GetListProperty(flimflam::kServicesProperty
)->AppendIfNotPresent(
299 base::Value::CreateStringValue(service_path
))) {
300 CallNotifyObserversPropertyChanged(flimflam::kServicesProperty
, 0);
302 if (add_to_watch_list
)
303 AddServiceToWatchList(service_path
);
306 void ShillManagerClientStub::AddServiceAtIndex(const std::string
& service_path
,
308 bool add_to_watch_list
) {
309 base::StringValue
path_value(service_path
);
310 base::ListValue
* service_list
=
311 GetListProperty(flimflam::kServicesProperty
);
312 base::ListValue::iterator iter
=
313 std::find_if(service_list
->begin(), service_list
->end(),
314 ValueEquals(&path_value
));
315 service_list
->Find(path_value
);
316 if (iter
!= service_list
->end())
317 service_list
->Erase(iter
, NULL
);
318 service_list
->Insert(index
, path_value
.DeepCopy());
319 CallNotifyObserversPropertyChanged(flimflam::kServicesProperty
, 0);
320 if (add_to_watch_list
)
321 AddServiceToWatchList(service_path
);
324 void ShillManagerClientStub::RemoveService(const std::string
& service_path
) {
325 base::StringValue
service_path_value(service_path
);
326 if (GetListProperty(flimflam::kServicesProperty
)->Remove(
327 service_path_value
, NULL
)) {
328 CallNotifyObserversPropertyChanged(flimflam::kServicesProperty
, 0);
330 if (GetListProperty(flimflam::kServiceWatchListProperty
)->Remove(
331 service_path_value
, NULL
)) {
332 CallNotifyObserversPropertyChanged(
333 flimflam::kServiceWatchListProperty
, 0);
337 void ShillManagerClientStub::AddTechnology(const std::string
& type
,
339 if (GetListProperty(flimflam::kAvailableTechnologiesProperty
)->
340 AppendIfNotPresent(base::Value::CreateStringValue(type
))) {
341 CallNotifyObserversPropertyChanged(
342 flimflam::kAvailableTechnologiesProperty
, 0);
345 GetListProperty(flimflam::kEnabledTechnologiesProperty
)->
346 AppendIfNotPresent(base::Value::CreateStringValue(type
))) {
347 CallNotifyObserversPropertyChanged(
348 flimflam::kEnabledTechnologiesProperty
, 0);
352 void ShillManagerClientStub::RemoveTechnology(const std::string
& type
) {
353 base::StringValue
type_value(type
);
354 if (GetListProperty(flimflam::kAvailableTechnologiesProperty
)->Remove(
356 CallNotifyObserversPropertyChanged(
357 flimflam::kAvailableTechnologiesProperty
, 0);
359 if (GetListProperty(flimflam::kEnabledTechnologiesProperty
)->Remove(
361 CallNotifyObserversPropertyChanged(
362 flimflam::kEnabledTechnologiesProperty
, 0);
366 void ShillManagerClientStub::ClearProperties() {
367 stub_properties_
.Clear();
370 void ShillManagerClientStub::AddGeoNetwork(
371 const std::string
& technology
,
372 const base::DictionaryValue
& network
) {
373 base::ListValue
* list_value
= NULL
;
374 if (!stub_geo_networks_
.GetListWithoutPathExpansion(
375 technology
, &list_value
)) {
376 list_value
= new base::ListValue
;
377 stub_geo_networks_
.SetWithoutPathExpansion(technology
, list_value
);
379 list_value
->Append(network
.DeepCopy());
382 void ShillManagerClientStub::AddServiceToWatchList(
383 const std::string
& service_path
) {
385 flimflam::kServiceWatchListProperty
)->AppendIfNotPresent(
386 base::Value::CreateStringValue(service_path
))) {
387 CallNotifyObserversPropertyChanged(
388 flimflam::kServiceWatchListProperty
, 0);
392 void ShillManagerClientStub::SetDefaultProperties() {
393 // Stub Technologies.
394 if (!CommandLine::ForCurrentProcess()->HasSwitch(
395 chromeos::switches::kDisableStubEthernet
)) {
396 AddTechnology(flimflam::kTypeEthernet
, true);
398 AddTechnology(flimflam::kTypeWifi
, true);
399 AddTechnology(flimflam::kTypeCellular
, true);
402 void ShillManagerClientStub::PassStubProperties(
403 const DictionaryValueCallback
& callback
) const {
404 scoped_ptr
<base::DictionaryValue
> stub_properties(
405 stub_properties_
.DeepCopy());
406 // Remove disabled services from the list
407 stub_properties
->SetWithoutPathExpansion(
408 flimflam::kServicesProperty
,
409 GetEnabledServiceList(flimflam::kServicesProperty
));
410 stub_properties
->SetWithoutPathExpansion(
411 flimflam::kServiceWatchListProperty
,
412 GetEnabledServiceList(flimflam::kServiceWatchListProperty
));
413 callback
.Run(DBUS_METHOD_CALL_SUCCESS
, *stub_properties
);
416 void ShillManagerClientStub::PassStubGeoNetworks(
417 const DictionaryValueCallback
& callback
) const {
418 callback
.Run(DBUS_METHOD_CALL_SUCCESS
, stub_geo_networks_
);
421 void ShillManagerClientStub::CallNotifyObserversPropertyChanged(
422 const std::string
& property
,
424 // Avoid unnecessary delayed task if we have no observers (e.g. during
426 if (observer_list_
.size() == 0)
428 MessageLoop::current()->PostDelayedTask(
430 base::Bind(&ShillManagerClientStub::NotifyObserversPropertyChanged
,
431 weak_ptr_factory_
.GetWeakPtr(),
433 base::TimeDelta::FromMilliseconds(delay_ms
));
436 void ShillManagerClientStub::NotifyObserversPropertyChanged(
437 const std::string
& property
) {
438 if (property
== flimflam::kServicesProperty
||
439 property
== flimflam::kServiceWatchListProperty
) {
440 scoped_ptr
<base::ListValue
> services(GetEnabledServiceList(property
));
441 FOR_EACH_OBSERVER(ShillPropertyChangedObserver
,
443 OnPropertyChanged(property
, *(services
.get())));
446 base::Value
* value
= NULL
;
447 if (!stub_properties_
.GetWithoutPathExpansion(property
, &value
)) {
448 LOG(ERROR
) << "Notify for unknown property: " << property
;
451 FOR_EACH_OBSERVER(ShillPropertyChangedObserver
,
453 OnPropertyChanged(property
, *value
));
456 base::ListValue
* ShillManagerClientStub::GetListProperty(
457 const std::string
& property
) {
458 base::ListValue
* list_property
= NULL
;
459 if (!stub_properties_
.GetListWithoutPathExpansion(
460 property
, &list_property
)) {
461 list_property
= new base::ListValue
;
462 stub_properties_
.SetWithoutPathExpansion(property
, list_property
);
464 return list_property
;
467 bool ShillManagerClientStub::TechnologyEnabled(const std::string
& type
) const {
468 if (type
== flimflam::kTypeVPN
)
469 return true; // VPN is always "enabled" since there is no associated device
470 bool enabled
= false;
471 const base::ListValue
* technologies
;
472 if (stub_properties_
.GetListWithoutPathExpansion(
473 flimflam::kEnabledTechnologiesProperty
, &technologies
)) {
474 base::StringValue
type_value(type
);
475 if (technologies
->Find(type_value
) != technologies
->end())
481 base::ListValue
* ShillManagerClientStub::GetEnabledServiceList(
482 const std::string
& property
) const {
483 base::ListValue
* new_service_list
= new base::ListValue
;
484 const base::ListValue
* service_list
;
485 if (stub_properties_
.GetListWithoutPathExpansion(property
, &service_list
)) {
486 ShillServiceClient::TestInterface
* service_client
=
487 DBusThreadManager::Get()->GetShillServiceClient()->GetTestInterface();
488 for (base::ListValue::const_iterator iter
= service_list
->begin();
489 iter
!= service_list
->end(); ++iter
) {
490 std::string service_path
;
491 if (!(*iter
)->GetAsString(&service_path
))
493 const base::DictionaryValue
* properties
=
494 service_client
->GetServiceProperties(service_path
);
496 LOG(ERROR
) << "Properties not found for service: " << service_path
;
500 properties
->GetString(flimflam::kNameProperty
, &name
);
502 properties
->GetString(flimflam::kTypeProperty
, &type
);
503 if (TechnologyEnabled(type
))
504 new_service_list
->Append((*iter
)->DeepCopy());
507 return new_service_list
;
510 } // namespace chromeos