NoReply Exception in DBUS communication

Question:

I’m working on an asynchronous communication script that will act as a middleman between a react native app and another agent. To do this I used python with DBUS to implement the communication between the two.

To implement this we created two processes one for the BLE and one for the communication with the agent. In cases where the agent replies immediately (with a non-blocking call) the communication always works as intended. For the case where we attach to a signal to continuously monitor an update status this error occurs most of the time at random points during the process:

dbus.exceptions.DBusException: org.freedesktop.DBus.Error.NoReply: Did not receive a reply. Possible causes include: the remote application did not send a reply, the message bus security policy blocked the reply, the reply timeout expired, or the network connection was broken.

I have tested both the BLE process and the agent process separately and they work as intended.

I’m currently suspecting that it could be related to messages "crashing" on the system bus or some race conditions but we are unsure how to validate that.

Any advice on what could be causing this issue or how I could avoid it?

For completeness I’ve attached a simplified version of the class that handles the communication with the agent.

import multiprocessing
from enum import Enum
import dbus
import dbus.mainloop.glib
from dbus.proxies import ProxyObject
from gi.repository import GLib
from omegaconf import DictConfig
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)


class ClientUpdateStatus(Enum):
    SUCCESS = 0
    PENDING = 1
    IN_PROGRESS = 2
    FAILED = 3

class DBUSManager:

    GLIB_LOOP = GLib.MainLoop()
    COMMUNICATION_QUEUE = multiprocessing.Queue()
    
    def __init__(self, config: DictConfig) -> None:
        
        dbus_system_bus = dbus.SystemBus()
        
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
        self._config = config
        
        self._dbus_object = dbus_system_bus.get_object(self._config['dbus_interface'],
                                                            self._config['dbus_object_path'], introspect=False)

    def get_version(self) -> str:

        version = self._dbus_object.GetVersion("clientSimulator", dbus_interface=self._config['dbus_interface'])
        return version

    def check_for_update(self) -> str:
        update_version = self._dbus_object.CheckForUpdate("clientSimulator",
                                                               dbus_interface=self._config['dbus_interface'])
        return update_version

    def run_update(self) -> ClientUpdateStatus:
        raw_status = self._dbus_object.ExecuteUpdate(dbus_interface=self._config['dbus_interface'])
        
        update_status = ClientUpdateStatus(raw_status)
        
        # Launch listening process
        signal_update_proc = multiprocessing.Process(target=DBUSManager.start_listener_process,
                                                     args=(self._dbus_object, self._config['dbus_interface'],))
        signal_update_proc.start()

        while True:
            raw_status = DBUSManager.COMMUNICATION_QUEUE.get()
            update_status = ClientUpdateStatus(raw_status)
            
            if ClientUpdateStatus.SUCCESS == update_status:
                break

        signal_update_proc.join()

        return update_status

    @staticmethod
    def start_listener_process(dbus_object: ProxyObject, dbus_interface: str) -> None:
       
        dbus_object.connect_to_signal("UpdateStatusChanged", DBUSManager.status_change_handler,
                                           dbus_interface=dbus_interface)
        # Launch loop to acquire signals
        DBUSManager.GLIB_LOOP.run()  # This listening loop exits on GLIB_LOOP.quit()

    @staticmethod
    def status_change_handler(new_status: int) -> None:
        DBUSManager.COMMUNICATION_QUEUE.put(new_status)
        if ClientUpdateStatus.SUCCESS == ClientUpdateStatus(new_status):
            DBUSManager.GLIB_LOOP.quit()
Asked By: Bruno

||

Answers:

At this stage I would recommend to do a dbus-monitor to see if agent and BLE are reacting to requests properly.

Answered By: idle_roamer

Maybe to help others in the future I haven’t found the solution but at least a way to work around it. We have encountered that problem at various places in our project and what generally helped, don’t ask me why, was to always re-instantiate all needed dbus objects. So instead of having a single class that has a system bus variable self._system_bus = dbus.SystemBus() or a interface variable self._manager_interface = dbus.Interface(proxy_object, "org.freedesktop.DBus.ObjectManager") we would always re-instiate them.

If somebody knows what the problem is I’m happy to hear it.

Answered By: Bruno
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.