Why should I use a D-Bus Proxy?

,

I have written my application to mostly using g_dbus_connection_call_sync() after an InterfacesAdded occurs on org.freedesktop.DBus.ObjectManager.

There is also a g_dbus_proxy_call_sync() which I have not tried to use.

In my program I start with g_dbus_get_sync() which creates a D-Bus connection. Then I call g_dbus_connection_signal_subscribe() which does a callback when the interface I am interested in gets created.

Why would I want to do the extra step of creating the proxy?

The D-BUS Tutorial says:

A proxy object is a convenient native object created to represent a remote object in another process. The low-level DBus API involves manually creating a method call message, sending it, then manually receiving and processing the method reply message. Higher-level bindings provide proxies as an alternative. Proxies look like a normal native object; but when you invoke a method on the proxy object, the binding converts it into a DBus method call message, waits for the reply message, unpacks the return value, and returns it from the native method.

Then they show pseudo code that is somewhat more involved in the non-proxy method, but using g_dbus*() functions, I am not sure that this is the case.

I did find this piece of documentation:

As an exception to the usual GLib rule that a particular object must not be used by two threads at the same time, GDBusConnection‘s methods may be called from any thread. This is so that g_bus_get() and g_bus_get_sync() can safely return the same GDBusConnection when called from any thread.

I am using one connection object across multiple threads in my program. I have a thread for each end point device, but am sharing the same connection object. So maybe this is saying that if you have multiple threads then you should not use proxy objects?

GDBusProxy is a simpler and much higher-level API than GDBusConnection. You would normally use GDBusProxy in application code whenever possible, and use GDBusConnection only when you need extra power. I’m not sure if I’ve ever used GDBusConnection for any purpose other than to create a GDBusProxy.

GDBusProxy and GDBusConnection are both threadsafe:

A GDBusProxy instance can be used from multiple threads but note that all signals (e.g. “g-signal”, “g-properties-changed” and “notify”) are emitted in the thread-default main context of the thread where the instance was constructed.

(This is unusual. Normally you cannot ever share objects across threads.)

One more piece of advice: working directly with threads is dangerous and error-prone. Whenever possible, prefer to do async I/O on the main thread instead. The actual I/O happens on secondary threads, of course, but that’s hidden behind the GIO APIs so that you don’t need to worry about it.

Also if you use gdbus-codegen, you can generate a subclass of GDBusProxy that’s even more convenient to use. Whether this is worth it or not is up to you to decide.

I have completed my D-BUS/GATT/BlueZ/libgio/libg program. I am very happy.

The purpose of my application is to connect to multiple identical BLE endpoint devices simultaneously using BlueZ. I only have 10 devices presently to test simultaneously (and many more that have to be filtered out that are in our environment). This requirement was satisfied.

This project was my first involving D-BUS and libgio.

I was given someone’s non-working python program that used the python bleak library, and only worked under windows.

So what I did was study someone else’s libgio example that did a Bluetooth scan and a python/bleak program that did not work on Linux. The libgio example did not use D-BUS proxies. I have not seen a full example that uses libgio, D-Bus proxies and GATT.

So these are the libgio api’s that I used involving D-Bus:

g_bus_get_sync
g_dbus_connection_signal_subscribe
g_main_loop_new
g_dbus_connection_signal_unsubscribe
g_dbus_connection_call_sync
g_dbus_error_get_remote_error
g_dbus_error_strip_remote_error

I created one thread per connection by calling g_task_new() in a g_dbus_connection_signal_subscribe() callback. This thread managed my Bluetooth connections, and unless the thread was terminated due to some kind of abort, it always removed the Bluetooth device from BlueZ when it finished. The thread did a sequential set of operations on the remote BLE device. I did not think I could get my head around keeping track of states with nothing but callbacks, but it is probably possible.

I created two GAsyncQueue’s. One queue is used as a semaphore so a callback to tell my BLE connection task that it is time to wake up when a D-Bus signal occurs. The 2nd queue was to keep track of attempted BLE connections, so that if the program was terminated early it could remove any BLE devices. Without removing the remote BLE devices the system got into a bad state.

C library functions used (all of which I believe are thread safe):

strrchr
strlen
strncmp
signal (to ignore SIGHUP)

All other functions were from libg.

I will probably need to try D-BUS proxy some other time.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.