You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
470 lines
15 KiB
470 lines
15 KiB
// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#ifndef LIBBRILLO_BRILLO_GLIB_DBUS_H_
|
|
#define LIBBRILLO_BRILLO_GLIB_DBUS_H_
|
|
|
|
// IMPORTANT: Do not use this in new code. Instead, use libchrome's D-Bus
|
|
// bindings. See https://goo.gl/EH3MmR for more details.
|
|
|
|
#include <dbus/dbus-glib.h>
|
|
#include <glib-object.h>
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "base/logging.h"
|
|
#include <brillo/brillo_export.h>
|
|
#include <brillo/glib/object.h>
|
|
|
|
struct DBusMessage;
|
|
struct DBusConnection;
|
|
|
|
namespace brillo {
|
|
|
|
namespace dbus {
|
|
|
|
// \brief BusConnection manages the ref-count for a ::DBusGConnection*.
|
|
//
|
|
// A BusConnection has reference semantics bound to a particular communication
|
|
// bus.
|
|
//
|
|
// \models Copyable, Assignable
|
|
// \related GetSystemBusConnection()
|
|
|
|
class BRILLO_EXPORT BusConnection {
|
|
public:
|
|
typedef ::DBusGConnection* value_type;
|
|
|
|
BusConnection(const BusConnection& x) : object_(x.object_) {
|
|
if (object_)
|
|
::dbus_g_connection_ref(object_);
|
|
}
|
|
|
|
~BusConnection() {
|
|
if (object_)
|
|
::dbus_g_connection_unref(object_);
|
|
}
|
|
|
|
BusConnection& operator=(BusConnection x) {
|
|
swap(*this, x);
|
|
return *this;
|
|
}
|
|
|
|
const value_type& g_connection() const {
|
|
DCHECK(object_) << "referencing an empty connection";
|
|
return object_;
|
|
}
|
|
|
|
operator bool() const { return object_; }
|
|
|
|
bool HasConnection() const { return object_; }
|
|
|
|
private:
|
|
friend void swap(BusConnection& x, BusConnection& y);
|
|
|
|
friend class Proxy;
|
|
friend BusConnection GetSystemBusConnection();
|
|
friend BusConnection GetPrivateBusConnection(const char* address);
|
|
|
|
// Constructor takes ownership
|
|
BRILLO_PRIVATE explicit BusConnection(::DBusGConnection* x) : object_(x) {}
|
|
|
|
value_type object_;
|
|
};
|
|
|
|
inline void swap(BusConnection& x, BusConnection& y) {
|
|
std::swap(x.object_, y.object_);
|
|
}
|
|
|
|
// \brief Proxy manages the ref-count for a ::DBusGProxy*.
|
|
//
|
|
// Proxy has reference semantics and represents a connection to on object on
|
|
// the bus. A proxy object is constructed with a connection to a bus, a name
|
|
// to an entity on the bus, a path to an object owned by the entity, and an
|
|
// interface protocol name used to communicate with the object.
|
|
|
|
class BRILLO_EXPORT Proxy {
|
|
public:
|
|
typedef ::DBusGProxy* value_type;
|
|
|
|
Proxy();
|
|
|
|
// Set |connect_to_name_owner| true if you'd like to use
|
|
// dbus_g_proxy_new_for_name_owner() rather than dbus_g_proxy_new_for_name().
|
|
Proxy(const BusConnection& connection,
|
|
const char* name,
|
|
const char* path,
|
|
const char* interface,
|
|
bool connect_to_name_owner);
|
|
|
|
// Equivalent to Proxy(connection, name, path, interface, false).
|
|
Proxy(const BusConnection& connection,
|
|
const char* name,
|
|
const char* path,
|
|
const char* interface);
|
|
|
|
// Creates a peer proxy using dbus_g_proxy_new_for_peer.
|
|
Proxy(const BusConnection& connection,
|
|
const char* path,
|
|
const char* interface);
|
|
|
|
Proxy(const Proxy& x);
|
|
|
|
~Proxy();
|
|
|
|
Proxy& operator=(Proxy x) {
|
|
swap(*this, x);
|
|
return *this;
|
|
}
|
|
|
|
const char* path() const {
|
|
DCHECK(object_) << "referencing an empty proxy";
|
|
return ::dbus_g_proxy_get_path(object_);
|
|
}
|
|
|
|
// gproxy() returns a reference to the underlying ::DBusGProxy*. As this
|
|
// library evolves, the gproxy() will be moved to be private.
|
|
|
|
const value_type& gproxy() const {
|
|
DCHECK(object_) << "referencing an empty proxy";
|
|
return object_;
|
|
}
|
|
|
|
operator bool() const { return object_; }
|
|
|
|
private:
|
|
BRILLO_PRIVATE static value_type GetGProxy(const BusConnection& connection,
|
|
const char* name,
|
|
const char* path,
|
|
const char* interface,
|
|
bool connect_to_name_owner);
|
|
|
|
BRILLO_PRIVATE static value_type GetGPeerProxy(
|
|
const BusConnection& connection,
|
|
const char* path,
|
|
const char* interface);
|
|
|
|
BRILLO_PRIVATE operator int() const; // for safe bool cast
|
|
friend void swap(Proxy& x, Proxy& y);
|
|
|
|
value_type object_;
|
|
};
|
|
|
|
inline void swap(Proxy& x, Proxy& y) {
|
|
std::swap(x.object_, y.object_);
|
|
}
|
|
|
|
// \brief RegisterExclusiveService configures a GObject to run as a service on
|
|
// a supplied ::BusConnection.
|
|
//
|
|
// RegisterExclusiveService encapsulates the process of configuring the
|
|
// supplied \param object at \param service_path on the \param connection.
|
|
// Exclusivity is ensured by replacing any existing services at that named
|
|
// location and confirming that the connection is the primary owner.
|
|
//
|
|
// Type information for the \param object must be installed with
|
|
// dbus_g_object_type_install_info prior to use.
|
|
|
|
BRILLO_EXPORT bool RegisterExclusiveService(const BusConnection& connection,
|
|
const char* interface_name,
|
|
const char* service_name,
|
|
const char* service_path,
|
|
GObject* object);
|
|
|
|
template<typename F> // F is a function signature
|
|
class MonitorConnection;
|
|
|
|
template<typename A1>
|
|
class MonitorConnection<void(A1)> {
|
|
public:
|
|
MonitorConnection(const Proxy& proxy,
|
|
const char* name,
|
|
void (*monitor)(void*, A1),
|
|
void* object)
|
|
: proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
|
|
|
|
static void Run(::DBusGProxy*, A1 x, MonitorConnection* self) {
|
|
self->monitor_(self->object_, x);
|
|
}
|
|
const Proxy& proxy() const { return proxy_; }
|
|
const std::string& name() const { return name_; }
|
|
|
|
private:
|
|
Proxy proxy_;
|
|
std::string name_;
|
|
void (*monitor_)(void*, A1);
|
|
void* object_;
|
|
};
|
|
|
|
template<typename A1, typename A2>
|
|
class MonitorConnection<void(A1, A2)> {
|
|
public:
|
|
MonitorConnection(const Proxy& proxy,
|
|
const char* name,
|
|
void (*monitor)(void*, A1, A2),
|
|
void* object)
|
|
: proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
|
|
|
|
static void Run(::DBusGProxy*, A1 x, A2 y, MonitorConnection* self) {
|
|
self->monitor_(self->object_, x, y);
|
|
}
|
|
const Proxy& proxy() const { return proxy_; }
|
|
const std::string& name() const { return name_; }
|
|
|
|
private:
|
|
Proxy proxy_;
|
|
std::string name_;
|
|
void (*monitor_)(void*, A1, A2);
|
|
void* object_;
|
|
};
|
|
|
|
template<typename A1, typename A2, typename A3>
|
|
class MonitorConnection<void(A1, A2, A3)> {
|
|
public:
|
|
MonitorConnection(const Proxy& proxy,
|
|
const char* name,
|
|
void (*monitor)(void*, A1, A2, A3),
|
|
void* object)
|
|
: proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
|
|
|
|
static void Run(::DBusGProxy*, A1 x, A2 y, A3 z, MonitorConnection* self) {
|
|
self->monitor_(self->object_, x, y, z);
|
|
}
|
|
const Proxy& proxy() const { return proxy_; }
|
|
const std::string& name() const { return name_; }
|
|
|
|
private:
|
|
Proxy proxy_;
|
|
std::string name_;
|
|
void (*monitor_)(void*, A1, A2, A3);
|
|
void* object_;
|
|
};
|
|
|
|
template<typename A1, typename A2, typename A3, typename A4>
|
|
class MonitorConnection<void(A1, A2, A3, A4)> {
|
|
public:
|
|
MonitorConnection(const Proxy& proxy,
|
|
const char* name,
|
|
void (*monitor)(void*, A1, A2, A3, A4),
|
|
void* object)
|
|
: proxy_(proxy), name_(name), monitor_(monitor), object_(object) {}
|
|
|
|
static void Run(::DBusGProxy*,
|
|
A1 x,
|
|
A2 y,
|
|
A3 z,
|
|
A4 w,
|
|
MonitorConnection* self) {
|
|
self->monitor_(self->object_, x, y, z, w);
|
|
}
|
|
const Proxy& proxy() const { return proxy_; }
|
|
const std::string& name() const { return name_; }
|
|
|
|
private:
|
|
Proxy proxy_;
|
|
std::string name_;
|
|
void (*monitor_)(void*, A1, A2, A3, A4);
|
|
void* object_;
|
|
};
|
|
|
|
template<typename A1>
|
|
MonitorConnection<void(A1)>* Monitor(const Proxy& proxy,
|
|
const char* name,
|
|
void (*monitor)(void*, A1),
|
|
void* object) {
|
|
typedef MonitorConnection<void(A1)> ConnectionType;
|
|
|
|
ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
|
|
|
|
::dbus_g_proxy_add_signal(
|
|
proxy.gproxy(), name, glib::type_to_gtypeid<A1>(), G_TYPE_INVALID);
|
|
::dbus_g_proxy_connect_signal(
|
|
proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
|
|
return result;
|
|
}
|
|
|
|
template<typename A1, typename A2>
|
|
MonitorConnection<void(A1, A2)>* Monitor(const Proxy& proxy,
|
|
const char* name,
|
|
void (*monitor)(void*, A1, A2),
|
|
void* object) {
|
|
typedef MonitorConnection<void(A1, A2)> ConnectionType;
|
|
|
|
ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
|
|
|
|
::dbus_g_proxy_add_signal(proxy.gproxy(),
|
|
name,
|
|
glib::type_to_gtypeid<A1>(),
|
|
glib::type_to_gtypeid<A2>(),
|
|
G_TYPE_INVALID);
|
|
::dbus_g_proxy_connect_signal(
|
|
proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
|
|
return result;
|
|
}
|
|
|
|
template<typename A1, typename A2, typename A3>
|
|
MonitorConnection<void(A1, A2, A3)>* Monitor(const Proxy& proxy,
|
|
const char* name,
|
|
void (*monitor)(void*, A1, A2, A3),
|
|
void* object) {
|
|
typedef MonitorConnection<void(A1, A2, A3)> ConnectionType;
|
|
|
|
ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
|
|
|
|
::dbus_g_proxy_add_signal(proxy.gproxy(),
|
|
name,
|
|
glib::type_to_gtypeid<A1>(),
|
|
glib::type_to_gtypeid<A2>(),
|
|
glib::type_to_gtypeid<A3>(),
|
|
G_TYPE_INVALID);
|
|
::dbus_g_proxy_connect_signal(
|
|
proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
|
|
return result;
|
|
}
|
|
|
|
template<typename A1, typename A2, typename A3, typename A4>
|
|
MonitorConnection<void(A1, A2, A3, A4)>* Monitor(
|
|
const Proxy& proxy,
|
|
const char* name,
|
|
void (*monitor)(void*, A1, A2, A3, A4),
|
|
void* object) {
|
|
typedef MonitorConnection<void(A1, A2, A3, A4)> ConnectionType;
|
|
|
|
ConnectionType* result = new ConnectionType(proxy, name, monitor, object);
|
|
|
|
::dbus_g_proxy_add_signal(proxy.gproxy(),
|
|
name,
|
|
glib::type_to_gtypeid<A1>(),
|
|
glib::type_to_gtypeid<A2>(),
|
|
glib::type_to_gtypeid<A3>(),
|
|
glib::type_to_gtypeid<A4>(),
|
|
G_TYPE_INVALID);
|
|
::dbus_g_proxy_connect_signal(
|
|
proxy.gproxy(), name, G_CALLBACK(&ConnectionType::Run), result, nullptr);
|
|
return result;
|
|
}
|
|
|
|
template<typename F>
|
|
void Disconnect(MonitorConnection<F>* connection) {
|
|
typedef MonitorConnection<F> ConnectionType;
|
|
|
|
::dbus_g_proxy_disconnect_signal(connection->proxy().gproxy(),
|
|
connection->name().c_str(),
|
|
G_CALLBACK(&ConnectionType::Run),
|
|
connection);
|
|
delete connection;
|
|
}
|
|
|
|
// \brief call_PtrArray() invokes a method on a proxy returning a
|
|
// glib::PtrArray.
|
|
//
|
|
// CallPtrArray is the first instance of what is likely to be a general
|
|
// way to make method calls to a proxy. It will likely be replaced with
|
|
// something like Call(proxy, method, arg1, arg2, ..., ResultType*) in the
|
|
// future. However, I don't yet have enough cases to generalize from.
|
|
|
|
BRILLO_EXPORT bool CallPtrArray(const Proxy& proxy,
|
|
const char* method,
|
|
glib::ScopedPtrArray<const char*>* result);
|
|
|
|
// \brief RetrieveProperty() retrieves a property of an object associated with a
|
|
// proxy.
|
|
//
|
|
// Given a proxy to an object supporting the org.freedesktop.DBus.Properties
|
|
// interface, the RetrieveProperty() call will retrieve a property of the
|
|
// specified interface on the object storing it in \param result and returning
|
|
// \true. If the dbus call fails or the object returned is not of type \param T,
|
|
// then \false is returned and \param result is unchanged.
|
|
//
|
|
// \example
|
|
// Proxy proxy(GetSystemBusConnection(),
|
|
// "org.freedesktop.DeviceKit.Power", // A named entity on the bus
|
|
// battery_name, // Path to a battery on the bus
|
|
// "org.freedesktop.DBus.Properties") // Properties interface
|
|
//
|
|
// double x;
|
|
// if (RetrieveProperty(proxy,
|
|
// "org.freedesktop.DeviceKit.Power.Device",
|
|
// "percentage")
|
|
// std::cout << "Battery charge is " << x << "% of capacity.";
|
|
// \end_example
|
|
|
|
template<typename T>
|
|
inline bool RetrieveProperty(const Proxy& proxy,
|
|
const char* interface,
|
|
const char* property,
|
|
T* result) {
|
|
glib::ScopedError error;
|
|
glib::Value value;
|
|
|
|
if (!::dbus_g_proxy_call(proxy.gproxy(), "Get", &Resetter(&error).lvalue(),
|
|
G_TYPE_STRING, interface,
|
|
G_TYPE_STRING, property,
|
|
G_TYPE_INVALID,
|
|
G_TYPE_VALUE, &value,
|
|
G_TYPE_INVALID)) {
|
|
LOG(ERROR) << "Getting property failed: "
|
|
<< (error->message ? error->message : "Unknown Error.");
|
|
return false;
|
|
}
|
|
return glib::Retrieve(value, result);
|
|
}
|
|
|
|
// \brief RetrieveProperties returns a HashTable of all properties for the
|
|
// specified interface.
|
|
|
|
BRILLO_EXPORT bool RetrieveProperties(const Proxy& proxy,
|
|
const char* interface,
|
|
glib::ScopedHashTable* result);
|
|
|
|
// \brief Returns a connection to the system bus.
|
|
|
|
BRILLO_EXPORT BusConnection GetSystemBusConnection();
|
|
|
|
// \brief Returns a private connection to a bus at |address|.
|
|
|
|
BRILLO_EXPORT BusConnection GetPrivateBusConnection(const char* address);
|
|
|
|
// \brief Calls a method |method_name| with no arguments per the given |path|
|
|
// and |interface_name|. Ignores return value.
|
|
|
|
BRILLO_EXPORT void CallMethodWithNoArguments(const char* service_name,
|
|
const char* path,
|
|
const char* interface_name,
|
|
const char* method_name);
|
|
|
|
// \brief Low-level signal monitor base class.
|
|
//
|
|
// Used when there is no definite named signal sender (that Proxy
|
|
// could be used for).
|
|
|
|
class BRILLO_EXPORT SignalWatcher {
|
|
public:
|
|
SignalWatcher() {}
|
|
~SignalWatcher();
|
|
void StartMonitoring(const std::string& interface, const std::string& signal);
|
|
|
|
private:
|
|
// Callback invoked on the given signal arrival.
|
|
virtual void OnSignal(DBusMessage* message) = 0;
|
|
|
|
// Returns a string matching the D-Bus messages that we want to listen for.
|
|
BRILLO_PRIVATE std::string GetDBusMatchString() const;
|
|
|
|
// A D-Bus message filter to receive signals.
|
|
BRILLO_PRIVATE static DBusHandlerResult FilterDBusMessage(
|
|
DBusConnection* dbus_conn,
|
|
DBusMessage* message,
|
|
void* data);
|
|
std::string interface_;
|
|
std::string signal_;
|
|
};
|
|
|
|
} // namespace dbus
|
|
} // namespace brillo
|
|
|
|
#endif // LIBBRILLO_BRILLO_GLIB_DBUS_H_
|