简体   繁体   中英

NoReply Exception in DBUS communication

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()

在这个阶段,我建议做一个dbus-monitor来查看代理和 BLE 是否正确地响应请求。

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM