Skip to content

Commit

Permalink
Add a method to check if a D-Bus service has an owner. Use it for mtpd.
Browse files Browse the repository at this point in the history
BUG=181064

Review URL: https://chromiumcodereview.appspot.com/14568005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@198328 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
thestig@chromium.org committed May 4, 2013
1 parent b809655 commit 1db0b35
Show file tree
Hide file tree
Showing 4 changed files with 165 additions and 76 deletions.
58 changes: 58 additions & 0 deletions dbus/bus.cc
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,64 @@ void Bus::AssertOnDBusThread() {
}
}

std::string Bus::GetServiceOwnerAndBlock(const std::string& service_name,
GetServiceOwnerOption options) {
AssertOnDBusThread();

MethodCall get_name_owner_call("org.freedesktop.DBus", "GetNameOwner");
MessageWriter writer(&get_name_owner_call);
writer.AppendString(service_name);
VLOG(1) << "Method call: " << get_name_owner_call.ToString();

const ObjectPath obj_path("/org/freedesktop/DBus");
if (!get_name_owner_call.SetDestination("org.freedesktop.DBus") ||
!get_name_owner_call.SetPath(obj_path)) {
if (options == REPORT_ERRORS)
LOG(ERROR) << "Failed to get name owner.";
return "";
}

ScopedDBusError error;
DBusMessage* response_message =
SendWithReplyAndBlock(get_name_owner_call.raw_message(),
ObjectProxy::TIMEOUT_USE_DEFAULT,
error.get());
if (!response_message) {
if (options == REPORT_ERRORS) {
LOG(ERROR) << "Failed to get name owner. Got " << error.name() << ": "
<< error.message();
}
return "";
}

scoped_ptr<Response> response(Response::FromRawMessage(response_message));
MessageReader reader(response.get());

std::string service_owner;
if (!reader.PopString(&service_owner))
service_owner.clear();
return service_owner;
}

void Bus::GetServiceOwner(const std::string& service_name,
const GetServiceOwnerCallback& callback) {
AssertOnOriginThread();

PostTaskToDBusThread(
FROM_HERE,
base::Bind(&Bus::GetServiceOwnerInternal, this, service_name, callback));
}

void Bus::GetServiceOwnerInternal(const std::string& service_name,
const GetServiceOwnerCallback& callback) {
AssertOnDBusThread();

std::string service_owner;
if (Connect())
service_owner = GetServiceOwnerAndBlock(service_name, REPORT_ERRORS);
PostTaskToOriginThread(FROM_HERE, base::Bind(callback, service_owner));
}

dbus_bool_t Bus::OnAddWatch(DBusWatch* raw_watch) {
AssertOnDBusThread();

Expand Down
30 changes: 30 additions & 0 deletions dbus/bus.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
SHARED,
};

// Specifies whether the GetServiceOwnerAndBlock call should report or
// suppress errors.
enum GetServiceOwnerOption {
REPORT_ERRORS,
SUPPRESS_ERRORS,
};

// Options used to create a Bus object.
struct CHROME_DBUS_EXPORT Options {
Options();
Expand Down Expand Up @@ -211,6 +218,12 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
// - the requested service name.
// - whether ownership has been obtained or not.
typedef base::Callback<void (const std::string&, bool)> OnOwnershipCallback;

// Called when GetServiceOwner() completes.
// |service_owner| is the return value from GetServiceOwnerAndBlock().
typedef base::Callback<void (const std::string& service_owner)>
GetServiceOwnerCallback;

// TODO(satorux): Remove the service name parameter as the caller of
// RequestOwnership() knows the service name.

Expand Down Expand Up @@ -530,6 +543,19 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
// AssertOnOriginThread().
virtual void AssertOnDBusThread();

// Gets the owner for |service_name| via org.freedesktop.DBus.GetNameOwner.
// Returns the owner name, if any, or an empty string on failure.
// |options| specifies where to printing error messages or not.
//
// BLOCKING CALL.
virtual std::string GetServiceOwnerAndBlock(const std::string& service_name,
GetServiceOwnerOption options);

// A non-blocking version of GetServiceOwnerAndBlock().
// Must be called in the origin thread.
virtual void GetServiceOwner(const std::string& service_name,
const GetServiceOwnerCallback& callback);

// Returns true if the bus is connected to D-Bus.
bool is_connected() { return connection_ != NULL; }

Expand All @@ -555,6 +581,10 @@ class CHROME_DBUS_EXPORT Bus : public base::RefCountedThreadSafe<Bus> {
void RequestOwnershipInternal(const std::string& service_name,
OnOwnershipCallback on_ownership_callback);

// Helper function used for GetServiceOwner().
void GetServiceOwnerInternal(const std::string& service_name,
const GetServiceOwnerCallback& callback);

// Processes the all incoming data to the connection, if any.
//
// BLOCKING CALL.
Expand Down
82 changes: 30 additions & 52 deletions dbus/object_proxy.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "dbus/object_proxy.h"
#include "dbus/scoped_dbus_error.h"

namespace dbus {

namespace {

const char kErrorServiceUnknown[] = "org.freedesktop.DBus.Error.ServiceUnknown";
Expand All @@ -28,6 +30,15 @@ const int kSuccessRatioHistogramMaxValue = 2;
// The path of D-Bus Object sending NameOwnerChanged signal.
const char kDBusSystemObjectPath[] = "/org/freedesktop/DBus";

// The D-Bus Object interface.
const char kDBusSystemObjectInterface[] = "org.freedesktop.DBus";

// The D-Bus Object address.
const char kDBusSystemObjectAddress[] = "org.freedesktop.DBus";

// The NameOwnerChanged member in |kDBusSystemObjectInterface|.
const char kNameOwnerChangedMember[] = "NameOwnerChanged";

// Gets the absolute signal name by concatenating the interface name and
// the signal name. Used for building keys for method_table_ in
// ObjectProxy.
Expand All @@ -38,13 +49,11 @@ std::string GetAbsoluteSignalName(
}

// An empty function used for ObjectProxy::EmptyResponseCallback().
void EmptyResponseCallbackBody(dbus::Response* unused_response) {
void EmptyResponseCallbackBody(Response* /*response*/) {
}

} // namespace

namespace dbus {

ObjectProxy::ObjectProxy(Bus* bus,
const std::string& service_name,
const ObjectPath& object_path,
Expand Down Expand Up @@ -285,18 +294,17 @@ void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
} else if (dbus_message_get_type(response_message) ==
DBUS_MESSAGE_TYPE_ERROR) {
// This will take |response_message| and release (unref) it.
scoped_ptr<dbus::ErrorResponse> error_response(
dbus::ErrorResponse::FromRawMessage(response_message));
scoped_ptr<ErrorResponse> error_response(
ErrorResponse::FromRawMessage(response_message));
error_callback.Run(error_response.get());
// Delete the message on the D-Bus thread. See below for why.
bus_->PostTaskToDBusThread(
FROM_HERE,
base::Bind(&base::DeletePointer<dbus::ErrorResponse>,
base::Bind(&base::DeletePointer<ErrorResponse>,
error_response.release()));
} else {
// This will take |response_message| and release (unref) it.
scoped_ptr<dbus::Response> response(
dbus::Response::FromRawMessage(response_message));
scoped_ptr<Response> response(Response::FromRawMessage(response_message));
// The response is successfully received.
response_callback.Run(response.get());
// The message should be deleted on the D-Bus thread for a complicated
Expand All @@ -319,8 +327,7 @@ void ObjectProxy::RunResponseCallback(ResponseCallback response_callback,
// thread, not from the current thread here, which is likely UI thread.
bus_->PostTaskToDBusThread(
FROM_HERE,
base::Bind(&base::DeletePointer<dbus::Response>,
response.release()));
base::Bind(&base::DeletePointer<Response>, response.release()));

method_call_successful = true;
// Record time spent for the method call. Don't include failures.
Expand Down Expand Up @@ -439,10 +446,10 @@ DBusHandlerResult ObjectProxy::HandleMessage(
// Verify the signal comes from the object we're proxying for, this is
// our last chance to return DBUS_HANDLER_RESULT_NOT_YET_HANDLED and
// allow other object proxies to handle instead.
const dbus::ObjectPath path = signal->GetPath();
const ObjectPath path = signal->GetPath();
if (path != object_path_) {
if (path.value() == kDBusSystemObjectPath &&
signal->GetMember() == "NameOwnerChanged") {
signal->GetMember() == kNameOwnerChangedMember) {
// Handle NameOwnerChanged separately
return HandleNameOwnerChanged(signal.Pass());
}
Expand Down Expand Up @@ -507,7 +514,7 @@ void ObjectProxy::RunMethod(base::TimeTicks start_time,
// RunResponseCallback().
bus_->PostTaskToDBusThread(
FROM_HERE,
base::Bind(&base::DeletePointer<dbus::Signal>, signal));
base::Bind(&base::DeletePointer<Signal>, signal));

// Record time spent for handling the signal.
UMA_HISTOGRAM_TIMES("DBus.SignalHandleTime",
Expand Down Expand Up @@ -541,7 +548,7 @@ void ObjectProxy::OnCallMethodError(const std::string& interface_name,
ErrorResponse* error_response) {
if (error_response) {
// Error message may contain the error message as string.
dbus::MessageReader reader(error_response);
MessageReader reader(error_response);
std::string error_message;
reader.PopString(&error_message);
LogMethodCallFailure(interface_name,
Expand All @@ -564,8 +571,8 @@ bool ObjectProxy::AddMatchRuleWithCallback(
ScopedDBusError error;
bus_->AddMatch(match_rule, error.get());
if (error.is_set()) {
LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got " <<
error.name() << ": " << error.message();
LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
<< error.name() << ": " << error.message();
return false;
} else {
// Store the match rule, so that we can remove this in Detach().
Expand Down Expand Up @@ -594,8 +601,8 @@ bool ObjectProxy::AddMatchRuleWithoutCallback(
ScopedDBusError error;
bus_->AddMatch(match_rule, error.get());
if (error.is_set()) {
LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got " <<
error.name() << ": " << error.message();
LOG(ERROR) << "Failed to add match rule \"" << match_rule << "\". Got "
<< error.name() << ": " << error.message();
return false;
}
// Store the match rule, so that we can remove this in Detach().
Expand All @@ -605,37 +612,8 @@ bool ObjectProxy::AddMatchRuleWithoutCallback(

void ObjectProxy::UpdateNameOwnerAndBlock() {
bus_->AssertOnDBusThread();

MethodCall get_name_owner_call("org.freedesktop.DBus", "GetNameOwner");
MessageWriter writer(&get_name_owner_call);
writer.AppendString(service_name_);
VLOG(1) << "Method call: " << get_name_owner_call.ToString();

const dbus::ObjectPath obj_path("/org/freedesktop/DBus");
ScopedDBusError error;
if (!get_name_owner_call.SetDestination("org.freedesktop.DBus") ||
!get_name_owner_call.SetPath(obj_path)) {
LOG(ERROR) << "Failed to get name owner.";
return;
}

DBusMessage* response_message = bus_->SendWithReplyAndBlock(
get_name_owner_call.raw_message(),
TIMEOUT_USE_DEFAULT,
error.get());
if (!response_message) {
LOG(ERROR) << "Failed to get name owner. Got " << error.name() << ": " <<
error.message();
return;
}
scoped_ptr<Response> response(Response::FromRawMessage(response_message));
MessageReader reader(response.get());

std::string new_service_name_owner;
if (reader.PopString(&new_service_name_owner))
service_name_owner_ = new_service_name_owner;
else
service_name_owner_.clear();
service_name_owner_ =
bus_->GetServiceOwnerAndBlock(service_name_, Bus::SUPPRESS_ERRORS);
}

DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
Expand All @@ -644,9 +622,9 @@ DBusHandlerResult ObjectProxy::HandleNameOwnerChanged(
bus_->AssertOnDBusThread();

// Confirm the validity of the NameOwnerChanged signal.
if (signal->GetMember() == "NameOwnerChanged" &&
signal->GetInterface() == "org.freedesktop.DBus" &&
signal->GetSender() == "org.freedesktop.DBus") {
if (signal->GetMember() == kNameOwnerChangedMember &&
signal->GetInterface() == kDBusSystemObjectInterface &&
signal->GetSender() == kDBusSystemObjectAddress) {
MessageReader reader(signal.get());
std::string name, old_owner, new_owner;
if (reader.PopString(&name) &&
Expand Down
Loading

0 comments on commit 1db0b35

Please sign in to comment.