blob: 89162cbfefcf818ae3aae9da1a4fcf4f58f454e8 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/dbus/flimflam_client_helper.h"
#include "base/bind.h"
#include "base/values.h"
#include "dbus/message.h"
#include "dbus/object_proxy.h"
#include "dbus/values_util.h"
#include "third_party/cros_system_api/dbus/service_constants.h"
namespace chromeos {
FlimflamClientHelper::FlimflamClientHelper(dbus::Bus* bus,
dbus::ObjectProxy* proxy)
: weak_ptr_factory_(this),
blocking_method_caller_(bus, proxy),
proxy_(proxy) {
}
FlimflamClientHelper::~FlimflamClientHelper() {
}
void FlimflamClientHelper::SetPropertyChangedHandler(
const PropertyChangedHandler& handler) {
property_changed_handler_ = handler;
}
void FlimflamClientHelper::ResetPropertyChangedHandler() {
property_changed_handler_.Reset();
}
void FlimflamClientHelper::MonitorPropertyChanged(
const std::string& interface_name) {
// We are not using dbus::PropertySet to monitor PropertyChanged signal
// because the interface is not "org.freedesktop.DBus.Properties".
proxy_->ConnectToSignal(interface_name,
flimflam::kMonitorPropertyChanged,
base::Bind(&FlimflamClientHelper::OnPropertyChanged,
weak_ptr_factory_.GetWeakPtr()),
base::Bind(&FlimflamClientHelper::OnSignalConnected,
weak_ptr_factory_.GetWeakPtr()));
}
void FlimflamClientHelper::CallVoidMethod(dbus::MethodCall* method_call,
const VoidCallback& callback) {
proxy_->CallMethod(method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&FlimflamClientHelper::OnVoidMethod,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void FlimflamClientHelper::CallObjectPathMethod(
dbus::MethodCall* method_call,
const ObjectPathCallback& callback) {
proxy_->CallMethod(method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&FlimflamClientHelper::OnObjectPathMethod,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void FlimflamClientHelper::CallDictionaryValueMethod(
dbus::MethodCall* method_call,
const DictionaryValueCallback& callback) {
proxy_->CallMethod(method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&FlimflamClientHelper::OnDictionaryValueMethod,
weak_ptr_factory_.GetWeakPtr(),
callback));
}
void FlimflamClientHelper::CallVoidMethodWithErrorCallback(
dbus::MethodCall* method_call,
const base::Closure& callback,
const ErrorCallback& error_callback) {
proxy_->CallMethodWithErrorCallback(
method_call, dbus::ObjectProxy::TIMEOUT_USE_DEFAULT,
base::Bind(&FlimflamClientHelper::OnVoidMethodWithErrorCallback,
weak_ptr_factory_.GetWeakPtr(),
callback),
base::Bind(&FlimflamClientHelper::OnError,
weak_ptr_factory_.GetWeakPtr(),
error_callback));
}
bool FlimflamClientHelper::CallVoidMethodAndBlock(
dbus::MethodCall* method_call) {
scoped_ptr<dbus::Response> response(
blocking_method_caller_.CallMethodAndBlock(method_call));
if (!response.get())
return false;
return true;
}
dbus::ObjectPath FlimflamClientHelper::CallObjectPathMethodAndBlock(
dbus::MethodCall* method_call) {
scoped_ptr<dbus::Response> response(
blocking_method_caller_.CallMethodAndBlock(method_call));
if (!response.get())
return dbus::ObjectPath();
dbus::MessageReader reader(response.get());
dbus::ObjectPath result;
if (!reader.PopObjectPath(&result))
return dbus::ObjectPath();
return result;
}
base::DictionaryValue* FlimflamClientHelper::CallDictionaryValueMethodAndBlock(
dbus::MethodCall* method_call) {
scoped_ptr<dbus::Response> response(
blocking_method_caller_.CallMethodAndBlock(method_call));
if (!response.get())
return NULL;
dbus::MessageReader reader(response.get());
base::Value* value = dbus::PopDataAsValue(&reader);
base::DictionaryValue* result = NULL;
if (!value || !value->GetAsDictionary(&result)) {
delete value;
return NULL;
}
return result;
}
// static
void FlimflamClientHelper::AppendValueDataAsVariant(dbus::MessageWriter* writer,
const base::Value& value) {
// Support basic types and string-to-string dictionary.
switch (value.GetType()) {
case base::Value::TYPE_DICTIONARY: {
const base::DictionaryValue* dictionary = NULL;
value.GetAsDictionary(&dictionary);
dbus::MessageWriter variant_writer(NULL);
writer->OpenVariant("a{ss}", &variant_writer);
dbus::MessageWriter array_writer(NULL);
variant_writer.OpenArray("{ss}", &array_writer);
for (base::DictionaryValue::Iterator it(*dictionary);
it.HasNext();
it.Advance()) {
dbus::MessageWriter entry_writer(NULL);
array_writer.OpenDictEntry(&entry_writer);
entry_writer.AppendString(it.key());
const base::Value& value = it.value();
std::string value_string;
DLOG_IF(ERROR, value.GetType() != base::Value::TYPE_STRING)
<< "Unexpected type " << value.GetType();
value.GetAsString(&value_string);
entry_writer.AppendString(value_string);
array_writer.CloseContainer(&entry_writer);
}
variant_writer.CloseContainer(&array_writer);
writer->CloseContainer(&variant_writer);
break;
}
case base::Value::TYPE_BOOLEAN:
case base::Value::TYPE_INTEGER:
case base::Value::TYPE_DOUBLE:
case base::Value::TYPE_STRING:
dbus::AppendBasicTypeValueDataAsVariant(writer, value);
break;
default:
DLOG(ERROR) << "Unexpected type " << value.GetType();
}
}
void FlimflamClientHelper::OnSignalConnected(const std::string& interface,
const std::string& signal,
bool success) {
LOG_IF(ERROR, !success) << "Connect to " << interface << " " << signal
<< " failed.";
}
void FlimflamClientHelper::OnPropertyChanged(dbus::Signal* signal) {
if (property_changed_handler_.is_null())
return;
dbus::MessageReader reader(signal);
std::string name;
if (!reader.PopString(&name))
return;
scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader));
if (!value.get())
return;
property_changed_handler_.Run(name, *value);
}
void FlimflamClientHelper::OnVoidMethod(const VoidCallback& callback,
dbus::Response* response) {
if (!response) {
callback.Run(DBUS_METHOD_CALL_FAILURE);
return;
}
callback.Run(DBUS_METHOD_CALL_SUCCESS);
}
void FlimflamClientHelper::OnObjectPathMethod(
const ObjectPathCallback& callback,
dbus::Response* response) {
if (!response) {
callback.Run(DBUS_METHOD_CALL_FAILURE, dbus::ObjectPath());
return;
}
dbus::MessageReader reader(response);
dbus::ObjectPath result;
if (!reader.PopObjectPath(&result)) {
callback.Run(DBUS_METHOD_CALL_FAILURE, dbus::ObjectPath());
return;
}
callback.Run(DBUS_METHOD_CALL_SUCCESS, result);
}
void FlimflamClientHelper::OnDictionaryValueMethod(
const DictionaryValueCallback& callback,
dbus::Response* response) {
if (!response) {
base::DictionaryValue result;
callback.Run(DBUS_METHOD_CALL_FAILURE, result);
return;
}
dbus::MessageReader reader(response);
scoped_ptr<base::Value> value(dbus::PopDataAsValue(&reader));
base::DictionaryValue* result = NULL;
if (!value.get() || !value->GetAsDictionary(&result)) {
base::DictionaryValue result;
callback.Run(DBUS_METHOD_CALL_FAILURE, result);
return;
}
callback.Run(DBUS_METHOD_CALL_SUCCESS, *result);
}
void FlimflamClientHelper::OnVoidMethodWithErrorCallback(
const base::Closure& callback,
dbus::Response* response) {
callback.Run();
}
void FlimflamClientHelper::OnError(const ErrorCallback& error_callback,
dbus::ErrorResponse* response) {
std::string error_name;
std::string error_message;
if (response) {
// Error message may contain the error message as string.
dbus::MessageReader reader(response);
error_name = response->GetErrorName();
reader.PopString(&error_message);
}
error_callback.Run(error_name, error_message);
}
} // namespace chromeos