(→Using d-feet) |
(→qdbus and dbus-send (command line): links to tutorials) |
||
| (28 intermediate revisions not shown) | |||
| Line 1: | Line 1: | ||
| + | [[Category:devguide]] | ||
| + | [[Category:language-C]] | ||
| + | [[Category:Meego-1.0]] | ||
| + | [[Category:tutorial]] | ||
| + | [[Category:platform-developer]] | ||
| + | |||
== Introduction == | == Introduction == | ||
| Line 32: | Line 38: | ||
== Investigating and debugging D-Bus services == | == Investigating and debugging D-Bus services == | ||
| - | Often the easiest way to get started investigating a service on the Bus is to use D-Feet, a graphical D-Bus debugging tool. | + | === d-feet (graphical tool) === |
| + | |||
| + | Often the easiest way to get started investigating a service on the Bus is to use D-Feet, a graphical D-Bus debugging tool. Here's an example of it monitoring the system bus on a MeeGo netbook: | ||
[[File:D-Bus-overview-d-feet.png|alt=D-Feet graphic D-Bus debugging tool|D-Feet graphic D-Bus debugging tool]] | [[File:D-Bus-overview-d-feet.png|alt=D-Feet graphic D-Bus debugging tool|D-Feet graphic D-Bus debugging tool]] | ||
| Line 46: | Line 54: | ||
</code> | </code> | ||
| - | === Using d-feet === | + | ==== Using d-feet ==== |
D-Feet can be started from the command line with: | D-Feet can be started from the command line with: | ||
| Line 54: | Line 62: | ||
You can then connect to either the system bus or the session bus, using the connect icon: | You can then connect to either the system bus or the session bus, using the connect icon: | ||
| - | [[File:Dbus-d-feet-connect-icon. | + | [[File:Dbus-d-feet-connect-icon.png|alt=d-feet connect icon|d-feet connect icon]] |
The address to enter depends on the bus type you want to monitor: | The address to enter depends on the bus type you want to monitor: | ||
| Line 73: | Line 81: | ||
</ul> | </ul> | ||
| - | Once you've connected to a bus, you'll get a list of bus names on the left. Click on one to see the | + | Once you've connected to a bus, you'll get a list of bus names on the left. Click on one to see the available object paths in the right panel (see the screenshot above). The root path (/) will usually have some useful interfaces you can poke. It's also possible to invoke methods on the services you discover: for example, here's the output of the <code>EnumerateDevices</code> method of the <code>org.freedesktop.UDisks</code> interface: |
| + | |||
| + | [[File:dbus-d-feet-execute.png|alt=Executing a method on a D-Bus service using d-feet|Executing a method on a D-Bus service using d-feet]] | ||
| + | |||
| + | To execute a method which takes parameters, specify arguments for them in Python syntax, separated by commas. For example, here's the libsocialweb <code>UpdateStatus</code> method being executed over D-Bus from d-feet: | ||
| + | |||
| + | [[File:dbus-d-feet-twitter-update.png|alt=Executing a libsocialweb method over D-Bus from d-feet|Executing a libsocialweb method over D-Bus from d-feet]] | ||
| + | |||
| + | Note that the method has two parameters which we supply with arguments: | ||
| + | |||
| + | # <code>s status_message</code>: a string representing the status update; I used "Using d-feet to invoke libsocialweb methods over D-Bus" as my status update. | ||
| + | # <code>a{ss} fields</code>: a dictionary mapping strings to strings; I used <nowiki>{}</nowiki> (no data except the update string). | ||
| + | |||
| + | For more on the valid D-Bus types, see [http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures the D-Bus specification]. | ||
| + | |||
| + | === dbus-monitor (command line) === | ||
| + | |||
| + | <code>dbus-monitor</code> is a command line tool which displays signals sent by and messages sent to a D-Bus bus. Invoke it with: | ||
| + | |||
| + | <pre> | ||
| + | dbus-monitor --system | ||
| + | </pre> | ||
| + | |||
| + | for the system bus; or with: | ||
| + | |||
| + | <pre> | ||
| + | dbus-monitor --session | ||
| + | </pre> | ||
| + | |||
| + | for the session bus (the default). | ||
| + | |||
| + | Here's the example of some output from the session bus (Banshee's media indexing back-end Tracker sending a signal to say it's going to process metadata from files; then the <code>SparqlQuery</code> method being called on Tracker): | ||
| + | |||
| + | <pre> | ||
| + | signal sender=:1.55 -> dest=(null destination) serial=204 path=/org/freedesktop/Tracker1/Miner/Files; | ||
| + | interface=org.freedesktop.Tracker1.Miner; member=Progress | ||
| + | string "Processing files" | ||
| + | double 1 | ||
| + | method call sender=:1.55 -> dest=org.freedesktop.Tracker1 serial=205 | ||
| + | path=/org/freedesktop/Tracker1/Resources; interface=org.freedesktop.Tracker1.Resources; | ||
| + | member=SparqlQuery | ||
| + | string "SELECT ?s WHERE { ?s nie:url "file:///home/meego/.recently-used.xbel.TGR7EV" }" | ||
| + | method call sender=:1.57 -> dest=org.freedesktop.DBus serial=220 path=/org/freedesktop/DBus; | ||
| + | interface=org.freedesktop.DBus; member=GetConnectionUnixProcessID | ||
| + | string ":1.55" | ||
| + | method return sender=:1.57 -> dest=:1.55 reply_serial=205 | ||
| + | array [ | ||
| + | ] | ||
| + | </pre> | ||
| + | |||
| + | It's possible to filter which signals/methods are reported, using watch expressions. Here's example from the man page for <code>dbus-monitor</code>, which tells dbus-monitor "to watch for the gnome typing monitor to say things": | ||
| + | |||
| + | <pre> | ||
| + | dbus-monitor "type=’signal’,sender=’org.gnome.TypingMonitor’,interface=’org.gnome.TypingMonitor’" | ||
| + | </pre> | ||
| + | |||
| + | === qdbus and dbus-send (command line) === | ||
| + | Qdbus and dbus-send are command line tools to send dbus messages. First on comes with qt-toolkit and later commonly with gtk. In example you can do introspect from command line like this: | ||
| + | |||
| + | <pre> | ||
| + | qdbus --system com.nokia.system_ui /com/nokia/system_ui/request org.freedesktop.DBus.Introspectable.Introspect | ||
| + | dbus-send --system --type=method_call --print-reply --dest=com.nokia.time /com/nokia/time org.freedesktop.DBus.Introspectable.Introspect | ||
| + | </pre> | ||
| + | |||
| + | Available services in system bus can be listed like this: | ||
| + | <pre> | ||
| + | qdbus --system org.freedesktop.DBus / org.freedesktop.DBus.ListNames | ||
| + | </pre> | ||
| + | |||
| + | And extra arguments, if any, are the message contents. (Parameters for the function which is called.) | ||
| + | <pre> | ||
| + | dbus-send --system --type=method_call --print-reply --dest=org.ofono /phonesim org.ofono.VoiceCallManager.Dial string:"12345678" string:""; | ||
| + | </pre> | ||
| + | |||
| + | ;Links | ||
| + | * [http://wiki.maemo.org/Phone_control Phone control with DBus] (Maemo wiki) | ||
| + | * [http://usrlocalbin.blogspot.com/2008/04/qdbus-tutorial-part-one.html Simple qdbus tutorial: part one], [http://usrlocalbin.blogspot.com/2008/04/simple-qdbus-tutorial-part-two.html part two] | ||
== Interacting with a bus programatically using high-level bindings == | == Interacting with a bus programatically using high-level bindings == | ||
| - | High level bindings for D-Bus tend to provide a mechanism for proxying remote objects: so instead of having to deal with message sending directly, objects on the bus can be proxied to local objects in the application. From there, a program can interact with objects on the bus by calling methods on the proxied object. | + | High level bindings for D-Bus tend to provide a mechanism for proxying remote objects: so instead of having to deal with message sending directly, objects on the bus can be proxied to local objects in the application. From there, a program can interact with objects on the bus by calling methods on the proxied object. D-Bus GLib provides bindings which behave this way. |
===D-Bus GLib=== | ===D-Bus GLib=== | ||
| Line 101: | Line 185: | ||
#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" | #define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager" | ||
| - | static GMainLoop *main_loop; | + | static GMainLoop *main_loop; |
static void | static void | ||
_method_call_notify_cb (DBusGProxy *proxy, | _method_call_notify_cb (DBusGProxy *proxy, | ||
| - | + | DBusGProxyCall *call, | |
| - | + | gpointer user_data) | |
{ | { | ||
| - | + | GError *error = NULL; | |
| - | + | gchar *state = NULL; | |
| - | + | dbus_g_proxy_end_call (proxy, | |
| - | + | call, | |
| - | + | &error, | |
| - | + | G_TYPE_STRING, | |
| - | + | &state, | |
| - | + | G_TYPE_INVALID); | |
| - | + | g_print ("Network state is %s\n", state); | |
| - | + | ||
| - | + | g_main_loop_quit (main_loop); | |
} | } | ||
| Line 128: | Line 211: | ||
char **argv) | char **argv) | ||
{ | { | ||
| - | + | g_type_init (); | |
| - | + | ||
| - | + | DBusGConnection *connection; | |
| - | + | DBusGProxy *proxy; | |
| - | + | main_loop = g_main_loop_new (NULL, TRUE); | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); | |
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | ||
| - | + | proxy = dbus_g_proxy_new_for_name (connection, | |
| + | CONNMAN_SERVICE, | ||
| + | CONNMAN_MANAGER_PATH, | ||
| + | CONNMAN_MANAGER_INTERFACE); | ||
| + | |||
| + | dbus_g_proxy_begin_call (proxy, | ||
| + | "GetState", | ||
| + | _method_call_notify_cb, | ||
| + | main_loop, | ||
| + | NULL, | ||
| + | G_TYPE_INVALID); | ||
| + | |||
| + | g_main_loop_run (main_loop); | ||
} | } | ||
</pre> | </pre> | ||
| + | |||
| + | === QtDBus === | ||
| + | Below is an example of using the Qt bindings to determine the online state of a MeeGo system using the D-Bus service (on the system bus) provided by the ConnMan connectivity daemon. To use QtDBus there should be qdbus defined in project file. | ||
| + | |||
| + | <pre> | ||
| + | # dbus.pro | ||
| + | |||
| + | CONFIG += qdbus | ||
| + | |||
| + | HEADERS += | ||
| + | SOURCES += main.cpp | ||
| + | </pre> | ||
| + | |||
| + | <pre> | ||
| + | /* main.cpp | ||
| + | * Uses QtDBus to ask ConnMan whether there is an active internet connection | ||
| + | * Compile with: | ||
| + | * qmake && make | ||
| + | */ | ||
| + | |||
| + | #include <QtDBus/QtDBus> | ||
| + | #include <QtDBus/qdbusreply.h> | ||
| + | #include <QtDBus/QDBusConnection> | ||
| + | |||
| + | int main(int argc, char *argv[]) | ||
| + | { | ||
| + | QDBusInterface iface("org.moblin.connman", "/", "org.moblin.connman.Manager", QDBusConnection::systemBus()); | ||
| + | QDBusMessage reply=iface.call("GetState"); | ||
| + | qDebug() << "Network state is" << reply.arguments().at(0).toString() << "\n"; | ||
| + | } | ||
| + | </pre> | ||
| + | |||
| + | ;Examples and tutorials | ||
| + | * [http://techbase.kde.org/Development/Tutorials/D-Bus KDE's DBus tutorial] | ||
| + | * [http://matgnt.wordpress.com/2010/07/19/qt-ofono-d-bus-and-qml-part-1/ Qt, Ofono, D-Bus and QML: part1], [http://matgnt.wordpress.com/2010/07/19/qt-ofono-d-bus-and-qml-part-2 part2], [http://matgnt.wordpress.com/2010/07/19/qt-ofono-d-bus-and-qml-part-3/ part3] | ||
| + | * [http://cep.xor.aps.anl.gov/software/qt4-x11-4.2.2-browser/dc/d8a/qdbus_8cpp-source.html Source code of QtDBus] | ||
| + | * [http://laurii.info/articles/2007/03/22/dbus-and-qt-programming How to send more complex data via DBus] | ||
| + | * [http://mail.gnome.org/archives/networkmanager-list/2009-November/msg00101.html Example how to parse DBus reply] | ||
Contents |
D-Bus is an Inter Process Communication (IPC) system, providing a mechanism for applications running on a single machine to "talk" to each other. Due to its focus on being a message bus for local applications, D-Bus has some nice features compared to alternative IPC mechanisms: these include the capability to autostart applications which are not active but which have been sent a message; and the ability to ensure that only a single instance of an application is ever running.
The core D-Bus protocol is a 2-way, asynchronous, binary protocol. While it is possible to use for direct application to application communication (using libdbus - not recommended), the most common usage of the protocol is via a D-Bus message bus server. The server is connected to each client using D-Bus, and routes each message from the application which sent it its intended recipient. Each application which exposes its capabilities on the bus is known as a service. (An application doesn't have to expose any services to make use of the bus: it can just send messages to other applications which do provide services.)
There are actually multiple D-Bus message buses running on MeeGo (and on your average Linux system) at any one time, of two types:
Services on a D-Bus expose a tree of objects to interact with. Each service has a root path; from the root come branches, one for each object provided by that service. Each object on a service tree is addressable by an object path.
Object paths are typically in a reverse-domain name format, akin to Java package names; for example, org.freedesktop.Tracker1 for the Tracker (content framework) root path.
Interfaces are the contract between an object and its callers, much like interfaces in Java, GObject etc.. An interface, as in most object-oriented programming environments, defines the methods and properties an object exposes. In addition, D-Bus interfaces can also contain signals. Signals provide a way for objects to notify other objects about events which happen to them: for example, a Door interface might provide a signal to other objects when it is opened, perhaps called door-opened. (A nearby Doorman object might listen out for door-opened signals, so it knows when people come into the building.)
Each D-Bus object implements one or more interfaces. Most implement two standard interfaces as a minimum, org.freedesktop.DBus.Introspectable and org.freedesktop.DBus.Properties:
Introspectable interface specifies a single method, Introspect(). Calling this method on an object returns a string of XML which defines the interfaces (and the properties, signals and methods of those interfaces) implemented by that object.
Properties interface specifies three standard methods for getting and setting an object's properties: Get(), GetAll(), and Set().
Get() takes the interface name and a property name as arguments and returns the value of the specified property.
GetAll() takes the interface name and returns a dictionary of property name to value mappings.
Set() takes the interface name, a property name and the value to set for the property as arguments.
Often the easiest way to get started investigating a service on the Bus is to use D-Feet, a graphical D-Bus debugging tool. Here's an example of it monitoring the system bus on a MeeGo netbook:
Using D-Feet, one can browse the tree of objects available for each service.
D-Feet uses the Introspect() method of the Introspection interface to determine what methods, properties and signals an object implements. It even allows execution of the available methods using a Python-like syntax for specifying arguments.
D-Feet is available in the MeeGo package repositories and can be installed with:
sudo yum install d-feet
D-Feet can be started from the command line with:
d-feet
You can then connect to either the system bus or the session bus, using the connect icon:
The address to enter depends on the bus type you want to monitor:
unix:path=/var/run/dbus/system_bus_socketYou can find the system bus path manually by grepping
/etc/dbus-1/system.conf for the <listen> setting.$env | grep DBUS_SESSION_BUS_ADDRESS
Example output:
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-6H89TrarMk,guid=a72013b7b9456e7a3eca017100000038You need the bit after the first '=' sign (starting
unix:abstract).Once you've connected to a bus, you'll get a list of bus names on the left. Click on one to see the available object paths in the right panel (see the screenshot above). The root path (/) will usually have some useful interfaces you can poke. It's also possible to invoke methods on the services you discover: for example, here's the output of the EnumerateDevices method of the org.freedesktop.UDisks interface:
To execute a method which takes parameters, specify arguments for them in Python syntax, separated by commas. For example, here's the libsocialweb UpdateStatus method being executed over D-Bus from d-feet:
Note that the method has two parameters which we supply with arguments:
s status_message: a string representing the status update; I used "Using d-feet to invoke libsocialweb methods over D-Bus" as my status update.
a{ss} fields: a dictionary mapping strings to strings; I used {} (no data except the update string).
For more on the valid D-Bus types, see the D-Bus specification.
dbus-monitor is a command line tool which displays signals sent by and messages sent to a D-Bus bus. Invoke it with:
dbus-monitor --system
for the system bus; or with:
dbus-monitor --session
for the session bus (the default).
Here's the example of some output from the session bus (Banshee's media indexing back-end Tracker sending a signal to say it's going to process metadata from files; then the SparqlQuery method being called on Tracker):
signal sender=:1.55 -> dest=(null destination) serial=204 path=/org/freedesktop/Tracker1/Miner/Files;
interface=org.freedesktop.Tracker1.Miner; member=Progress
string "Processing files"
double 1
method call sender=:1.55 -> dest=org.freedesktop.Tracker1 serial=205
path=/org/freedesktop/Tracker1/Resources; interface=org.freedesktop.Tracker1.Resources;
member=SparqlQuery
string "SELECT ?s WHERE { ?s nie:url "file:///home/meego/.recently-used.xbel.TGR7EV" }"
method call sender=:1.57 -> dest=org.freedesktop.DBus serial=220 path=/org/freedesktop/DBus;
interface=org.freedesktop.DBus; member=GetConnectionUnixProcessID
string ":1.55"
method return sender=:1.57 -> dest=:1.55 reply_serial=205
array [
]
It's possible to filter which signals/methods are reported, using watch expressions. Here's example from the man page for dbus-monitor, which tells dbus-monitor "to watch for the gnome typing monitor to say things":
dbus-monitor "type=’signal’,sender=’org.gnome.TypingMonitor’,interface=’org.gnome.TypingMonitor’"
Qdbus and dbus-send are command line tools to send dbus messages. First on comes with qt-toolkit and later commonly with gtk. In example you can do introspect from command line like this:
qdbus --system com.nokia.system_ui /com/nokia/system_ui/request org.freedesktop.DBus.Introspectable.Introspect dbus-send --system --type=method_call --print-reply --dest=com.nokia.time /com/nokia/time org.freedesktop.DBus.Introspectable.Introspect
Available services in system bus can be listed like this:
qdbus --system org.freedesktop.DBus / org.freedesktop.DBus.ListNames
And extra arguments, if any, are the message contents. (Parameters for the function which is called.)
dbus-send --system --type=method_call --print-reply --dest=org.ofono /phonesim org.ofono.VoiceCallManager.Dial string:"12345678" string:"";
High level bindings for D-Bus tend to provide a mechanism for proxying remote objects: so instead of having to deal with message sending directly, objects on the bus can be proxied to local objects in the application. From there, a program can interact with objects on the bus by calling methods on the proxied object. D-Bus GLib provides bindings which behave this way.
The D-Bus GLib bindings (yum install dbus-glib-devel) offer a high-level, GObject-like binding for interacting with the D-Bus message bus.
Below is an example of using the bindings to determine the online state of a MeeGo system using the D-Bus service (on the system bus) provided by the ConnMan connectivity daemon.
/*
* amionline.c
* Uses dbus-glib to ask ConnMan whether there is an active internet connection
* Compile with:
* gcc -o amionline amionline.c `pkg-config --libs --cflags glib-2.0 gthread-2.0 dbus-glib-1`
*/
#include <glib.h>
#include <dbus/dbus-glib.h>
#include <dbus/dbus.h>
#define CONNMAN_SERVICE "org.moblin.connman"
#define CONNMAN_MANAGER_PATH "/"
#define CONNMAN_MANAGER_INTERFACE CONNMAN_SERVICE ".Manager"
static GMainLoop *main_loop;
static void
_method_call_notify_cb (DBusGProxy *proxy,
DBusGProxyCall *call,
gpointer user_data)
{
GError *error = NULL;
gchar *state = NULL;
dbus_g_proxy_end_call (proxy,
call,
&error,
G_TYPE_STRING,
&state,
G_TYPE_INVALID);
g_print ("Network state is %s\n", state);
g_main_loop_quit (main_loop);
}
int
main (int argc,
char **argv)
{
g_type_init ();
DBusGConnection *connection;
DBusGProxy *proxy;
main_loop = g_main_loop_new (NULL, TRUE);
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL);
proxy = dbus_g_proxy_new_for_name (connection,
CONNMAN_SERVICE,
CONNMAN_MANAGER_PATH,
CONNMAN_MANAGER_INTERFACE);
dbus_g_proxy_begin_call (proxy,
"GetState",
_method_call_notify_cb,
main_loop,
NULL,
G_TYPE_INVALID);
g_main_loop_run (main_loop);
}
Below is an example of using the Qt bindings to determine the online state of a MeeGo system using the D-Bus service (on the system bus) provided by the ConnMan connectivity daemon. To use QtDBus there should be qdbus defined in project file.
# dbus.pro CONFIG += qdbus HEADERS += SOURCES += main.cpp
/* main.cpp
* Uses QtDBus to ask ConnMan whether there is an active internet connection
* Compile with:
* qmake && make
*/
#include <QtDBus/QtDBus>
#include <QtDBus/qdbusreply.h>
#include <QtDBus/QDBusConnection>
int main(int argc, char *argv[])
{
QDBusInterface iface("org.moblin.connman", "/", "org.moblin.connman.Manager", QDBusConnection::systemBus());
QDBusMessage reply=iface.call("GetState");
qDebug() << "Network state is" << reply.arguments().at(0).toString() << "\n";
}