summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/Makefile.am36
-rw-r--r--doc/Makefile.in50
-rw-r--r--doc/busconfig.dtd7
-rw-r--r--doc/dbus-api-design.duck888
-rw-r--r--doc/dbus-daemon.1.xml.in56
-rw-r--r--doc/dbus-specification.xml70
-rw-r--r--doc/dbus-test-tool.1.xml.in325
7 files changed, 1418 insertions, 14 deletions
diff --git a/doc/Makefile.am b/doc/Makefile.am
index b9a4c106..f875dc25 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -7,6 +7,7 @@ man_pages = \
dbus-monitor.1 \
dbus-run-session.1 \
dbus-send.1 \
+ dbus-test-tool.1 \
dbus-uuidgen.1 \
$(NULL)
@@ -30,6 +31,7 @@ STATIC_DOCS = \
dbus-specification.xml \
dbus-test-plan.xml \
dbus-tutorial.xml \
+ dbus-api-design.duck \
dcop-howto.txt \
introspect.xsl \
$(DTDS)
@@ -50,8 +52,24 @@ 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 \
@@ -84,6 +102,16 @@ dbus.devhelp: $(srcdir)/doxygen_to_devhelp.xsl doxygen.stamp
$(XSLTPROC) -o $@ $< api/xml/index.xml
endif
+if DBUS_DUCKTYPE_DOCS_ENABLED
+html_DATA += $(YELP_HTML) $(YELP_STATIC_HTML)
+
+%.page: %.duck
+ $(DUCKTYPE) -o $@ $<
+%.html: %.page
+ $(YELP_BUILD) html $<
+$(YELP_STATIC_HTML): $(YELP_HTML)
+endif
+
# this assumes CREATE_SUBDIRS isn't set to YES in Doxyfile
# (which it isn't currently)
install-data-local:: doxygen.stamp
@@ -112,13 +140,15 @@ 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_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_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
@@ -142,7 +172,7 @@ maintainer-upload-docs: dbus-docs.tar.gz dbus-docs
else
maintainer-upload-docs:
@echo "Can't upload documentation! Re-run configure with"
- @echo " --enable-doxygen-docs --enable-xml-docs"
+ @echo " --enable-doxygen-docs --enable-xml-docs --enable-ducktype-docs"
@echo "and ensure that man2html is installed."
@false
endif
@@ -151,6 +181,8 @@ CLEANFILES = \
$(man1_MANS) \
$(MAN_XML_FILES) \
$(XMLTO_HTML) \
+ $(YELP_HTML) \
+ $(YELP_STATIC_HTML) \
$(NULL)
clean-local:
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 412da9bc..ab554382 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -80,14 +80,16 @@ build_triplet = @build@
host_triplet = @host@
@DBUS_XML_DOCS_ENABLED_TRUE@am__append_1 = $(XMLTO_HTML)
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@am__append_2 = dbus.devhelp
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@am__append_3 = $(YELP_HTML) $(YELP_STATIC_HTML)
subdir = doc
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
$(srcdir)/dbus-cleanup-sockets.1.xml.in \
$(srcdir)/dbus-daemon.1.xml.in $(srcdir)/dbus-launch.1.xml.in \
$(srcdir)/dbus-monitor.1.xml.in \
$(srcdir)/dbus-run-session.1.xml.in \
- $(srcdir)/dbus-send.1.xml.in $(srcdir)/dbus-uuidgen.1.xml.in \
- $(dist_doc_DATA) $(dist_html_DATA) TODO
+ $(srcdir)/dbus-send.1.xml.in $(srcdir)/dbus-test-tool.1.xml.in \
+ $(srcdir)/dbus-uuidgen.1.xml.in $(dist_doc_DATA) \
+ $(dist_html_DATA) TODO
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
$(top_srcdir)/m4/compiler.m4 $(top_srcdir)/m4/libtool.m4 \
@@ -102,7 +104,7 @@ mkinstalldirs = $(install_sh) -d
CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES = dbus-cleanup-sockets.1.xml dbus-daemon.1.xml \
dbus-launch.1.xml dbus-monitor.1.xml dbus-run-session.1.xml \
- dbus-send.1.xml dbus-uuidgen.1.xml
+ dbus-send.1.xml dbus-test-tool.1.xml dbus-uuidgen.1.xml
CONFIG_CLEAN_VPATH_FILES =
AM_V_P = $(am__v_P_@AM_V@)
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -162,6 +164,8 @@ ACLOCAL = @ACLOCAL@
ADT_LIBS = @ADT_LIBS@
AMTAR = @AMTAR@
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPARMOR_CFLAGS = @APPARMOR_CFLAGS@
+APPARMOR_LIBS = @APPARMOR_LIBS@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
@@ -216,6 +220,7 @@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
DOXYGEN = @DOXYGEN@
DSYMUTIL = @DSYMUTIL@
+DUCKTYPE = @DUCKTYPE@
DUMPBIN = @DUMPBIN@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
@@ -305,6 +310,7 @@ X_CFLAGS = @X_CFLAGS@
X_EXTRA_LIBS = @X_EXTRA_LIBS@
X_LIBS = @X_LIBS@
X_PRE_LIBS = @X_PRE_LIBS@
+YELP_BUILD = @YELP_BUILD@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@@ -372,6 +378,7 @@ man_pages = \
dbus-monitor.1 \
dbus-run-session.1 \
dbus-send.1 \
+ dbus-test-tool.1 \
dbus-uuidgen.1 \
$(NULL)
@@ -390,6 +397,7 @@ STATIC_DOCS = \
dbus-specification.xml \
dbus-test-plan.xml \
dbus-tutorial.xml \
+ dbus-api-design.duck \
dcop-howto.txt \
introspect.xsl \
$(DTDS)
@@ -399,7 +407,7 @@ EXTRA_DIST = \
doxygen_to_devhelp.xsl \
$(STATIC_DOCS)
-html_DATA = $(am__append_1) $(am__append_2)
+html_DATA = $(am__append_1) $(am__append_2) $(am__append_3)
dist_html_DATA = $(STATIC_HTML)
# diagram.png/diagram.svg aren't really HTML, but must go in the same
@@ -409,6 +417,24 @@ 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)
+
+
+# Content HTML files generated by yelp-build.
+YELP_HTML = \
+ dbus-api-design.html \
+ $(NULL)
+
XMLTO_HTML = \
dbus-faq.html \
dbus-specification.html \
@@ -433,6 +459,8 @@ CLEANFILES = \
$(man1_MANS) \
$(MAN_XML_FILES) \
$(XMLTO_HTML) \
+ $(YELP_HTML) \
+ $(YELP_STATIC_HTML) \
$(NULL)
all: all-am
@@ -480,6 +508,8 @@ dbus-run-session.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-run-session
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
dbus-send.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-send.1.xml.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+dbus-test-tool.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-test-tool.1.xml.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
dbus-uuidgen.1.xml: $(top_builddir)/config.status $(srcdir)/dbus-uuidgen.1.xml.in
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
@@ -774,6 +804,12 @@ uninstall-man: uninstall-man1
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@dbus.devhelp: $(srcdir)/doxygen_to_devhelp.xsl doxygen.stamp
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_HAVE_XSLTPROC_TRUE@ $(XSLTPROC) -o $@ $< api/xml/index.xml
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@%.page: %.duck
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@ $(DUCKTYPE) -o $@ $<
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@%.html: %.page
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@ $(YELP_BUILD) html $<
+@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@@DBUS_DUCKTYPE_DOCS_ENABLED_TRUE@$(YELP_STATIC_HTML): $(YELP_HTML)
+
# this assumes CREATE_SUBDIRS isn't set to YES in Doxyfile
# (which it isn't currently)
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@install-data-local:: doxygen.stamp
@@ -792,13 +828,15 @@ uninstall-man: uninstall-man1
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rmdir --ignore-fail-on-non-empty $(DESTDIR)$(apidir) || \
@DBUS_DOXYGEN_DOCS_ENABLED_TRUE@ rmdir $(DESTDIR)$(apidir)
-@DBUS_CAN_UPLOAD_DOCS_TRUE@dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML)
+@DBUS_CAN_UPLOAD_DOCS_TRUE@dbus-docs: $(STATIC_DOCS) $(MAN_XML_FILES) $(dist_doc_DATA) $(dist_html_DATA) $(MAN_HTML_FILES) $(BONUS_FILES) doxygen.stamp $(XMLTO_HTML) $(YELP_HTML) $(YELP_STATIC_HTML)
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)rm -rf $@ $@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_GEN)$(MKDIR_P) $@.tmp/api
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(STATIC_DOCS) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(dist_doc_DATA) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cd $(srcdir) && cp $(STATIC_HTML) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(XMLTO_HTML) @abs_builddir@/$@.tmp
+@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(YELP_HTML) @abs_builddir@/$@.tmp
+@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(YELP_STATIC_HTML) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(MAN_HTML_FILES) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(MAN_XML_FILES) @abs_builddir@/$@.tmp
@DBUS_CAN_UPLOAD_DOCS_TRUE@ $(AM_V_at)cp $(BONUS_FILES) @abs_builddir@/$@.tmp
@@ -815,7 +853,7 @@ uninstall-man: uninstall-man1
@DBUS_CAN_UPLOAD_DOCS_TRUE@ cd $(srcdir) && scp -p $(DTDS) $(SPECIFICATION_SERVER):$(SPECIFICATION_PATH)/
@DBUS_CAN_UPLOAD_DOCS_FALSE@maintainer-upload-docs:
@DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo "Can't upload documentation! Re-run configure with"
-@DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo " --enable-doxygen-docs --enable-xml-docs"
+@DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo " --enable-doxygen-docs --enable-xml-docs --enable-ducktype-docs"
@DBUS_CAN_UPLOAD_DOCS_FALSE@ @echo "and ensure that man2html is installed."
@DBUS_CAN_UPLOAD_DOCS_FALSE@ @false
diff --git a/doc/busconfig.dtd b/doc/busconfig.dtd
index 0cc519b4..8c5ac334 100644
--- a/doc/busconfig.dtd
+++ b/doc/busconfig.dtd
@@ -11,7 +11,8 @@
include |
policy |
limit |
- selinux)*>
+ selinux |
+ apparmor)*>
<!ELEMENT user (#PCDATA)>
<!ELEMENT listen (#PCDATA)>
@@ -63,3 +64,7 @@
<!ATTLIST associate
own CDATA #REQUIRED
context CDATA #REQUIRED>
+
+<!ELEMENT apparmor EMPTY>
+<!ATTLIST apparmor
+ mode (required|enabled|disabled) "enabled">
diff --git a/doc/dbus-api-design.duck b/doc/dbus-api-design.duck
new file mode 100644
index 00000000..be3ea9fd
--- /dev/null
+++ b/doc/dbus-api-design.duck
@@ -0,0 +1,888 @@
+= 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 dbus-glib to implement D-Bus
+ services as it is deprecated and unmaintained. Most services should also avoid
+ libdbus (dbus-1), which is a low-level library and is awkward to use
+ correctly: it is designed to be used via a language binding such as
+ $link[>>http://qt-project.org/doc/qt-4.8/qtdbus.html](QtDBus).
+
+ 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 for public API should be installed to
+$code($var($$(datadir$))/dbus-1/interfaces) so that other services can load
+them. Private APIs should not be installed. There should be one file installed
+per D-Bus interface, named after the interface, containing a single top-level
+$code(<node>) element with a single $code(<interface>) beneath it. For example,
+interface $code(com.example.MyService1.Manager) would be described by file
+$file($var($$(datadir$))/dbus-1/interfaces/com.example.MyService1.Manager.xml):
+
+[listing]
+ [title]
+ Example D-Bus Interface XML
+ [desc]
+ A brief example interface XML document.
+ [code mime="application/xml"]
+ <!DOCTYPE node PUBLIC
+ "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" >
+ <node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
+ <interface name="com.example.MyService1.InterestingInterface">
+ <method name="AddContact">
+ <arg name="name" direction="in" type="s">
+ <doc:doc><doc:summary>Name of new contact</doc:summary></doc:doc>
+ </arg>
+ <arg name="email" direction="in" type="s">
+ <doc:doc><doc:summary>E-mail address of new contact</doc:summary></doc:doc>
+ </arg>
+ <arg name="id" direction="out" type="u">
+ <doc:doc><doc:summary>ID of newly added contact</doc:summary></doc:doc>
+ </arg>
+ <doc:doc>
+ <doc:description>
+ <doc:para>
+ Adds a new contact to the address book with their name and
+ e-mail address.
+ </doc:para>
+ </doc:description>
+ </doc:doc>
+ </method>
+ </interface>
+ </node>
+
+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 if they want to run against older
+versions of the service which don’t implement new methods. (This also prevents
+use of generated bindings; any method which a client wants to gracefully fall
+back from should be called using a generic D-Bus method invocation rather than
+a specific generated binding.)
+
+When API is broken, changed or removed, the service’s version number must be
+bumped; for example, from $code(com.example.MyService1)
+to $code(com.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.
+
+As discussed in $link[>#annotations], new or deprecated APIs should be marked in
+the interface XML using annotations.
+
+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(com.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(/com/example/MyService1/Manager) instead of $code(/) or
+$code(/com/example/MyService/Manager).
+
+In summary, version numbers should be included in all service names, interface
+names and object paths:
+[list]
+* $code(com.example.MyService1)
+* $code(com.example.MyService1.InterestingInterface)
+* $code(com.example.MyService1.OtherInterface)
+* $code(/com/example/MyService1/Manager)
+* $code(/com/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(com.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.
+
+For APIs being used in constrained situations, enumerated values should be
+transmitted as unsigned integers. For APIs which need to be extended by third
+parties or which are used in more loosely coupled systems, enumerated values
+should be strings in some defined format.
+
+Transmitting values as integers means string parsing and matching can be
+avoided, the messages are more compact, and typos can be more easily avoided by
+developers (if, for example, C enums are used in the implementation).
+
+Transmitting values as strings means additional values can be defined by third
+parties without fear of conflicting over integer values; for instance by using
+the same reverse-domain-name namespacing as D-Bus interfaces.
+
+In both cases, the interface documentation should describe the meaning of each
+value. It should state whether the type can be extended in future and, if so,
+how the service and client should handle unrecognized values — typically by
+considering them equal to an ‘unknown’ or ‘failure’ value. Conventionally, zero
+is used as the ‘unknown’ value.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ Status:
+
+ Status of the object.
+ Valid statuses: ‘unknown’, ‘ready’, ‘complete’.
+ -->
+ <property name="Status" type="s" access="read" />
+
+ Use:
+ [code style="valid" mime="application/xml"]
+ <!--
+ Status:
+
+ Status of the object.
+ Valid statuses: 0 = Unknown, 1 = Ready, 2 = Complete.
+ Unrecognized statuses should be considered equal to Unknown.
+ -->
+ <property name="Status" type="u" access="read" />
+
+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.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ MoveAddressBook:
+ @direction: %TRUE to move it up in the list, %FALSE to move it down
+
+ Move this address book up or down in the user’s list of address books.
+ Higher address books have their contacts displayed first in search
+ results.
+ -->
+ <method name="MoveAddressBook">
+ <arg name="direction" type="b" direction="in" />
+ </method>
+
+ Be more explicit than a boolean:
+ [code style="valid" mime="application/xml"]
+ <!--
+ MoveAddressBook:
+ @direction: 0 = Move it up in the list, 1 = Move it down
+
+ Move this address book up or down in the user’s list of address books.
+ Higher address books have their contacts displayed first in search
+ results.
+
+ Unrecognized enum values for @direction will result in the address book
+ not moving.
+ -->
+ <method name="MoveAddressBook">
+ <arg name="direction" type="u" direction="in" />
+ </method>
+
+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.
+
+In situations where a service has received a human readable string from
+somewhere else, it should pass it on unmodified to the client, ideally with its
+locale alongside. Passing human readable information to a client is better than
+passing nothing.
+
+[example]
+ For example, instead of:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ ProgressNotification:
+ @progress_message: Human readable progress message string.
+
+ Emitted whenever significant progress is made with some example
+ operation. The @progress_message can be displayed in a UI dialogue to
+ please the user.
+ -->
+ <signal name="ProgressNotification">
+ <arg name="progress_message" type="s" />
+ </method>
+
+ The progress should be reported as an enumerated value:
+ [code style="valid" mime="application/xml"]
+ <!--
+ ProgressNotification:
+ @progress_state: 0 = Preparing, 1 = In progress, 2 = Finished
+
+ Emitted whenever significant progress is made with some example
+ operation. The @progress_state is typically converted to a human readable
+ string and presented to the user. Unrecognized @progress_state values
+ should be treated as state 1, in progress.
+ -->
+ <signal name="ProgressNotification">
+ <arg name="progress_state" type="u" />
+ </method>
+
+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. Typically, unsigned values are more frequently needed
+than signed values.
+
+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. Note, however, that structures are not extensible in future, so always
+consider $link[>#extensibility].
+
+[example]
+ For example, instead of several identically-indexed arrays containing
+ different properties of the same set of items:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ AddContacts:
+ @names: Array of contact names to add.
+ @emails: Corresponding array of contact e-mail addresses.
+ @ids: Returned array of the IDs of the new contacts. This will be the
+ same length as @names.
+
+ Add zero or more contacts to the address book, using their names and
+ e-mail addresses. @names and @emails must be the same length.
+ -->
+ <method name="AddContacts">
+ <arg name="names" type="as" direction="in" />
+ <arg name="emails" type="as" direction="in" />
+ <arg name="ids" type="au" direction="out" />
+ </method>
+
+ The arrays can be combined into a single array of structures:
+ [code style="invalid" mime="application/xml"]
+ <!--
+ AddContacts:
+ @details: Array of (contact name, contact e-mail address) to add.
+ @ids: Returned array of the IDs of the new contacts. This will be the
+ same length as @details.
+
+ Add zero or more contacts to the address book, using their names and
+ e-mail addresses.
+ -->
+ <method name="AddContacts">
+ <arg name="details" type="a(ss)" direction="in" />
+ <arg name="ids" type="au" direction="out" />
+ </method>
+
+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.
+
+[comment]
+ FIXME: Mention maybe types and the extended kdbus/GVariant type system once
+ that’s stable and round-trip-ability is no longer a concern.
+
+=== Extensibility
+ [id="extensibility"]
+
+Some D-Bus APIs have very well-defined use cases, and will never need extension.
+Others are used in more loosely coupled systems which may change over time, and
+hence should be designed to be extensible from the beginning without the need
+to break API in future. This is a trade off between having a more complex API,
+and being able to easily extend it in future.
+
+The key tool for extensibility in D-Bus is $code(a{sv}), the dictionary mapping
+strings to variants. If well-defined namespaced strings are used as the
+dictionary keys, arbitrary D-Bus peers can add whatever information they need
+into the dictionary. Any other peer which understands it can query and retrieve
+the information; other peers will ignore it.
+
+The canonical example of an extensible API using $code(a{sv}) is
+$link[>>http://telepathy.freedesktop.org/spec/](Telepathy). It uses $code(a{sv})
+values as the final element in structures to allow them to be extended in
+future.
+
+A secondary tool is the use of flag fields in method calls. The set of accepted
+flags is entirely under the control of the interface designer and, as with
+enumerated types, can be extended in future without breaking API. Adding more
+flags allows the functionality of the method call to be tweaked.
+
+=== 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.
+
+Note that D-Bus client bindings may implement synthetic timeouts of several
+tens of seconds, unless explicitly disabled for a call. For very long-running
+operations, you should disable the client bindings’ timeout and make it clear
+in the client’s UI that the application has not frozen and is simply running a
+long operation.
+
+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.
+
+Clients should handle all possible standard and documented D-Bus errors for each
+method call. IPC inherently has more potential failures than normal C function
+calls, and clients should be prepared to handle all of them gracefully.
+
+=== Using Standard Interfaces
+ [id="standard-interfaces"]
+
+Use standard D-Bus interfaces where possible.
+
+==== Properties
+ [id="interface-properties"]
+
+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.
+
+[example]
+ For example, consider an object implementing an interface
+ $code(com.example.MyService1.SomeInterface) with methods:
+ [list]
+ * $code(GetName($) → (s$))
+ * $code(SetName(s$) → ($))
+ * $code(GetStatus($) → (u$))
+ * $code(RunOperation(ss$) → (u$))
+ and signals:
+ [list]
+ * $code(NameChanged(u$))
+ * $code(StatusChanged(u$))
+
+ The interface could be cut down to a single method:
+ [list]
+ * $code(RunOperation(ss$) → (u$))
+ The object could then implement the $code(org.freedesktop.DBus.Properties)
+ interface and define properties:
+ [list]
+ * $code(Name) of type $code(s), read–write
+ * $code(Status) of type $code(u), read-only
+
+ The $code(NameChanged) and $code(StatusChanged) signals would be replaced by
+ $code(org.freedesktop.DBus.Properties.PropertiesChanged).
+
+==== Object Manager
+ [id="interface-object-manager"]
+
+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, and
+clients are expected to be interested in most or all of the objects. 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.
+
+If clients are not expected to be interested in most of the exposed objects,
+$code(ObjectManager) should $em(not) be used, as it will send all of the objects
+to each client anyway, wasting bus bandwidth. A file manager, therefore, should
+not expose the entire file system hierarchy using $code(ObjectManager).
+
+[example]
+ For example, consider an object implementing an interface
+ $code(com.example.MyService1.AddressBookManager) with methods:
+ [list]
+ * $code(GetAddressBooks($) → (ao$))
+ and signals:
+ [list]
+ * $code(AddressBookAdded(o$))
+ * $code(AddressBookRemoved(o$))
+
+ If the manager object is at path
+ $code(/com/example/MyService1/AddressBookManager), each address book is a
+ child object, e.g.
+ $code(/com/example/MyService1/AddressBookManager/SomeAddressBook).
+
+ The interface could be eliminated, and the
+ $code(org.freedesktop.DBus.ObjectManager) interface implemented on the manager
+ object instead.
+
+ Calls to $code(GetAddressBooks) would become calls to $code(GetManagedObjects)
+ and emissions of the $code(AddressBookAdded) and $code(AddressBookRemoved)
+ signals would become emissions of $code(InterfacesAdded) and
+ $code(InterfacesRemoved).
+
+=== 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.
+
+Services use reverse-domain-name notation, based on the domain name of the
+project providing the service (all in lower case), plus a unique name for the
+service (in camel case).
+
+[example]
+ For example, version 2 of an address book application called $code(ContactDex)
+ provided by a software vendor whose website is $code(chocolateteapot.com)
+ would use service name $code(com.chocolateteapot.ContactDex2).
+
+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)).
+
+[example]
+ [terms]
+ - Service Name
+ * $code(com.example.MyService1)
+ - Interface Name
+ * $code(com.example.MyService1.SomeInterface)
+ - Object Path (Root Object)
+ * $code(/com/example/MyService1)
+ - Object Path (Child Object)
+ * $code(/com/example/MyService1/SomeChild)
+ - Object Path (Grandchild Object)
+ * $code(/com/example/MyService1/AnotherChild/Grandchild1)
+ - Method Name
+ * $code(com.example.MyService1.SomeInterface.MethodName)
+ - Signal Name
+ * $code(com.example.MyService1.SomeInterface.SignalName)
+ - Property Name
+ * $code(com.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).
+
+== Annotations
+ [id="annotations"]
+
+Annotations may be added to the interface XML to expose metadata on the API
+which can be used by documentation or code generation tools to modify their
+output. Some standard annotations are given in the
+$link[>>http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format](D-Bus
+specification), but further annotations may be defined by specific tools.
+
+For example, $cmd(gdbus-codegen) defines several useful annotations, listed on
+its man page.
+
+The following annotations are the most useful:
+
+[terms]
+- $code(org.freedesktop.DBus.Deprecated)
+* Mark a symbol as deprecated. This should be used whenever the API is changed,
+ specifying the version introducing the deprecation, the reason for
+ deprecation, and a replacement symbol to use.
+- $code(org.gtk.GDBus.Since)
+* Mark a symbol as having been added to the API after the initial release. This
+ should include the version the symbol was first added in.
+- $code(org.gtk.GDBus.C.Name) and $code(org.freedesktop.DBus.GLib.CSymbol)
+* Both used interchangeably to hint at a C function name to use when generating
+ code for a symbol. Use of this annotation can make generated bindings a lot
+ more pleasant to use.
+- $code(org.freedesktop.DBus.Property.EmitsChangedSignal)
+* Indicate whether a property is expected to emit change signals. This can
+ affect code generation, but is also useful documentation, as client programs
+ then know when to expect property change notifications and when they have to
+ requery.
+
+== Documentation
+ [id="documentation"]
+
+Also just like C APIs, D-Bus APIs must be documented. There are several methods
+for documenting the interfaces, methods, properties and signals in a D-Bus
+interface XML file, each unfortunately with their own downsides. You should
+choose the method which best matches the tooling and workflow you are using.
+
+=== XML Comments
+
+XML comments containing documentation in the
+$link[>>https://developer.gnome.org/gtk-doc-manual/stable/documenting_syntax.html.en](gtk-doc
+format) is the recommended format for use with
+$link[>>https://developer.gnome.org/gio/stable/gdbus-codegen.html]($cmd(gdbus-codegen)).
+Using $cmd(gdbus-codegen), these comments can be extracted, converted to DocBook
+format and included in the project’s API manual. 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"]
+ <!--
+ org.freedesktop.DBus.Properties:
+ @short_description: Standard property getter/setter interface
+
+ Interface for all objects which expose properties on the bus, allowing
+ those properties to be got, set, and signals emitted to notify of changes
+ to the property values.
+ -->
+ <interface name="org.freedesktop.DBus.Properties">
+ <!--
+ Get:
+ @interface_name: Name of the interface the property is defined on.
+ @property_name: Name of the property to get.
+ @value: Property value, wrapped in a variant.
+
+ Retrieves the value of the property at @property_name on
+ @interface_name on this object. If @interface_name is an empty string,
+ all interfaces will be searched for @property_name; if multiple
+ properties match, the result is undefined.
+
+ If @interface_name or @property_name do not exist, a
+ #org.freedesktop.DBus.Error.InvalidArgs error is returned.
+ -->
+ <method name="Get">
+ <arg type="s" name="interface_name" direction="in"/>
+ <arg type="s" name="property_name" direction="in"/>
+ <arg type="v" name="value" direction="out"/>
+ </method>
+
+ <!--
+ PropertiesChanged:
+ @interface_name: Name of the interface the properties changed on.
+ @changed_properties: Map of property name to updated value for the
+ changed properties.
+ @invalidated_properties: List of names of other properties which have
+ changed, but whose updated values are not notified.
+
+ Emitted when one or more properties change values on @interface_name.
+ A property may be listed in @changed_properties or
+ @invalidated_properties depending on whether the service wants to
+ broadcast the property’s new value. If a value is large or infrequently
+ used, the service might not want to broadcast it, and will wait for
+ clients to request it instead.
+ -->
+ <signal name="PropertiesChanged">
+ <arg type="s" name="interface_name"/>
+ <arg type="a{sv}" name="changed_properties"/>
+ <arg type="as" name="invalidated_properties"/>
+ </signal>
+ </interface>
+
+[comment]
+ FIXME: This is only present to fix
+ $link[>>https://github.com/projectmallard/mallard-ducktype/issues/2].
+
+=== XML Annotations
+
+Documentation can also be added as annotation elements in the XML. This format
+is also supported by $cmd(gdbus-codegen), but gtk-doc comments are preferred.
+For example:
+
+[listing]
+ [title]
+ Documentation Annotations in D-Bus Interface XML
+ [desc]
+ Example GDBus documentation annotations in the introspection XML for
+ the $code(org.freedesktop.DBus.Properties) interface.
+ [code mime="application/xml"]
+ <interface name="org.freedesktop.DBus.Properties">
+ <annotation name="org.gtk.GDBus.DocString" value="Interface for all
+ objects which expose properties on the bus, allowing those properties to
+ be got, set, and signals emitted to notify of changes to the property
+ values."/>
+ <annotation name="org.gtk.GDBus.DocString.Short"
+ value="Standard property getter/setter interface"/>
+
+ <method name="Get">
+ <annotation name="org.gtk.GDBus.DocString" value="Retrieves the value of
+ the property at @property_name on @interface_name on this object. If
+ @interface_name is an empty string, all interfaces will be searched
+ for @property_name; if multiple properties match, the result is
+ undefined.
+
+ If @interface_name or @property_name do not exist, a
+ #org.freedesktop.DBus.Error.InvalidArgs error is returned."/>
+
+ <arg type="s" name="interface_name" direction="in">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the interface the property is defined on."/>
+ </arg>
+
+ <arg type="s" name="property_name" direction="in">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the property to get."/>
+ </arg>
+
+ <arg type="v" name="value" direction="out">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Property value, wrapped in a variant."/>
+ </arg>
+ </method>
+
+ <signal name="PropertiesChanged">
+ <annotation name="org.gtk.GDBus.DocString" value="Emitted when one or
+ more properties change values on @interface_name. A property may be
+ listed in @changed_properties or @invalidated_properties depending on
+ whether the service wants to broadcast the property’s new value. If a
+ value is large or infrequently used, the service might not want to
+ broadcast it, and will wait for clients to request it instead."/>
+
+ <arg type="s" name="interface_name">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Name of the interface the properties changed on."/>
+ </arg>
+
+ <arg type="a{sv}" name="changed_properties">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="Map of property name to updated value for the changed
+ properties."/>
+ </arg>
+
+ <arg type="as" name="invalidated_properties">
+ <annotation name="org.gtk.GDBus.DocString"
+ value="List of names of other properties which have changed, but
+ whose updated values are not notified."/>
+ </arg>
+ </signal>
+ </interface>
+
+[comment]
+ FIXME: This is only present to fix
+ $link[>>https://github.com/projectmallard/mallard-ducktype/issues/2].
+
+== 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(com.example.MyService1.service) for well-known name
+$code(com.example.MyService1). Files must be installed in
+$file($var($$(datadir$))/dbus-1/services) for the session bus and
+$file($var($$(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"]
+
+At a high level, the D-Bus security model is:
+[list]
+* There is a system bus, and zero or more session buses.
+* Any process may connect to the system bus. The system bus limits which can own
+ names or send method calls, and only processes running as privileged users can
+ receive unicast messages not addressed to them. Every process may receive
+ broadcasts.
+* Each session bus has an owner (a user). Only its owner may connect; on
+ general-purpose Linux, a session bus is not treated as a privilege boundary,
+ so there is no further privilege separation between processes on it.
+
+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 are written as XML files in
+$file($var($$(sysconfdir$)/dbus-1/system.d)) and
+$file($var($$(sysconfdir$)/dbus-1/session.d)) and 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. Each $code(<allow>) or
+$code(<deny>) rule in the policy should have the $code(own),
+$code(send_destination) or $code(receive_sender) attribute set.
+
+When designing an API, bear in mind the need to write and install 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 for the system bus 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. The default policy for the session bus is not restrictive, but
+it is typically not a security boundary.
+
+== 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 security policy for the system bus
+to be manually relaxed to allow eavesdropping on all messages. This meant that
+debugging it 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.
diff --git a/doc/dbus-daemon.1.xml.in b/doc/dbus-daemon.1.xml.in
index 78f0fd08..59cc016f 100644
--- a/doc/dbus-daemon.1.xml.in
+++ b/doc/dbus-daemon.1.xml.in
@@ -809,6 +809,31 @@ Right now the default will be the security context of the bus itself.</para>
<para>If two &lt;associate&gt; elements specify the same name, the element
appearing later in the configuration file will be used.</para>
+<itemizedlist remap='TP'>
+
+ <listitem><para><emphasis remap='I'>&lt;apparmor&gt;</emphasis></para></listitem>
+
+
+</itemizedlist>
+
+<para>The &lt;apparmor&gt; element is used to configure AppArmor mediation on
+the bus. It can contain one attribute that specifies the mediation mode:</para>
+
+<literallayout remap='.nf'>
+ &lt;apparmor mode="(enabled|disabled|required)"/&gt;
+</literallayout> <!-- .fi -->
+
+<para>The default mode is "enabled". In "enabled" mode, AppArmor mediation
+will be performed if AppArmor support is available in the kernel. If it is not
+available, dbus-daemon will start but AppArmor mediation will not occur. In
+"disabled" mode, AppArmor mediation is disabled. In "required" mode, AppArmor
+mediation will be enabled if AppArmor support is available, otherwise
+dbus-daemon will refuse to start.</para>
+
+<para>The AppArmor mediation mode of the bus cannot be changed after the bus
+starts. Modifying the mode in the configuration file and sending a SIGHUP
+signal to the daemon has no effect on the mediation mode.</para>
+
</refsect1>
<refsect1 id='selinux'><title>SELinux</title>
@@ -876,6 +901,37 @@ itself will be used.</para>
</refsect1>
+<refsect1 id='apparmor'><title>AppArmor</title>
+<para>The AppArmor confinement context is stored when applications connect to
+the bus. The confinement context consists of a label and a confinement mode.
+When a security decision is required, the daemon uses the confinement context
+to query the AppArmor policy to determine if the action should be allowed or
+denied and if the action should be audited.</para>
+
+<para>The daemon performs AppArmor security checks in three places.</para>
+
+<para>First, any time a message is routed from one connection to another
+connection, the bus daemon will check permissions with the label of the first
+connection as source, label and/or connection name of the second connection as
+target, along with the bus name, the path name, the interface name, and the
+member name. Reply messages, such as method_return and error messages, are
+implicitly allowed if they are in response to a message that has already been
+allowed.</para>
+
+<para>Second, any time a connection asks to own a name, the bus daemon will
+check permissions with the label of the connection as source, the requested
+name as target, along with the bus name.</para>
+
+<para>Third, any time a connection attempts to eavesdrop, the bus daemon will
+check permissions with the label of the connection as the source, along with
+the bus name.</para>
+
+<para>AppArmor rules for bus mediation are not stored in the bus configuration
+files. They are stored in the application's AppArmor profile. Please see
+<emphasis remap='I'>apparmor.d(5)</emphasis> for more details.</para>
+
+</refsect1>
+
<refsect1 id='debugging'><title>DEBUGGING</title>
<para>If you're trying to figure out where your messages are going or why
you aren't getting messages, there are several things you can try.</para>
diff --git a/doc/dbus-specification.xml b/doc/dbus-specification.xml
index 2f9fef8b..ce3929e2 100644
--- a/doc/dbus-specification.xml
+++ b/doc/dbus-specification.xml
@@ -6,8 +6,8 @@
<article id="index">
<articleinfo>
<title>D-Bus Specification</title>
- <releaseinfo>Version 0.25</releaseinfo>
- <date>(not yet released)</date>
+ <releaseinfo>Version 0.26</releaseinfo>
+ <date>2015-02-19</date>
<authorgroup>
<author>
<firstname>Havoc</firstname>
@@ -72,10 +72,11 @@
<revhistory>
<revision>
<revnumber>0.26</revnumber>
- <date>(not yet released)</date>
- <authorinitials>n/a</authorinitials>
+ <date>2015-02-19</date>
+ <authorinitials>smcv, rh</authorinitials>
<revremark>
- see <ulink url='http://cgit.freedesktop.org/dbus/dbus/log/doc/dbus-specification.xml'>commit log</ulink>
+ GetConnectionCredentials can return LinuxSecurityLabel or
+ WindowsSID; add privileged BecomeMonitor method
</revremark>
</revision>
<revision>
@@ -6005,6 +6006,65 @@
this concept. On Unix, this is the process ID defined by
POSIX.</entry>
</row>
+ <row>
+ <entry>WindowsSID</entry>
+ <entry>STRING</entry>
+ <entry>The Windows security identifier in its string form,
+ e.g. "S-1-5-21-3623811015-3361044348-30300820-1013" for
+ a domain or local computer user or "S-1-5-18" for the
+ LOCAL_SYSTEM user</entry>
+ </row>
+
+ <row>
+ <entry>LinuxSecurityLabel</entry>
+ <entry>ARRAY of BYTE</entry>
+ <entry>
+ <para>On Linux systems, the security label that would result
+ from the SO_PEERSEC getsockopt call. The array contains
+ the non-zero bytes of the security label in an unspecified
+ ASCII-compatible encoding<footnote>
+ <para>It could be ASCII or UTF-8, but could also be
+ ISO Latin-1 or any other encoding.</para>
+ </footnote>, followed by a single zero byte.</para>
+ <para>
+ For example, the SELinux context
+ <literal>system_u:system_r:init_t:s0</literal>
+ (a string of length 27) would be encoded as 28 bytes
+ ending with ':', 's', '0', '\x00'.<footnote>
+ <para>Note that this is not the same as the older
+ GetConnectionSELinuxContext method, which does
+ not append the zero byte. Always appending the
+ zero byte allows callers to read the string
+ from the message payload without copying.</para>
+ </footnote>
+ </para>
+ <para>
+ On SELinux systems this is the SELinux context, as output
+ by <literal>ps -Z</literal> or <literal>ls -Z</literal>.
+ Typical values might include
+ <literal>system_u:system_r:init_t:s0</literal>,
+ <literal>unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023</literal>,
+ or
+ <literal>unconfined_u:unconfined_r:chrome_sandbox_t:s0-s0:c0.c1023</literal>.
+ </para>
+ <para>
+ On Smack systems, this is the Smack label.
+ Typical values might include
+ <literal>_</literal>, <literal>*</literal>,
+ <literal>User</literal>, <literal>System</literal>
+ or <literal>System::Shared</literal>.
+ </para>
+ <para>
+ On AppArmor systems, this is the AppArmor context,
+ a composite string encoding the AppArmor label (one or more
+ profiles) and the enforcement mode.
+ Typical values might include <literal>unconfined</literal>,
+ <literal>/usr/bin/firefox (enforce)</literal> or
+ <literal>user1 (complain)</literal>.
+ </para>
+ </entry>
+ </row>
+
</tbody>
</tgroup>
</informaltable>
diff --git a/doc/dbus-test-tool.1.xml.in b/doc/dbus-test-tool.1.xml.in
new file mode 100644
index 00000000..091dee14
--- /dev/null
+++ b/doc/dbus-test-tool.1.xml.in
@@ -0,0 +1,325 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<refentry id="dbus-test-tool.1">
+ <refentryinfo>
+ <copyright>
+ <year>2015</year>
+ <holder>Collabora Ltd.</holder>
+ </copyright>
+ <legalnotice>
+ <para>This man page is distributed under the same terms as
+ dbus-test-tool (GPL-2+). There is NO WARRANTY, to the extent
+ permitted by law.</para>
+ </legalnotice>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>dbus-test-tool</refentrytitle>
+ <manvolnum>1</manvolnum>
+ <refmiscinfo class="manual">User Commands</refmiscinfo>
+ <refmiscinfo class="source">D-Bus</refmiscinfo>
+ <refmiscinfo class="version">@DBUS_VERSION@</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>dbus-test-tool</refname>
+ <refpurpose>D-Bus traffic generator and test tool</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv id="synopsis">
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">black-hole</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--name=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--no-read</arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">echo</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--name=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--sleep=<replaceable>MS</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>dbus-test-tool</command>
+ <arg choice="plain">spam</arg>
+ <group choice="opt">
+ <arg choice="plain">--session</arg>
+ <arg choice="plain">--system</arg>
+ </group>
+ <arg choice="opt">--dest=<replaceable>NAME</replaceable></arg>
+ <arg choice="opt">--count=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--flood</arg>
+ <arg choice="opt">--ignore-errors</arg>
+ <arg choice="opt">--messages-per-conn=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--no-reply</arg>
+ <arg choice="opt">--queue=<replaceable>N</replaceable></arg>
+ <arg choice="opt">--seed=<replaceable>SEED</replaceable></arg>
+ <group choice="opt">
+ <arg choice="plain">--string</arg>
+ <arg choice="plain">--bytes</arg>
+ <arg choice="plain">--empty</arg>
+ </group>
+ <group choice="opt">
+ <arg choice="plain">--payload=<replaceable>S</replaceable></arg>
+ <arg choice="plain">--stdin</arg>
+ <arg choice="plain">--message-stdin</arg>
+ <arg choice="plain">--random-size</arg>
+ </group>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 id="description">
+ <title>DESCRIPTION</title>
+ <para><command>dbus-test-tool</command> is a multi-purpose tool
+ for debugging and profiling D-Bus.</para>
+
+ <para><command>dbus-test-tool black-hole</command>
+ connects to D-Bus, optionally requests a name, then does not
+ reply to messages. It normally reads and discards messages from
+ its D-Bus socket, but can be configured to sleep forever without
+ reading.</para>
+
+ <para><command>dbus-test-tool echo</command>
+ connects to D-Bus, optionally requests a name, then sends back an
+ empty reply to every method call, after an optional delay.</para>
+
+ <para><command>dbus-test-tool spam</command>
+ connects to D-Bus and makes repeated method calls,
+ normally named <literal>com.example.Spam</literal>.</para>
+ </refsect1>
+
+ <refsect1 id="options">
+ <title>OPTIONS</title>
+ <refsect2>
+ <title>Common options</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--session</option></term>
+ <listitem>
+ <para>Connect to the session bus. This is the default.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--system</option></term>
+ <listitem>
+ <para>Connect to the system bus.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>black-hole mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--name=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Before proceeding, request ownership of the well-known
+ bus name <replaceable>NAME</replaceable>, for example
+ <literal>com.example.NoReply</literal>. By default,
+ no name is requested, and the tool can only be addressed by
+ a unique bus name such as <literal>:1.23</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-read</option></term>
+ <listitem>
+ <para>Do not read from the D-Bus socket.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>echo mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--name=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Before proceeding, request ownership of the well-known
+ bus name <replaceable>NAME</replaceable>, for example
+ <literal>com.example.Echo</literal>. By default,
+ no name is requested, and the tool can only be addressed by
+ a unique bus name such as <literal>:1.23</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--sleep=</option><replaceable>MS</replaceable></term>
+ <listitem>
+ <para>Block for <replaceable>MS</replaceable> milliseconds
+ before replying to a method call.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>spam mode</title>
+ <variablelist remap="TP">
+
+ <varlistentry>
+ <term><option>--dest=</option><replaceable>NAME</replaceable></term>
+ <listitem>
+ <para>Send method calls to the well-known or unique
+ bus name <replaceable>NAME</replaceable>.
+ The default is the dbus-daemon,
+ <literal>org.freedesktop.DBus</literal>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--count=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>Send <replaceable>N</replaceable> method calls in total.
+ The default is 1.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--queue=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>Send <replaceable>N</replaceable> method calls before
+ waiting for any replies, then send one new call per reply
+ received, keeping <replaceable>N</replaceable> method calls
+ "in flight" at all times until the number of messages specified
+ with the <option>--count</option> option have been sent.
+ The default is 1, unless <option>--flood</option>
+ is used.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--flood</option></term>
+ <listitem>
+ <para>Send all messages without waiting for a reply,
+ equivalent to <option>--queue</option> with an arbitrarily
+ large <replaceable>N</replaceable>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--no-reply</option></term>
+ <listitem>
+ <para>Set the "no reply desired" flag on the messages.
+ This implies <option>--flood</option>, since it disables
+ the replies that would be used for a finite
+ <option>--queue</option> length.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--messages-per-conn=</option><replaceable>N</replaceable></term>
+ <listitem>
+ <para>If given, send <replaceable>N</replaceable> method calls
+ on the same connection, then disconnect and reconnect.
+ The default is to use the same connection for all method
+ calls.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--string</option></term>
+ <listitem>
+ <para>The payload of each message is a UTF-8 string. This is the
+ default. The actual string used is given by the
+ <option>--payload</option> or <option>--stdin</option>
+ option, defaulting to "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--bytes</option></term>
+ <listitem>
+ <para>The payload of each message is a byte-array.
+ The actual bytes used are given by the
+ <option>--payload</option> or <option>--stdin</option>
+ option, defaulting to the ASCII encoding of
+ "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--empty</option></term>
+ <listitem>
+ <para>The messages have no payload.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--payload=</option><replaceable>S</replaceable></term>
+ <listitem>
+ <para>Use <replaceable>S</replaceable> as the
+ <option>--string</option> or <option>--bytes</option>
+ in the messages. The default is "hello, world!".</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--stdin</option></term>
+ <listitem>
+ <para>Read from standard input until end-of-file is reached,
+ and use that as the <option>--string</option> or
+ <option>--bytes</option> in the messages.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--message-stdin</option></term>
+ <listitem>
+ <para>Read a complete binary D-Bus method call message from
+ standard input, and use that for each method call.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--random-size</option></term>
+ <listitem>
+ <para>Read whitespace-separated ASCII decimal numbers from
+ standard input, choose one at random for each message,
+ and send a message whose payload is a string of that
+ length.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--seed=</option><replaceable>SEED</replaceable></term>
+ <listitem>
+ <para>Use <replaceable>SEED</replaceable> as the seed
+ for the pseudorandom number generator, to have somewhat
+ repeatable sequences of random messages.</para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <refsect1 id="bugs">
+ <title>BUGS</title>
+ <para>Please send bug reports to the D-Bus bug tracker or mailing list.
+ See <ulink url="http://www.freedesktop.org/software/dbus/">http://www.freedesktop.org/software/dbus/</ulink>.</para>
+ </refsect1>
+
+ <refsect1 id="see_also">
+ <title>SEE ALSO</title>
+ <para><citerefentry><refentrytitle>dbus-send</refentrytitle><manvolnum>1</manvolnum></citerefentry></para>
+ </refsect1>
+</refentry>