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_service_client_stub.h"
8 #include "base/command_line.h"
9 #include "base/message_loop.h"
10 #include "base/stl_util.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_manager_client.h"
15 #include "chromeos/dbus/shill_property_changed_observer.h"
17 #include "dbus/message.h"
18 #include "dbus/object_proxy.h"
19 #include "third_party/cros_system_api/dbus/service_constants.h"
25 void ErrorFunction(const std::string
& error_name
,
26 const std::string
& error_message
) {
27 LOG(ERROR
) << "Shill Error: " << error_name
<< " : " << error_message
;
30 void PassStubListValue(const ShillServiceClient::ListValueCallback
& callback
,
31 base::ListValue
* value
) {
35 void PassStubServiceProperties(
36 const ShillServiceClient::DictionaryValueCallback
& callback
,
37 DBusMethodCallStatus call_status
,
38 const base::DictionaryValue
* properties
) {
39 callback
.Run(call_status
, *properties
);
44 ShillServiceClientStub::ShillServiceClientStub() : weak_ptr_factory_(this) {
45 SetDefaultProperties();
48 ShillServiceClientStub::~ShillServiceClientStub() {
49 STLDeleteContainerPairSecondPointers(
50 observer_list_
.begin(), observer_list_
.end());
53 // ShillServiceClient overrides.
55 void ShillServiceClientStub::AddPropertyChangedObserver(
56 const dbus::ObjectPath
& service_path
,
57 ShillPropertyChangedObserver
* observer
) {
58 GetObserverList(service_path
).AddObserver(observer
);
61 void ShillServiceClientStub::RemovePropertyChangedObserver(
62 const dbus::ObjectPath
& service_path
,
63 ShillPropertyChangedObserver
* observer
) {
64 GetObserverList(service_path
).RemoveObserver(observer
);
67 void ShillServiceClientStub::GetProperties(
68 const dbus::ObjectPath
& service_path
,
69 const DictionaryValueCallback
& callback
) {
70 if (callback
.is_null())
73 base::DictionaryValue
* nested_dict
= NULL
;
74 scoped_ptr
<base::DictionaryValue
> result_properties
;
75 DBusMethodCallStatus call_status
;
76 stub_services_
.GetDictionaryWithoutPathExpansion(service_path
.value(),
79 result_properties
.reset(nested_dict
->DeepCopy());
80 // Remove credentials that Shill wouldn't send.
81 result_properties
->RemoveWithoutPathExpansion(flimflam::kPassphraseProperty
,
83 call_status
= DBUS_METHOD_CALL_SUCCESS
;
85 result_properties
.reset(new base::DictionaryValue
);
86 call_status
= DBUS_METHOD_CALL_FAILURE
;
89 base::MessageLoop::current()->PostTask(
91 base::Bind(&PassStubServiceProperties
,
94 base::Owned(result_properties
.release())));
97 void ShillServiceClientStub::SetProperty(const dbus::ObjectPath
& service_path
,
98 const std::string
& name
,
99 const base::Value
& value
,
100 const base::Closure
& callback
,
101 const ErrorCallback
& error_callback
) {
102 base::DictionaryValue
* dict
= NULL
;
103 if (!stub_services_
.GetDictionaryWithoutPathExpansion(
104 service_path
.value(), &dict
)) {
105 LOG(ERROR
) << "Service not found: " << service_path
.value();
106 error_callback
.Run("Error.InvalidService", "Invalid Service");
109 VLOG(1) << "Service.SetProperty: " << name
<< " = " << value
110 << " For: " << service_path
.value();
111 if (name
== flimflam::kStateProperty
) {
112 // If the service went into a connected state, then move it to the top of
113 // the list in the manager client.
114 // TODO(gauravsh): Generalize to sort services properly to allow for testing
115 // more complex scenarios.
117 if (value
.GetAsString(&state
) && (state
== flimflam::kStateOnline
||
118 state
== flimflam::kStatePortal
)) {
119 ShillManagerClient
* manager_client
=
120 DBusThreadManager::Get()->GetShillManagerClient();
121 manager_client
->GetTestInterface()->MoveServiceToIndex(
122 service_path
.value(), 0, true);
125 dict
->SetWithoutPathExpansion(name
, value
.DeepCopy());
126 base::MessageLoop::current()->PostTask(
128 base::Bind(&ShillServiceClientStub::NotifyObserversPropertyChanged
,
129 weak_ptr_factory_
.GetWeakPtr(), service_path
, name
));
130 if (callback
.is_null())
132 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
135 void ShillServiceClientStub::ClearProperty(
136 const dbus::ObjectPath
& service_path
,
137 const std::string
& name
,
138 const base::Closure
& callback
,
139 const ErrorCallback
& error_callback
) {
140 base::DictionaryValue
* dict
= NULL
;
141 if (!stub_services_
.GetDictionaryWithoutPathExpansion(
142 service_path
.value(), &dict
)) {
143 error_callback
.Run("Error.InvalidService", "Invalid Service");
146 dict
->Remove(name
, NULL
);
147 base::MessageLoop::current()->PostTask(
149 base::Bind(&ShillServiceClientStub::NotifyObserversPropertyChanged
,
150 weak_ptr_factory_
.GetWeakPtr(), service_path
, name
));
151 if (callback
.is_null())
153 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
156 void ShillServiceClientStub::ClearProperties(
157 const dbus::ObjectPath
& service_path
,
158 const std::vector
<std::string
>& names
,
159 const ListValueCallback
& callback
,
160 const ErrorCallback
& error_callback
) {
161 base::DictionaryValue
* dict
= NULL
;
162 if (!stub_services_
.GetDictionaryWithoutPathExpansion(
163 service_path
.value(), &dict
)) {
164 error_callback
.Run("Error.InvalidService", "Invalid Service");
167 scoped_ptr
<base::ListValue
> results(new base::ListValue
);
168 for (std::vector
<std::string
>::const_iterator iter
= names
.begin();
169 iter
!= names
.end(); ++iter
) {
170 dict
->Remove(*iter
, NULL
);
171 results
->AppendBoolean(true);
173 for (std::vector
<std::string
>::const_iterator iter
= names
.begin();
174 iter
!= names
.end(); ++iter
) {
175 base::MessageLoop::current()->PostTask(
178 &ShillServiceClientStub::NotifyObserversPropertyChanged
,
179 weak_ptr_factory_
.GetWeakPtr(), service_path
, *iter
));
181 if (callback
.is_null())
183 base::MessageLoop::current()->PostTask(
185 base::Bind(&PassStubListValue
,
186 callback
, base::Owned(results
.release())));
189 void ShillServiceClientStub::Connect(const dbus::ObjectPath
& service_path
,
190 const base::Closure
& callback
,
191 const ErrorCallback
& error_callback
) {
192 VLOG(1) << "ShillServiceClientStub::Connect: " << service_path
.value();
193 base::Value
* service
;
194 if (!stub_services_
.Get(service_path
.value(), &service
)) {
195 LOG(ERROR
) << "Service not found: " << service_path
.value();
196 error_callback
.Run("Error.InvalidService", "Invalid Service");
199 base::TimeDelta delay
;
201 base::StringValue
associating_value(flimflam::kStateAssociation
);
202 SetServiceProperty(service_path
.value(),
203 flimflam::kStateProperty
,
205 if (CommandLine::ForCurrentProcess()->HasSwitch(
206 chromeos::switches::kEnableStubInteractive
)) {
207 const int kConnectDelaySeconds
= 5;
208 delay
= base::TimeDelta::FromSeconds(kConnectDelaySeconds
);
210 // Set Online after a delay
211 base::StringValue
online_value(flimflam::kStateOnline
);
212 base::MessageLoop::current()->PostDelayedTask(
214 base::Bind(&ShillServiceClientStub::SetProperty
,
215 weak_ptr_factory_
.GetWeakPtr(),
217 flimflam::kStateProperty
,
219 base::Bind(&base::DoNothing
),
225 void ShillServiceClientStub::Disconnect(const dbus::ObjectPath
& service_path
,
226 const base::Closure
& callback
,
227 const ErrorCallback
& error_callback
) {
228 base::Value
* service
;
229 if (!stub_services_
.Get(service_path
.value(), &service
)) {
230 error_callback
.Run("Error.InvalidService", "Invalid Service");
233 base::TimeDelta delay
;
234 if (CommandLine::ForCurrentProcess()->HasSwitch(
235 chromeos::switches::kEnableStubInteractive
)) {
236 const int kConnectDelaySeconds
= 2;
237 delay
= base::TimeDelta::FromSeconds(kConnectDelaySeconds
);
239 // Set Idle after a delay
240 base::StringValue
idle_value(flimflam::kStateIdle
);
241 base::MessageLoop::current()->PostDelayedTask(
243 base::Bind(&ShillServiceClientStub::SetProperty
,
244 weak_ptr_factory_
.GetWeakPtr(),
246 flimflam::kStateProperty
,
248 base::Bind(&base::DoNothing
),
254 void ShillServiceClientStub::Remove(const dbus::ObjectPath
& service_path
,
255 const base::Closure
& callback
,
256 const ErrorCallback
& error_callback
) {
257 if (callback
.is_null())
259 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
262 void ShillServiceClientStub::ActivateCellularModem(
263 const dbus::ObjectPath
& service_path
,
264 const std::string
& carrier
,
265 const base::Closure
& callback
,
266 const ErrorCallback
& error_callback
) {
267 if (callback
.is_null())
269 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
272 void ShillServiceClientStub::CompleteCellularActivation(
273 const dbus::ObjectPath
& service_path
,
274 const base::Closure
& callback
,
275 const ErrorCallback
& error_callback
) {
276 if (callback
.is_null())
278 base::MessageLoop::current()->PostTask(FROM_HERE
, callback
);
281 bool ShillServiceClientStub::CallActivateCellularModemAndBlock(
282 const dbus::ObjectPath
& service_path
,
283 const std::string
& carrier
) {
287 ShillServiceClient::TestInterface
* ShillServiceClientStub::GetTestInterface() {
291 // ShillServiceClient::TestInterface overrides.
293 void ShillServiceClientStub::AddService(const std::string
& service_path
,
294 const std::string
& name
,
295 const std::string
& type
,
296 const std::string
& state
,
297 bool add_to_watch_list
) {
298 AddServiceWithIPConfig(service_path
, name
, type
, state
, "",
302 void ShillServiceClientStub::AddServiceWithIPConfig(
303 const std::string
& service_path
,
304 const std::string
& name
,
305 const std::string
& type
,
306 const std::string
& state
,
307 const std::string
& ipconfig_path
,
308 bool add_to_watch_list
) {
309 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
310 AddManagerService(service_path
, add_to_watch_list
);
312 base::DictionaryValue
* properties
=
313 GetModifiableServiceProperties(service_path
);
314 properties
->SetWithoutPathExpansion(
315 flimflam::kSSIDProperty
,
316 base::Value::CreateStringValue(service_path
));
317 properties
->SetWithoutPathExpansion(
318 flimflam::kNameProperty
,
319 base::Value::CreateStringValue(name
));
320 properties
->SetWithoutPathExpansion(
321 flimflam::kTypeProperty
,
322 base::Value::CreateStringValue(type
));
323 properties
->SetWithoutPathExpansion(
324 flimflam::kStateProperty
,
325 base::Value::CreateStringValue(state
));
326 if (!ipconfig_path
.empty())
327 properties
->SetWithoutPathExpansion(
328 shill::kIPConfigProperty
,
329 base::Value::CreateStringValue(ipconfig_path
));
332 void ShillServiceClientStub::RemoveService(const std::string
& service_path
) {
333 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
334 RemoveManagerService(service_path
);
336 stub_services_
.RemoveWithoutPathExpansion(service_path
, NULL
);
339 void ShillServiceClientStub::SetServiceProperty(const std::string
& service_path
,
340 const std::string
& property
,
341 const base::Value
& value
) {
342 SetProperty(dbus::ObjectPath(service_path
), property
, value
,
343 base::Bind(&base::DoNothing
),
344 base::Bind(&ErrorFunction
));
347 const base::DictionaryValue
* ShillServiceClientStub::GetServiceProperties(
348 const std::string
& service_path
) const {
349 const base::DictionaryValue
* properties
= NULL
;
350 stub_services_
.GetDictionaryWithoutPathExpansion(service_path
, &properties
);
354 void ShillServiceClientStub::ClearServices() {
355 DBusThreadManager::Get()->GetShillManagerClient()->GetTestInterface()->
356 ClearManagerServices();
358 stub_services_
.Clear();
361 void ShillServiceClientStub::SetDefaultProperties() {
362 const bool add_to_watchlist
= true;
364 if (!CommandLine::ForCurrentProcess()->HasSwitch(
365 chromeos::switches::kDisableStubEthernet
)) {
366 AddService("eth1", "eth1",
367 flimflam::kTypeEthernet
,
368 flimflam::kStateOnline
,
372 AddService("wifi1", "wifi1",
374 flimflam::kStateOnline
,
376 SetServiceProperty("wifi1",
377 flimflam::kSecurityProperty
,
378 base::StringValue(flimflam::kSecurityWep
));
380 AddService("wifi2", "wifi2_PSK",
382 flimflam::kStateIdle
,
384 SetServiceProperty("wifi2",
385 flimflam::kSecurityProperty
,
386 base::StringValue(flimflam::kSecurityPsk
));
387 base::FundamentalValue
strength_value(80);
388 SetServiceProperty("wifi2",
389 flimflam::kSignalStrengthProperty
,
392 AddService("cellular1", "cellular1",
393 flimflam::kTypeCellular
,
394 flimflam::kStateIdle
,
396 base::StringValue
technology_value(flimflam::kNetworkTechnologyGsm
);
397 SetServiceProperty("cellular1",
398 flimflam::kNetworkTechnologyProperty
,
400 SetServiceProperty("cellular1",
401 flimflam::kActivationStateProperty
,
402 base::StringValue(flimflam::kActivationStateNotActivated
));
403 SetServiceProperty("cellular1",
404 flimflam::kRoamingStateProperty
,
405 base::StringValue(flimflam::kRoamingStateHome
));
407 AddService("vpn1", "vpn1",
409 flimflam::kStateOnline
,
412 AddService("vpn2", "vpn2",
414 flimflam::kStateOffline
,
418 void ShillServiceClientStub::NotifyObserversPropertyChanged(
419 const dbus::ObjectPath
& service_path
,
420 const std::string
& property
) {
421 base::DictionaryValue
* dict
= NULL
;
422 std::string path
= service_path
.value();
423 if (!stub_services_
.GetDictionaryWithoutPathExpansion(path
, &dict
)) {
424 LOG(ERROR
) << "Notify for unknown service: " << path
;
427 base::Value
* value
= NULL
;
428 if (!dict
->GetWithoutPathExpansion(property
, &value
)) {
429 LOG(ERROR
) << "Notify for unknown property: "
430 << path
<< " : " << property
;
433 FOR_EACH_OBSERVER(ShillPropertyChangedObserver
,
434 GetObserverList(service_path
),
435 OnPropertyChanged(property
, *value
));
438 base::DictionaryValue
* ShillServiceClientStub::GetModifiableServiceProperties(
439 const std::string
& service_path
) {
440 base::DictionaryValue
* properties
= NULL
;
441 if (!stub_services_
.GetDictionaryWithoutPathExpansion(
442 service_path
, &properties
)) {
443 properties
= new base::DictionaryValue
;
444 stub_services_
.Set(service_path
, properties
);
449 ShillServiceClientStub::PropertyObserverList
&
450 ShillServiceClientStub::GetObserverList(const dbus::ObjectPath
& device_path
) {
451 std::map
<dbus::ObjectPath
, PropertyObserverList
*>::iterator iter
=
452 observer_list_
.find(device_path
);
453 if (iter
!= observer_list_
.end())
454 return *(iter
->second
);
455 PropertyObserverList
* observer_list
= new PropertyObserverList();
456 observer_list_
[device_path
] = observer_list
;
457 return *observer_list
;
460 } // namespace chromeos