From 11a69ec1cd26f48819ebc922a55dccea0a0eca2a Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Thu, 5 Feb 2015 12:08:03 +0000 Subject: [PATCH] doc: WIP work to add an API guidelines document This guide will give pointers on how to write D-Bus APIs which are nice to use. --- configure.ac | 21 +- doc/.gitignore | 9 + doc/Makefile.am | 30 ++- doc/dbus-api-design.duck | 504 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 558 insertions(+), 6 deletions(-) create mode 100644 doc/dbus-api-design.duck diff --git a/configure.ac b/configure.ac index 5e6f555..4f108ea 100644 --- a/configure.ac +++ b/configure.ac @@ -148,7 +148,7 @@ AC_ARG_ENABLE(ansi, AS_HELP_STRING([--enable-ansi],[enable -ansi -pedantic gcc f AC_ARG_ENABLE(verbose-mode, AS_HELP_STRING([--enable-verbose-mode],[support verbose debug mode]),enable_verbose_mode=$enableval,enable_verbose_mode=$enable_developer) AC_ARG_ENABLE(asserts, AS_HELP_STRING([--enable-asserts],[include assertion checks]),enable_asserts=$enableval,enable_asserts=$enable_developer) AC_ARG_ENABLE(checks, AS_HELP_STRING([--enable-checks],[include sanity checks on public API]),enable_checks=$enableval,enable_checks=yes) -AC_ARG_ENABLE(xml-docs, AS_HELP_STRING([--enable-xml-docs],[build XML documentation (requires xmlto)]),enable_xml_docs=$enableval,enable_xml_docs=auto) +AC_ARG_ENABLE(xml-docs, AS_HELP_STRING([--enable-xml-docs],[build XML documentation (requires xmlto, ducktype and yelp-build)]),enable_xml_docs=$enableval,enable_xml_docs=auto) AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGEN documentation (requires Doxygen)]),enable_doxygen_docs=$enableval,enable_doxygen_docs=auto) AC_ARG_ENABLE(abstract-sockets, AS_HELP_STRING([--enable-abstract-sockets],[use abstract socket namespace (linux only)]),enable_abstract_sockets=$enableval,enable_abstract_sockets=auto) AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto) @@ -1418,9 +1418,11 @@ AC_MSG_RESULT($enable_doxygen_docs) AC_CHECK_PROGS([XSLTPROC], [xsltproc]) AM_CONDITIONAL([DBUS_HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"]) -### XML Documentation +### XML and Ducktype Documentation AC_PATH_PROG(XMLTO, xmlto, no) +AC_PATH_PROG([DUCKTYPE],[ducktype],[no]) +AC_PATH_PROG([YELP_BUILD],[yelp-build],[no]) AC_MSG_CHECKING([whether to build XML documentation]) @@ -1430,8 +1432,11 @@ else have_xmlto=yes fi +AS_IF([test "$DUCKTYPE" = "no"],[have_ducktype=no],[have_ducktype=yes]) +AS_IF([test "$YELP_BUILD" = "no"],[have_yelp_build=no],[have_yelp_build=yes]) + if test x$enable_xml_docs = xauto ; then - if test x$have_xmlto = xno ; then + if test x$have_xmlto = xno -o x$have_ducktype = xno -o x$have_yelp_build = xno; then enable_xml_docs=no else enable_xml_docs=yes @@ -1442,6 +1447,12 @@ if test x$enable_xml_docs = xyes; then if test x$have_xmlto = xno; then AC_MSG_ERROR([Building XML docs explicitly required, but xmlto not found]) fi + if test x$have_ducktype = xno; then + AC_MSG_ERROR([Building XML docs explicitly required, but ducktype not found]) + fi + if test x$have_yelp_build = xno; then + AC_MSG_ERROR([Building XML docs explicitly required, but yelp-build not found]) + fi fi AM_CONDITIONAL(DBUS_XML_DOCS_ENABLED, test x$enable_xml_docs = xyes) @@ -1826,7 +1837,9 @@ echo " 32-bit int: ${DBUS_INT32_TYPE} 16-bit int: ${DBUS_INT16_TYPE} Doxygen: ${DOXYGEN:-not found} - xmlto: ${XMLTO:-not found}" + xmlto: ${XMLTO:-not found} + ducktype: ${DUCKTYPE:-not found} + yelp-build: ${YELP_BUILD:-not found}" echo " Rebuilding generated files: ${USE_MAINTAINER_MODE} diff --git a/doc/.gitignore b/doc/.gitignore index 708fe36..e1ccbc8 100644 --- a/doc/.gitignore +++ b/doc/.gitignore @@ -17,3 +17,12 @@ dbus-faq.html dbus-docs dbus-docs.tar.gz doxygen.stamp +dbus-api-design.page +dbus-api-design.html +jquery.js +jquery.syntax.brush.html.js +jquery.syntax.core.js +jquery.syntax.js +jquery.syntax.layout.yelp.js +yelp.js +C.css diff --git a/doc/Makefile.am b/doc/Makefile.am index b9a4c10..2994eca 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -30,6 +30,7 @@ STATIC_DOCS = \ dbus-specification.xml \ dbus-test-plan.xml \ dbus-tutorial.xml \ + dbus-api-design.duck \ dcop-howto.txt \ introspect.xsl \ $(DTDS) @@ -50,24 +51,47 @@ STATIC_HTML = \ diagram.svg \ $(NULL) +# Static HTML helper files generated by yelp-build. +YELP_STATIC_HTML = \ + yelp.js \ + C.css \ + jquery.js \ + jquery.syntax.js \ + jquery.syntax.brush.html.js \ + jquery.syntax.core.js \ + jquery.syntax.layout.yelp.js \ + $(NULL) + dist_html_DATA += $(STATIC_HTML) +# Content HTML files generated by yelp-build. +YELP_HTML = \ + dbus-api-design.html \ + $(NULL) + XMLTO_HTML = \ dbus-faq.html \ dbus-specification.html \ dbus-test-plan.html \ dbus-tutorial.html \ + $(YELP_HTML) \ $(MAN_HTML_FILES) \ $(NULL) if DBUS_XML_DOCS_ENABLED -html_DATA += $(XMLTO_HTML) +html_DATA += $(XMLTO_HTML) $(YELP_STATIC_HTML) %.html: %.xml $(XMLTO) html-nochunks $< %.1: %.1.xml $(XMLTO) man $< + +%.page: %.duck + $(DUCKTYPE) $< +%.html: %.page + $(YELP_BUILD) html $< +$(YELP_STATIC_HTML): $(YELP_HTML) endif if DBUS_DOXYGEN_DOCS_ENABLED @@ -112,13 +136,14 @@ BONUS_FILES = \ $(top_srcdir)/COPYING \ $(top_srcdir)/ChangeLog -dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML) +dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML) $(YELP_STATIC_HTML) $(AM_V_at)rm -rf $@ $@.tmp $(AM_V_GEN)$(MKDIR_P) $@.tmp/api $(AM_V_at)cd $(srcdir) && cp $(STATIC_DOCS) @abs_builddir@/$@.tmp $(AM_V_at)cd $(srcdir) && cp $(dist_doc_DATA) @abs_builddir@/$@.tmp $(AM_V_at)cd $(srcdir) && cp $(STATIC_HTML) @abs_builddir@/$@.tmp $(AM_V_at)cp $(XMLTO_HTML) @abs_builddir@/$@.tmp + $(AM_V_at)cp $(YELP_STATIC_HTML) @abs_builddir@/$@.tmp $(AM_V_at)cp $(MAN_HTML_FILES) @abs_builddir@/$@.tmp $(AM_V_at)cp $(MAN_XML_FILES) @abs_builddir@/$@.tmp $(AM_V_at)cp $(BONUS_FILES) @abs_builddir@/$@.tmp @@ -151,6 +176,7 @@ CLEANFILES = \ $(man1_MANS) \ $(MAN_XML_FILES) \ $(XMLTO_HTML) \ + $(YELP_STATIC_HTML) \ $(NULL) clean-local: diff --git a/doc/dbus-api-design.duck b/doc/dbus-api-design.duck new file mode 100644 index 0000000..3dfce50 --- /dev/null +++ b/doc/dbus-api-design.duck @@ -0,0 +1,504 @@ += D-Bus API Design Guidelines +@link[guide >index] +@credit[type="author copyright"] + @name Philip Withnall + @email philip.withnall@collabora.co.uk + @years 2015 +@desc Guidelines for writing high quality D-Bus APIs +@revision[date=2015-02-05 status=draft] + +[synopsis] + [title] + Summary + + The most common use for D-Bus is in implementing a service which will be + consumed by multiple client programs, and hence all interfaces exported on the + bus form a public API. Designing a D-Bus API is like designing any other API: + there is a lot of flexibility, but there are design patterns to follow and + anti-patterns to avoid. + + This guide aims to explain the best practices for writing D-Bus APIs. These + have been refined over several years of use of D-Bus in many projects. + Pointers will be given for implementing APIs using common D-Bus + libraries like + $link[>>https://developer.gnome.org/gio/stable/gdbus-convenience.html](GDBus), + but detailed implementation instructions are left to the libraries’ + documentation. Note that you should $em(not) use libdbus-1 or libdbus-glib to + implement D-Bus services, as they are awkward to use correctly, deprecated + and unmaintained. + + For documentation on D-Bus itself, see the + $link[>>http://dbus.freedesktop.org/doc/dbus-specification.html](D-Bus + specification). + +[links section] + +== APIs + [id="apis"] + +A D-Bus API is a specification of one or more interfaces, which will be +implemented by objects exposed by a service on the bus. Typically an API is +designed as a set of $link[>#interface-files](interface files), and the +implementation of the service follows those files. Some projects, however, +choose to define the API in the code for the service, and to export XML +interface files from the running service +$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable](using +D-Bus introspection). Both are valid approaches. + +For simplicity, this document uses the XML descriptions of D-Bus interfaces as +the canonical representation. + +== Interface files + [id="interface-files"] + +A D-Bus interface file is an XML file which describes one or more D-Bus +interfaces, and is the best way of describing a D-Bus API in a machine +readable way. The format is described in the +$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format](D-Bus +specification), and is supported by tools such as $cmd(gdbus-codegen). + +Interface files should be installed to $code($var($$datadir)/dbus-1/interfaces) +so that other services can load them. There should be one file installed +per D-Bus interface, named after the interface, containing a single top-level +$code() element with a single $code() beneath it. For example, +interface $code(org.example.MyService1.Manager) would be described by file +$file($var($$datadir)/dbus-1/interfaces/org.example.MyService1.Manager.xml): + +[listing] + [title] + Example D-Bus Interface XML + [desc] + A brief example interface XML document. + [code mime="application/xml"] + + + + + + Name of new contact + + + E-mail address of new contact + + + ID of newly added contact + + + + + Adds a new contact to the address book with their name and + e-mail address. + + + + + + + +If an interface defined by service A needs to be used by client B, client B +should declare a build time dependency on service A, and use the installed copy +of the interface file for any code generation it has to do. It should $em(not) +have a local copy of the interface, as that could then go out of sync with the +canonical copy in service A’s git repository. + +== API versioning + [id="api-versioning"] + +$link[>>http://ometer.com/parallel.html](Just like C APIs), D-Bus interfaces +should be designed to be usable in parallel with API-incompatible versions. This +is achieved by including a version number in each interface name, service name +and object path which is incremented on every backwards-incompatible change. + +Version numbers should be included in all APIs from the first release, as that +means moving to a new version is as simple as incrementing the number, rather +than inserting a number everywhere, which takes more effort. + +New API can be added to a D-Bus interface without incrementing the version +number, as such additions are still backwards-compatible. However, clients +should gracefully handle the $code(org.freedesktop.DBus.Error.UnknownMethod) +error reply from all D-Bus method calls so that they can run against older +versions of the service which don’t implement new methods. + +When API is broken, changed or removed, the service’s version number must be +bumped; for example, from $code(org.example.MyService1) +to $code(org.example.MyService2). If backwards compatibility is maintained in +the service by implementing both the old and new interfaces, the service can +own $em(both) well-known names and clients can use whichever they support. + +Note, however, that supporting multiple interface versions simultaneously +requires that $em(object paths) are versioned as well, so objects $em(must not) +be put on the bus at the root path (‘/’). This is for technical reasons: signals +sent from a D-Bus service have the originating service name overwritten by its +unique name (e.g. $code(org.example.MyService2) is overwritten by $code(:1:15)). +If object paths are shared between objects implementing two versions of the +service’s interface, client programs cannot tell which object a signal has come +from. The solution is to include the version number in all object paths, for +example $code(/org/example/MyService1/Manager) instead of $code(/) or +$code(/org/example/MyService/Manager). + +In summary, version numbers should be included in all service names, interface +names and object paths: +[list] +* $code(org.example.MyService1) +* $code(org.example.MyService1.InterestingInterface) +* $code(org.example.MyService1.OtherInterface) +* $code(/org/example/MyService1/Manager) +* $code(/org/example/MyService1/OtherObject) + +== API design + [id="api-design"] + +D-Bus API design is broadly the same as C API design, but there are a few +additional points to bear in mind which arise both from D-Bus’ features +(explicit errors, signals and properties), and from its implementation as an IPC +system. + +D-Bus method calls are much more expensive than C function calls, typically +taking on the order of milliseconds to complete a round trip. Therefore, the +design should minimize the number of method calls needed to perform an +operation. + +The type system is very expressive, especially compared to C’s, and APIs should +take full advantage of it. + +Similarly, its support for signals and properties differentiates it from normal +C APIs, and well written D-Bus APIs make full use of these features where +appropriate. They can be coupled with standard interfaces defined in the D-Bus +specification to allow for consistent access to properties and objects in a +hierarchy. + +=== Minimizing Round Trips + [id="round-trips"] + +Each D-Bus method call is a round trip from a client program to a service and +back again, which is expensive — taking on the order of a millisecond. One of +the top priorities in D-Bus API design is to minimize the number of round trips +needed by clients. This can be achieved by a combination of providing specific +convenience APIs and designing APIs which operate on large data sets in a single +call, rather than requiring as many calls as elements in the data set. + +Consider an address book API, $code(org.example.MyService1.AddressBook). It +might have an $code(AddContact(ss) → (u)) method to add a contact (taking name +and e-mail address parameters and returning a unique contact ID), and a +$code(RemoveContact(u)) method to remove one by ID. In the normal case of +operating on single contacts in the address book, these calls are optimal. +However, if the user wants to import a list of contacts, or delete multiple +contacts simultaneously, one call has to be made per contact — this could take +a long time for large contact lists. + +Instead of the $code(AddContact) and $code(RemoveContact) methods, the interface +could have an $code(UpdateContacts(a(ss)au) → (au)) method, which takes an array +of structs containing the new contacts’ details, and an array of IDs of the +contacts to delete, and returns an array of IDs for the new contacts. This +reduces the number of round trips needed to one. + +Adding convenience APIs to replace a series of common method calls with a single +method call specifically for that task is best done after the API has been +profiled and bottlenecks identified, otherwise it could lead to premature +optimization. One area where convenience methods can typically be added +is during initialization of a client, where multiple method calls are needed to +establish its state with the service. + +=== Taking Advantage of the Type System + [id="type-system"] + +D-Bus’ type system is similar to Python’s, but with a terser syntax which may be +unfamiliar to C developers. The key to using the type system effectively is +to expose as much structure in types as possible. In particular, sending +structured strings over D-Bus should be avoided, as they need to be built and +parsed; both are complex operations which are prone to bugs. + +A common, useful approach is to use enumerated values transmitted as unsigned +integers over the bus, with the interface documentation describing what each +value means, and how unrecognized values should be handled. This allows for +extra values to be added in future without breaking API. Integers are better +than strings in this case as they do not require parsing or string matching when +received, and are more compact. + +Similarly, enumerated values should be used instead of booleans, as they allow +extra values to be added in future, and there is no ambiguity about the sense of +the boolean value. + +Enumerated values should also be used instead of $em(human readable) strings, +which should not be sent over the bus if possible. The service and client could +be running in different locales, and hence interpret any human readable strings +differently, or present them to the user in the wrong language. Transmit an +enumerated value and convert it to a human readable string in the client. + +D-Bus has none of the problems of signed versus unsigned integers which C has +(specifically, it does not do implicit sign conversion), so integer types should +always be chosen to be an appropriate size and signedness for the data they +could possibly contain. + +Structures can be used almost anywhere in a D-Bus type, and arrays of structures +are particularly useful. Structures should be used wherever data fields are +related. For example, if there are several identically-indexed arrays +containing different properties of the same set of items (e.g. $code((asasau))), +they can be combined to a single array of structures of those properties (e.g. +$code(a(ssu))). + +Note that D-Bus arrays are automatically transmitted with their length, so there +is no need to null-terminate them or encode their length separately. + +FIXME: Should we mention maybe types and the kdbus/GVariant type system? +FIXME: Examples + +=== Using Signals, Properties and Errors + [id="using-the-features"] + +D-Bus method calls are explicitly asynchronous due to the latency inherent in +IPC. This means that peers should not block on receiving a reply from a method +call; they should schedule other work (in a main loop) and handle the reply when +it is received. Even though method replies may take a while, the caller is +$em(guaranteed) to receive exactly one reply eventually. This reply could be the +return value from the method, an error from the method, or an error from the +D-Bus daemon indicating the service failed in some way (e.g. due to crashing). + +Because of this, service implementations should be careful to always reply +exactly once to each method call. Replying at the end of a long-running +operation is correct — the client will patiently wait until the operation has +finished and the reply is received. + +An anti-pattern to avoid in this situation is to start a long-running operation +when a method call is received, then to never reply to the method call and +instead notify the client of completion of the operation via a signal. This +approach is incorrect as signal emissions do not have a one-to-one relationship +with method calls — the signal could theoretically be emitted multiple times, or +never, which the client would not be able to handle. + +Similarly, use a D-Bus error reply to signify failure of an operation triggered +by a method call, rather than using a custom error code in the method’s +reply. This means that a reply always indicates success, and an error always +indicates failure — rather than a reply indicating either depending on its +parameters, and having to return dummy values in the other parameters. Using +D-Bus error replies also means such failures can be highlighted in debugging +tools, simplifying debugging. + +=== Using Standard Interfaces + [id="standard-interfaces"] + +Use standard D-Bus interfaces where possible. The D-Bus specification defines +the +$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties]($code(org.freedesktop.DBus.Properties)) +interface, which should be used by all objects to notify clients of changes +to their property values, with the $code(PropertiesChanged) signal. This signal +eliminates the need for individual $code($var(PropertyName)Changed) signals, and +allows multiple properties to be notified in a single signal emission, reducing +IPC round trips. Similarly, the $code(Get) and $code(Set) methods can be used to +manipulate properties on an object, eliminating redundant +$code(Get$var(PropertyName)) and $code(Set$var(PropertyName)) methods. + +The specification also defines the +$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager]($code(org.freedesktop.DBus.ObjectManager)) +interface, which should be used whenever a service needs to expose a variable +number of objects of the same class in a flat or tree-like structure. For +example, this could be used by an address book service which exposes multiple +address books, each as a separate object. The $code(GetManagedObjects) method +allows the full object tree to be queried, returning all the objects’ properties +too, eliminating the need for further IPC round trips to query the properties. + +FIXME: Add examples. + +=== Naming Conventions + [id="naming-conventions"] + +All D-Bus names, from service names through to method parameters, follow a set +of conventions. Following these conventions makes APIs more natural to use and +consistent with all other services on the system. + +Almost all names use camel case with no underscores, as in the examples below. +Method and signal parameters are an exception, using +$code(lowercase_with_underscores). Type information is never encoded in the +parameter name (i.e. $em(not) +$link[>>http://en.wikipedia.org/wiki/Hungarian_notation](Hungarian notation)). + +[terms] +- Service Name +* $code(org.example.MyService1) +- Interface Name +* $code(org.example.MyService1.SomeInterface) +- Object Path (Root Object) +* $code(/org/example/MyService1) +- Object Path (Child Object) +* $code(/org/example/MyService1/SomeChild) +- Object Path (Grandchild Object) +* $code(/org/example/MyService1/AnotherChild/Grandchild1) +- Method Name +* $code(org.example.MyService1.SomeInterface.MethodName) +- Signal Name +* $code(org.example.MyService1.SomeInterface.SignalName) +- Property Name +* $code(org.example.MyService1.SomeInterface.PropertyName) + +See also: $link[>#api-versioning]. + +== Code generation + [id="code-generation"] + +Rather than manually implementing both the server and client sides of a D-Bus +interface, it is often easier to write the interface XML description and use a +tool such as +$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)) +to generate type-safe C APIs, then build the implementation using those. This +avoids the tedious and error-prone process of writing code to build and read +D-Bus parameter variants for each method call. + +Use of code generators is beyond the scope of this guide; for more information, +see the +$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen) +manual). + +== Documentation + [id="documentation"] + +FIXME: Use http://www.freedesktop.org/dbus/1.0/doc.dtd instead? + +Also just like C APIs, D-Bus APIs must be documented. The D-Bus interface XML +format supports inline documentation for each method, property and signal, added +as XML comments. There is no standard syntax for these comments; +$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)), +the main tool for extracting and formatting such comments, expects them to be in +$link[>>https://developer.gnome.org/gtk-doc-manual/stable/documenting_syntax.html.en](gtk-doc +format). For example: + +[listing] + [title] + Documentation Comments in D-Bus Interface XML + [desc] + Example gtk-doc–style documentation comments in the introspection XML for + the $code(org.freedesktop.DBus.Properties) interface. + [code mime="application/xml"] + + + + + + + + + + + + + + + + + +Using $cmd(gdbus-codegen), these comments can be extracted, converted to DocBook +format and included in the project’s API manual. + +== Service files + [id="service-files"] + +Each D-Bus service must install a $file(.service) file describing its service +name and the command to run to start the service. This allows for service +activation (see the +$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-starting-services](D-Bus +specification)). + +Service files must be named after the service’s well-known name, for example +file $file(org.example.MyService1.service) for well-known name +$code(org.example.MyService1). Files must be installed in +$file($$(datadir)/dbus-1/services) for the session bus and +$file($$(datadir)/dbus-1/system-services) for the system bus. Note, however, +that services on the system bus almost always need a +$link[>#security-policies](security policy) as well. + +== Security Policies + [id="security-policies"] + +Full coverage of securing D-Bus services is beyond the scope of this guide, +however there are some steps which you can take when designing an API to ease +security policy implementation. + +D-Bus security policies use an allow/deny model, where each message (method +call, signal emission, etc.) can be allowed or denied according to the sum of +all policy rules which match it. When designing an API, bear in mind the need to +write such a security policy, and consider splitting up methods or providing +more restricted versions which accept constrained parameters, so that they +can be exposed with less restrictive security policies if needed by less trusted +clients. + +Secondly, the default D-Bus security policy is restrictive enough to allow +sensitive data, such as passwords, to be safely sent over the bus in unicast +messages (including unicast signals); so there is no need to complicate APIs by +implementing extra security. Note, however, that sensitive data must $em(not) be +sent in broadcast signals, as they can be seen by all peers on the bus. + +== Debugging + [id="debugging"] + +Debugging services running on D-Bus can be tricky, especially if they are +launched via service activation and hence in an environment out of your control. + +Three main tools are available: D-Bus Monitor, Bustle and D-Feet. + +=== D-Bus Monitor + [id="dbus-monitor"] + +$link[>>http://dbus.freedesktop.org/doc/dbus-monitor.1.html]($cmd(dbus-monitor)) +is a core D-Bus tool, and allows eavesdropping on the session or system bus, +printing all messages it sees. The messages may be filtered using a standard +$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-routing-match-rules](D-Bus +match rule) to make the stream more manageable. + +Previous versions of D-Bus have required the bus’ security policy to be manually +relaxed to allow eavesdropping on all messages, especially on the system bus. +This meant that debugging the system bus was difficult and insecure. The latest +versions of D-Bus add support for monitor-only connections for the root user, +which means that $cmd(dbus-monitor) can be run as root to painlessly monitor all +messages on the system bus without modifying its security policy. + +=== Bustle + [id="bustle"] + +$link[>>http://willthompson.co.uk/bustle/](Bustle) is a graphical version of +$cmd(dbus-monitor), with a UI focused on profiling D-Bus performance by plotting +messages on a timeline. It is ideal for finding bottlenecks in IPC performance +between a service and client. + +=== D-Feet + [id="d-feet"] + +$link[>>https://wiki.gnome.org/Apps/DFeet](D-Feet) is an introspection tool for +D-Bus, which displays all peers on the bus graphically, with their objects, +interfaces, methods, signals and properties listed for examination. It is useful +for debugging all kinds of issues related to presence of services on the bus +and the objects they expose. -- 1.9.3