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/dbus/shill_client_helper.h"
8 #include "base/values.h"
9 #include "chromeos/dbus/blocking_method_caller.h"
10 #include "dbus/message.h"
11 #include "dbus/object_proxy.h"
12 #include "dbus/values_util.h"
13 #include "third_party/cros_system_api/dbus/service_constants.h"
19 const char kInvalidResponseErrorName
[] = ""; // No error name.
20 const char kInvalidResponseErrorMessage
[] = "Invalid response.";
22 void OnBooleanMethodWithErrorCallback(
23 const ShillClientHelper::BooleanCallback
& callback
,
24 const ShillClientHelper::ErrorCallback
& error_callback
,
25 dbus::Response
* response
) {
27 error_callback
.Run(kInvalidResponseErrorName
, kInvalidResponseErrorMessage
);
30 dbus::MessageReader
reader(response
);
32 if (!reader
.PopBool(&result
)) {
33 error_callback
.Run(kInvalidResponseErrorName
, kInvalidResponseErrorMessage
);
39 void OnStringMethodWithErrorCallback(
40 const ShillClientHelper::StringCallback
& callback
,
41 const ShillClientHelper::ErrorCallback
& error_callback
,
42 dbus::Response
* response
) {
44 error_callback
.Run(kInvalidResponseErrorName
, kInvalidResponseErrorMessage
);
47 dbus::MessageReader
reader(response
);
49 if (!reader
.PopString(&result
)) {
50 error_callback
.Run(kInvalidResponseErrorName
, kInvalidResponseErrorMessage
);
56 // Handles responses for methods without results.
57 void OnVoidMethod(const VoidDBusMethodCallback
& callback
,
58 dbus::Response
* response
) {
60 callback
.Run(DBUS_METHOD_CALL_FAILURE
);
63 callback
.Run(DBUS_METHOD_CALL_SUCCESS
);
66 // Handles responses for methods with ObjectPath results.
67 void OnObjectPathMethod(
68 const ObjectPathDBusMethodCallback
& callback
,
69 dbus::Response
* response
) {
71 callback
.Run(DBUS_METHOD_CALL_FAILURE
, dbus::ObjectPath());
74 dbus::MessageReader
reader(response
);
75 dbus::ObjectPath result
;
76 if (!reader
.PopObjectPath(&result
)) {
77 callback
.Run(DBUS_METHOD_CALL_FAILURE
, dbus::ObjectPath());
80 callback
.Run(DBUS_METHOD_CALL_SUCCESS
, result
);
83 // Handles responses for methods with ObjectPath results and no status.
84 void OnObjectPathMethodWithoutStatus(
85 const ObjectPathCallback
& callback
,
86 const ShillClientHelper::ErrorCallback
& error_callback
,
87 dbus::Response
* response
) {
89 error_callback
.Run(kInvalidResponseErrorName
, kInvalidResponseErrorMessage
);
92 dbus::MessageReader
reader(response
);
93 dbus::ObjectPath result
;
94 if (!reader
.PopObjectPath(&result
)) {
95 error_callback
.Run(kInvalidResponseErrorName
, kInvalidResponseErrorMessage
);
101 // Handles responses for methods with DictionaryValue results.
102 void OnDictionaryValueMethod(
103 const ShillClientHelper::DictionaryValueCallback
& callback
,
104 dbus::Response
* response
) {
106 base::DictionaryValue result
;
107 callback
.Run(DBUS_METHOD_CALL_FAILURE
, result
);
110 dbus::MessageReader
reader(response
);
111 scoped_ptr
<base::Value
> value(dbus::PopDataAsValue(&reader
));
112 base::DictionaryValue
* result
= NULL
;
113 if (!value
.get() || !value
->GetAsDictionary(&result
)) {
114 base::DictionaryValue result
;
115 callback
.Run(DBUS_METHOD_CALL_FAILURE
, result
);
118 callback
.Run(DBUS_METHOD_CALL_SUCCESS
, *result
);
121 // Handles responses for methods without results.
122 void OnVoidMethodWithErrorCallback(
123 const base::Closure
& callback
,
124 dbus::Response
* response
) {
128 // Handles responses for methods with DictionaryValue results.
129 // Used by CallDictionaryValueMethodWithErrorCallback().
130 void OnDictionaryValueMethodWithErrorCallback(
131 const ShillClientHelper::DictionaryValueCallbackWithoutStatus
& callback
,
132 const ShillClientHelper::ErrorCallback
& error_callback
,
133 dbus::Response
* response
) {
134 dbus::MessageReader
reader(response
);
135 scoped_ptr
<base::Value
> value(dbus::PopDataAsValue(&reader
));
136 base::DictionaryValue
* result
= NULL
;
137 if (!value
.get() || !value
->GetAsDictionary(&result
)) {
138 error_callback
.Run(kInvalidResponseErrorName
, kInvalidResponseErrorMessage
);
141 callback
.Run(*result
);
144 // Handles responses for methods with ListValue results.
145 void OnListValueMethodWithErrorCallback(
146 const ShillClientHelper::ListValueCallback
& callback
,
147 const ShillClientHelper::ErrorCallback
& error_callback
,
148 dbus::Response
* response
) {
149 dbus::MessageReader
reader(response
);
150 scoped_ptr
<base::Value
> value(dbus::PopDataAsValue(&reader
));
151 base::ListValue
* result
= NULL
;
152 if (!value
.get() || !value
->GetAsList(&result
)) {
153 error_callback
.Run(kInvalidResponseErrorName
, kInvalidResponseErrorMessage
);
156 callback
.Run(*result
);
159 // Handles running appropriate error callbacks.
160 void OnError(const ShillClientHelper::ErrorCallback
& error_callback
,
161 dbus::ErrorResponse
* response
) {
162 std::string error_name
;
163 std::string error_message
;
165 // Error message may contain the error message as string.
166 dbus::MessageReader
reader(response
);
167 error_name
= response
->GetErrorName();
168 reader
.PopString(&error_message
);
170 error_callback
.Run(error_name
, error_message
);
175 ShillClientHelper::ShillClientHelper(dbus::Bus
* bus
,
176 dbus::ObjectProxy
* proxy
)
177 : blocking_method_caller_(new BlockingMethodCaller(bus
, proxy
)),
179 weak_ptr_factory_(this) {
182 ShillClientHelper::~ShillClientHelper() {
183 LOG_IF(ERROR
, observer_list_
.size() != 0u)
184 << "ShillClientHelper destroyed with active observers: "
185 << observer_list_
.size();
188 void ShillClientHelper::AddPropertyChangedObserver(
189 ShillPropertyChangedObserver
* observer
) {
190 // Excecute all the pending MonitorPropertyChanged calls.
191 for (size_t i
= 0; i
< interfaces_to_be_monitored_
.size(); ++i
) {
192 MonitorPropertyChangedInternal(interfaces_to_be_monitored_
[i
]);
194 interfaces_to_be_monitored_
.clear();
196 observer_list_
.AddObserver(observer
);
199 void ShillClientHelper::RemovePropertyChangedObserver(
200 ShillPropertyChangedObserver
* observer
) {
201 observer_list_
.RemoveObserver(observer
);
204 void ShillClientHelper::MonitorPropertyChanged(
205 const std::string
& interface_name
) {
206 if (observer_list_
.size() > 0) {
207 // Effectively monitor the PropertyChanged now.
208 MonitorPropertyChangedInternal(interface_name
);
210 // Delay the ConnectToSignal until an observer is added.
211 interfaces_to_be_monitored_
.push_back(interface_name
);
215 void ShillClientHelper::MonitorPropertyChangedInternal(
216 const std::string
& interface_name
) {
217 // We are not using dbus::PropertySet to monitor PropertyChanged signal
218 // because the interface is not "org.freedesktop.DBus.Properties".
219 proxy_
->ConnectToSignal(interface_name
,
220 flimflam::kMonitorPropertyChanged
,
221 base::Bind(&ShillClientHelper::OnPropertyChanged
,
222 weak_ptr_factory_
.GetWeakPtr()),
223 base::Bind(&ShillClientHelper::OnSignalConnected
,
224 weak_ptr_factory_
.GetWeakPtr()));
227 void ShillClientHelper::CallVoidMethod(
228 dbus::MethodCall
* method_call
,
229 const VoidDBusMethodCallback
& callback
) {
230 proxy_
->CallMethod(method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
231 base::Bind(&OnVoidMethod
,
235 void ShillClientHelper::CallObjectPathMethod(
236 dbus::MethodCall
* method_call
,
237 const ObjectPathDBusMethodCallback
& callback
) {
238 proxy_
->CallMethod(method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
239 base::Bind(&OnObjectPathMethod
,
243 void ShillClientHelper::CallObjectPathMethodWithErrorCallback(
244 dbus::MethodCall
* method_call
,
245 const ObjectPathCallback
& callback
,
246 const ErrorCallback
& error_callback
) {
247 proxy_
->CallMethodWithErrorCallback(
249 dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
250 base::Bind(&OnObjectPathMethodWithoutStatus
,
257 void ShillClientHelper::CallDictionaryValueMethod(
258 dbus::MethodCall
* method_call
,
259 const DictionaryValueCallback
& callback
) {
260 proxy_
->CallMethod(method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
261 base::Bind(&OnDictionaryValueMethod
,
265 void ShillClientHelper::CallVoidMethodWithErrorCallback(
266 dbus::MethodCall
* method_call
,
267 const base::Closure
& callback
,
268 const ErrorCallback
& error_callback
) {
269 proxy_
->CallMethodWithErrorCallback(
270 method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
271 base::Bind(&OnVoidMethodWithErrorCallback
,
277 void ShillClientHelper::CallBooleanMethodWithErrorCallback(
278 dbus::MethodCall
* method_call
,
279 const BooleanCallback
& callback
,
280 const ErrorCallback
& error_callback
) {
281 proxy_
->CallMethodWithErrorCallback(
282 method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
283 base::Bind(&OnBooleanMethodWithErrorCallback
,
290 void ShillClientHelper::CallStringMethodWithErrorCallback(
291 dbus::MethodCall
* method_call
,
292 const StringCallback
& callback
,
293 const ErrorCallback
& error_callback
) {
294 proxy_
->CallMethodWithErrorCallback(
295 method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
296 base::Bind(&OnStringMethodWithErrorCallback
,
303 void ShillClientHelper::CallDictionaryValueMethodWithErrorCallback(
304 dbus::MethodCall
* method_call
,
305 const DictionaryValueCallbackWithoutStatus
& callback
,
306 const ErrorCallback
& error_callback
) {
307 proxy_
->CallMethodWithErrorCallback(
308 method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
310 &OnDictionaryValueMethodWithErrorCallback
,
317 void ShillClientHelper::CallListValueMethodWithErrorCallback(
318 dbus::MethodCall
* method_call
,
319 const ListValueCallback
& callback
,
320 const ErrorCallback
& error_callback
) {
321 proxy_
->CallMethodWithErrorCallback(
322 method_call
, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT
,
324 &OnListValueMethodWithErrorCallback
,
331 bool ShillClientHelper::CallVoidMethodAndBlock(
332 dbus::MethodCall
* method_call
) {
333 scoped_ptr
<dbus::Response
> response(
334 blocking_method_caller_
->CallMethodAndBlock(method_call
));
340 base::DictionaryValue
* ShillClientHelper::CallDictionaryValueMethodAndBlock(
341 dbus::MethodCall
* method_call
) {
342 scoped_ptr
<dbus::Response
> response(
343 blocking_method_caller_
->CallMethodAndBlock(method_call
));
347 dbus::MessageReader
reader(response
.get());
348 base::Value
* value
= dbus::PopDataAsValue(&reader
);
349 base::DictionaryValue
* result
= NULL
;
350 if (!value
|| !value
->GetAsDictionary(&result
)) {
358 void ShillClientHelper::AppendValueDataAsVariant(dbus::MessageWriter
* writer
,
359 const base::Value
& value
) {
360 // Support basic types and string-to-string dictionary.
361 switch (value
.GetType()) {
362 case base::Value::TYPE_DICTIONARY
: {
363 const base::DictionaryValue
* dictionary
= NULL
;
364 value
.GetAsDictionary(&dictionary
);
365 dbus::MessageWriter
variant_writer(NULL
);
366 writer
->OpenVariant("a{ss}", &variant_writer
);
367 dbus::MessageWriter
array_writer(NULL
);
368 variant_writer
.OpenArray("{ss}", &array_writer
);
369 for (base::DictionaryValue::Iterator
it(*dictionary
);
372 dbus::MessageWriter
entry_writer(NULL
);
373 array_writer
.OpenDictEntry(&entry_writer
);
374 entry_writer
.AppendString(it
.key());
375 const base::Value
& value
= it
.value();
376 std::string value_string
;
377 DLOG_IF(ERROR
, value
.GetType() != base::Value::TYPE_STRING
)
378 << "Unexpected type " << value
.GetType();
379 value
.GetAsString(&value_string
);
380 entry_writer
.AppendString(value_string
);
381 array_writer
.CloseContainer(&entry_writer
);
383 variant_writer
.CloseContainer(&array_writer
);
384 writer
->CloseContainer(&variant_writer
);
387 case base::Value::TYPE_BOOLEAN
:
388 case base::Value::TYPE_INTEGER
:
389 case base::Value::TYPE_DOUBLE
:
390 case base::Value::TYPE_STRING
:
391 dbus::AppendBasicTypeValueDataAsVariant(writer
, value
);
394 DLOG(ERROR
) << "Unexpected type " << value
.GetType();
399 void ShillClientHelper::OnSignalConnected(const std::string
& interface
,
400 const std::string
& signal
,
402 LOG_IF(ERROR
, !success
) << "Connect to " << interface
<< " " << signal
406 void ShillClientHelper::OnPropertyChanged(dbus::Signal
* signal
) {
407 if (!observer_list_
.might_have_observers())
410 dbus::MessageReader
reader(signal
);
412 if (!reader
.PopString(&name
))
414 scoped_ptr
<base::Value
> value(dbus::PopDataAsValue(&reader
));
418 FOR_EACH_OBSERVER(ShillPropertyChangedObserver
, observer_list_
,
419 OnPropertyChanged(name
, *value
));
423 } // namespace chromeos