This source file includes following definitions.
- GetAbsoluteMethodName
- object_is_registered_
- ExportMethodAndBlock
- ExportMethod
- SendSignal
- Unregister
- ExportMethodInternal
- OnExported
- SendSignalInternal
- Register
- HandleMessage
- RunMethod
- SendResponse
- OnMethodCompleted
- OnUnregistered
- HandleMessageThunk
- OnUnregisteredThunk
#include "dbus/exported_object.h"
#include "base/bind.h"
#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "dbus/bus.h"
#include "dbus/message.h"
#include "dbus/object_path.h"
#include "dbus/scoped_dbus_error.h"
namespace dbus {
namespace {
const int kSuccessRatioHistogramMaxValue = 2;
std::string GetAbsoluteMethodName(
const std::string& interface_name,
const std::string& method_name) {
return interface_name + "." + method_name;
}
}
ExportedObject::ExportedObject(Bus* bus,
const ObjectPath& object_path)
: bus_(bus),
object_path_(object_path),
object_is_registered_(false) {
}
ExportedObject::~ExportedObject() {
DCHECK(!object_is_registered_);
}
bool ExportedObject::ExportMethodAndBlock(
const std::string& interface_name,
const std::string& method_name,
MethodCallCallback method_call_callback) {
bus_->AssertOnDBusThread();
const std::string absolute_method_name =
GetAbsoluteMethodName(interface_name, method_name);
if (method_table_.find(absolute_method_name) != method_table_.end()) {
LOG(ERROR) << absolute_method_name << " is already exported";
return false;
}
if (!bus_->Connect())
return false;
if (!bus_->SetUpAsyncOperations())
return false;
if (!Register())
return false;
method_table_[absolute_method_name] = method_call_callback;
return true;
}
void ExportedObject::ExportMethod(const std::string& interface_name,
const std::string& method_name,
MethodCallCallback method_call_callback,
OnExportedCallback on_exported_calback) {
bus_->AssertOnOriginThread();
base::Closure task = base::Bind(&ExportedObject::ExportMethodInternal,
this,
interface_name,
method_name,
method_call_callback,
on_exported_calback);
bus_->GetDBusTaskRunner()->PostTask(FROM_HERE, task);
}
void ExportedObject::SendSignal(Signal* signal) {
CHECK(signal->SetPath(object_path_));
DBusMessage* signal_message = signal->raw_message();
dbus_message_ref(signal_message);
const base::TimeTicks start_time = base::TimeTicks::Now();
bus_->GetDBusTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ExportedObject::SendSignalInternal,
this,
start_time,
signal_message));
}
void ExportedObject::Unregister() {
bus_->AssertOnDBusThread();
if (!object_is_registered_)
return;
bus_->UnregisterObjectPath(object_path_);
object_is_registered_ = false;
}
void ExportedObject::ExportMethodInternal(
const std::string& interface_name,
const std::string& method_name,
MethodCallCallback method_call_callback,
OnExportedCallback on_exported_calback) {
bus_->AssertOnDBusThread();
const bool success = ExportMethodAndBlock(interface_name,
method_name,
method_call_callback);
bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
base::Bind(&ExportedObject::OnExported,
this,
on_exported_calback,
interface_name,
method_name,
success));
}
void ExportedObject::OnExported(OnExportedCallback on_exported_callback,
const std::string& interface_name,
const std::string& method_name,
bool success) {
bus_->AssertOnOriginThread();
on_exported_callback.Run(interface_name, method_name, success);
}
void ExportedObject::SendSignalInternal(base::TimeTicks start_time,
DBusMessage* signal_message) {
uint32 serial = 0;
bus_->Send(signal_message, &serial);
dbus_message_unref(signal_message);
UMA_HISTOGRAM_TIMES("DBus.SignalSendTime",
base::TimeTicks::Now() - start_time);
}
bool ExportedObject::Register() {
bus_->AssertOnDBusThread();
if (object_is_registered_)
return true;
ScopedDBusError error;
DBusObjectPathVTable vtable = {};
vtable.message_function = &ExportedObject::HandleMessageThunk;
vtable.unregister_function = &ExportedObject::OnUnregisteredThunk;
const bool success = bus_->TryRegisterObjectPath(object_path_,
&vtable,
this,
error.get());
if (!success) {
LOG(ERROR) << "Failed to register the object: " << object_path_.value()
<< ": " << (error.is_set() ? error.message() : "");
return false;
}
object_is_registered_ = true;
return true;
}
DBusHandlerResult ExportedObject::HandleMessage(
DBusConnection* connection,
DBusMessage* raw_message) {
bus_->AssertOnDBusThread();
DCHECK_EQ(DBUS_MESSAGE_TYPE_METHOD_CALL, dbus_message_get_type(raw_message));
dbus_message_ref(raw_message);
scoped_ptr<MethodCall> method_call(
MethodCall::FromRawMessage(raw_message));
const std::string interface = method_call->GetInterface();
const std::string member = method_call->GetMember();
if (interface.empty()) {
LOG(WARNING) << "Interface is missing: " << method_call->ToString();
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
const std::string absolute_method_name = GetAbsoluteMethodName(
interface, member);
MethodTable::const_iterator iter = method_table_.find(absolute_method_name);
if (iter == method_table_.end()) {
LOG(WARNING) << "Unknown method: " << method_call->ToString();
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
const base::TimeTicks start_time = base::TimeTicks::Now();
if (bus_->HasDBusThread()) {
bus_->GetOriginTaskRunner()->PostTask(FROM_HERE,
base::Bind(&ExportedObject::RunMethod,
this,
iter->second,
base::Passed(&method_call),
start_time));
} else {
MethodCall* method = method_call.get();
iter->second.Run(method,
base::Bind(&ExportedObject::SendResponse,
this,
start_time,
base::Passed(&method_call)));
}
return DBUS_HANDLER_RESULT_HANDLED;
}
void ExportedObject::RunMethod(MethodCallCallback method_call_callback,
scoped_ptr<MethodCall> method_call,
base::TimeTicks start_time) {
bus_->AssertOnOriginThread();
MethodCall* method = method_call.get();
method_call_callback.Run(method,
base::Bind(&ExportedObject::SendResponse,
this,
start_time,
base::Passed(&method_call)));
}
void ExportedObject::SendResponse(base::TimeTicks start_time,
scoped_ptr<MethodCall> method_call,
scoped_ptr<Response> response) {
DCHECK(method_call);
if (bus_->HasDBusThread()) {
bus_->GetDBusTaskRunner()->PostTask(
FROM_HERE,
base::Bind(&ExportedObject::OnMethodCompleted,
this,
base::Passed(&method_call),
base::Passed(&response),
start_time));
} else {
OnMethodCompleted(method_call.Pass(), response.Pass(), start_time);
}
}
void ExportedObject::OnMethodCompleted(scoped_ptr<MethodCall> method_call,
scoped_ptr<Response> response,
base::TimeTicks start_time) {
bus_->AssertOnDBusThread();
UMA_HISTOGRAM_ENUMERATION("DBus.ExportedMethodHandleSuccess",
response ? 1 : 0,
kSuccessRatioHistogramMaxValue);
if (!bus_->is_connected())
return;
if (!response) {
scoped_ptr<ErrorResponse> error_response(
ErrorResponse::FromMethodCall(
method_call.get(),
DBUS_ERROR_FAILED,
"error occurred in " + method_call->GetMember()));
bus_->Send(error_response->raw_message(), NULL);
return;
}
bus_->Send(response->raw_message(), NULL);
UMA_HISTOGRAM_TIMES("DBus.ExportedMethodHandleTime",
base::TimeTicks::Now() - start_time);
}
void ExportedObject::OnUnregistered(DBusConnection* connection) {
}
DBusHandlerResult ExportedObject::HandleMessageThunk(
DBusConnection* connection,
DBusMessage* raw_message,
void* user_data) {
ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
return self->HandleMessage(connection, raw_message);
}
void ExportedObject::OnUnregisteredThunk(DBusConnection *connection,
void* user_data) {
ExportedObject* self = reinterpret_cast<ExportedObject*>(user_data);
return self->OnUnregistered(connection);
}
}