Posted on Mi 11 Februar 2009

How to Version D-Bus Interfaces Properly and Why Using / as Service Entry Point Sucks

So you are designing a D-Bus interface and want to make it future-proof. Of course, you thought about versioning your stuff. But you wonder how to do that best. Here are a few things I learned about versioning D-Bus APIs which might be of general interest:

Version your interfaces! This one is pretty obvious. No explanation needed. Simply include the interface version in the interface name as suffix. i.e. the initial release should use org.foobar.AwesomeStuff1, and if you do changes you should introduce org.foobar.AwesomeStuff2, and so on, possibly dropping the old interface.

When should you bump the interface version? Generally, I'd recommend only bumping when doing incompatible changes, such as function call signature changes. This of course requires clients to handle the org.freedesktop.DBus.Error.UnknownMethod error properly for each function you add to an existing interface. That said, in a few cases it might make sense to bump the interface version even without breaking compatibility of the calls. (e.g. in case you add something to an interface that is not directly visible in the introspection data)

Version your services! This one is almost as obvious. When you completely rework your D-Bus API introducing a new service name might be a good idea. Best way to do this is by simply bumping the service name. Hence, call your service org.foobar.AwesomeService1 right from the beginning and then bump the version if you reinvent the wheel. And don't forget that you can acquire more than one well-known service name on the bus, so even if you rework everything you can keep compatibilty. (Example: BlueZ 3 to BlueZ 4 switch)

Version your 'entry point' object paths! This one is far from obvious. The reasons why object paths should be versioned are purely technical, not philosophical: for signals sent from a service D-Bus overwrites the originating service name by the unique name (e.g. :1.42) even if you fill in a well-known name (e.g. org.foobar.AwesomeService1). Now, let's say your application registers two well-known service names, let's say two versions of the same service, versioned like mentioned above. And you have two objects -- one on each of the two service names -- that implement a generic interface and share the same object path: for the client there will be no way to figure out to which service name the signals sent from this object path belong. And that's why you should make sure to use versioned and hence different paths for both objects. i.e. start with /org/foobar/AwesomeStuff1 and then bump to /org/foobar/AwesomeStuff2 and so on. (Also see David's comments about this.)

When should you bump the object path version? Probably only when you bump the service name it belongs to. Important is to version the 'entry point' object path. Objects below that don't need explicit versioning.

In summary: For good D-Bus API design you should version all three: D-Bus interfaces, service names and 'entry point' object paths.

And don't forget: nobody gets API design right the first time. So even if you think your D-Bus API is perfect: version things right from the beginning because later on it might turn out you were not quite as bright as you thought you were.

A corollary from the reasoning behind versioning object paths as described above is that using / as entry point object path for your service is a bad idea. It makes it very hard to implement more than one service or service version on a single D-Bus connection. Again: Don't use / as entry point object path. Use something like /org/foobar/AwesomeStuff!

© Lennart Poettering. Built using Pelican. Theme by Giulio Fidente on github. .