如何读取dbus-monitor输出?


20

我正在与dbus-monitor一起玩,以尝试了解dbus在Ubuntu环境中的工作方式。在这方面,我有几个问题:

  1. 您能否让我知道如何正确阅读以下内容?我了解大创意,但不了解细节。

    signal sender=:1.1948 -> dest=(null destination) serial=1829990 path=/org/ayatana/menu/DA00003; interface=org.ayatana.dbusmenu; member=ItemPropertyUpdated
    int32 23
    string "enabled"
    variant boolean true
    method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1399 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications;
    member=GetCapabilities

    我知道第一个是信号,而第二个是方法。目的地是否意味着信号可以有特定的接收器/插槽?什么是会员?信号之后的列表项是否在信号中传递了参数?什么是发件人序列号

  2. 我注意到了音量控制和通知之间的关系。从我从dbus-monitor输出中读取的内容

    method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1400 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications; member=Notify
    string "gnome-settings-daemon"
    uint32 0
    string "notification-audio-volume-medium"
    string " "
    string ""
    array [
    ]
    array [
    dict entry(
    string "value"
    variant int32 38
    )
    dict entry(
    string "x-canonical-private-synchronous"
    variant string "volume"
    )
    ]
    int32 -1

    通知似乎是由其方法触发的。我只是真的不明白为什么它会这样工作。我认为,如果有一个信号发出“ notification-audio-volume-medium”,而通知将监听该信号并做出相应的反应,那将更有意义。如果发送/接收将是公共的而不是私有的,难道它不会带来更大的灵活性和效率吗?例如,如果有一个公共信号“ notification-audio-volume-medium” 然后几个应用程序可以侦听此信号(这将允许竞争的通知应用程序出现),而开发人员只需要关心发送信号,而拾取和处理信号将是通知应用程序的业务(或其他任何事务)需要这些信号的程序)。

  3. 我是Dbus的新手,我想在Python上使用Dbus时了解更多信息,主要是开发一些applet。我看过dbus-python教程,它教了如何监听所有信号(通过不指定接口或路径等)。但是如何像dbus-monitor一样跟踪调用方法时的方法?

如果您有耐心去教它是如何工作的,欢迎您。

Answers:


24

D-Bus介绍

  • D-Bus提供了在服务之间进行通信的方法。服务可以是匿名的(仅通过总线地址来标识,如:1.6),服务可以获取众所周知的名称,如org.freedesktop.Notificationsorg.freedesktop.NetworkManager。您在日志中看到的发件人和目的地是服务。“空目的地”是指广播:传送到所有服务。

  • 服务可以将一个或多个对象导出到总线。对象被赋予对象路径,例如/org/freedesktop/NetworkManager/ActiveConnection/1/org/ayatana/menu/DA00003。对象路径使用斜杠作为分隔符,例如文件系统路径。

  • 每个对象可以支持一个或多个接口。接口不过是一组方法和信号,俗称“ 成员”(非常类似于OOP接口)。方法和信号具有固定的签名。成员始终在众所周知的接口名称中进行命名空间。

  • 出版后,众所周知的名字就永远不会改变

  • 任何服务都可以连接到另一个服务的信号并异步调用其方法。任何服务都可以发出信号。

讯号

现在是您的具体问题。

信号发送器=:1.1948->目标=(空目标)序列号= 1829990路径= / org / ayatana / menu / DA00003; interface = org.ayatana.dbusmenu; member = ItemPropertyUpdated
int32 23
字符串“启用”
布尔值true

是的,你是对的,这是一个信号。它是通过服务广播的:1.1948,“自我”对象是/org/ayatana/menu/DA00003。信号具有ItemPropertyUpdated在接口中定义的名称org.ayatana.dbusmenu(例如org.ayatana.dbusmenu::ItemPropertyUpdated在C ++中)。我猜串行是总线上事件的唯一标识符。

然后我们看到信号参数。根据接口文档,第一个int32参数是项目的ID,第二个字符串是其属性名称,第三个变量是属性值。因此,/org/ayatana/menu/DA00003对象通知我们ID为23的商品已将其enabled属性更改为true。


关于信号的另一个示例:

信号发送器=:1.1602->目标=(空目标)序列= 20408路径= / im / pidgin /紫色/紫色对象; interface = im.pidgin.purple.PurpleInterface; 成员= SendingChatMsg
   int32 47893
   字符串“测试”
   uint32 1
信号发送者=:1.1602->目标=(空目标)序列= 20409路径= / im / pidgin /紫色/紫色对象; interface = im.pidgin.purple.PurpleInterface; 成员= IrcSendingText
   整数32170
   字符串“ PRIVMSG#聊天:测试

我使用Pidgin向IRC频道发送了一条文本消息“测试”,并/im/pidgin/purple/PurpleObject在该im.pidgin.purple.PurpleInterface接口下发出了两个信号:首先是常规信号SendingChatMsg,然后是更具体的信号IrcSendingText

方法

现在的方法。方法是让D-Bus对象执行某项操作或执行一些查询并返回数据的一种方法。它们与经典的OOP方法非常相似,不同之处在于D-Bus方法被异步调用。

让我们以编程方式调用D-Bus方法。

import dbus, dbus.proxies

#-- connect to the session bus (as opposed to the system bus)
session = dbus.SessionBus()

#-- create proxy object of D-Bus object
obj_proxy = dbus.proxies.ProxyObject(conn=session,
         bus_name="org.freedesktop.Notifications",     #-- name of the service we are retrieving object from
         object_path="/org/freedesktop/Notifications") #-- the object path

#-- create proxy object of the D-Bus object wrapped into specific interface
intf_proxy = dbus.proxies.Interface(obj_proxy, "org.freedesktop.Notifications")

#-- lastly, create proxy object of the D-Bus method
method_proxy = intf_proxy.get_dbus_method("Notify")

#-- ... and call the method
method_proxy("test from python",
             dbus.UInt32(0),
             "bluetooth",     #-- icon name
             "Notification summary",
             "Here goes notification body",
             [], {},
             5) #-- timeout

注意参数,尤其是图标名称。在您的示例"notification-audio-volume-medium"中,是中功率扬声器的图标。

定制服务

绝对可以运行自己的D-Bus服务,导出自己的D-Bus对象,并使用自己的方法和信号定义自己的D-Bus接口。一旦掌握了总体概念并阅读了dbus模块文档,所有这些操作都可以在Python中轻松完成。:)


欢迎进行讨论,尽管我可能在一两天内没有空。
ulidtko 2011年

谢谢:)这澄清了很多。发件人可以是匿名的,这在某种程度上很有趣,当我使用DFeet时,每个发件人都有一个对应的进程名,但这并没有反映在dbus-monitor输出中。可以追踪过程吗?现在,使用Python我已经看到我可以发送信号或提供方法或触发其他方的方法。还可以拦截方法吗?假设我想看看程序A是否触发了B的Dbus方法并对其进行了处理?
本杰明

关于通知:notify-osd由其他应用程序被动触发,而不是主动寻找信号。这不是不切实际,还是我对Dbus有误解?我想制作一个将替换notify-osd并在某种收件箱中收集通知的应用程序。我可以通过听信号来拦截通知吗?
本杰明

@Benjamin,好吧,当您想拦截针对外部服务的方法调用时,很可能会想到一个损坏的设计。你应该做的,以取代通知,OSD是写一个程序,它提供org.freedesktop.Notifications服务。这样,对该服务的所有方法调用都将由您的代码处理。
ulidtko 2011年

什么是“自我”对象?
kawing-chiu

10

我也在寻找解决方案,以使用python脚本通过dbus收集桌面通知。这个问题是我使用谷歌搜索时最接近的问题,但是写一个notify-osd的替代品似乎有点过分了:)

查看最近通知小程序源,我得到了一些如何监视dbus消息的提示,这是我想出的python实现:

import gtk
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def filter_cb(bus, message):
    # the NameAcquired message comes through before match string gets applied
    if message.get_member() != "Notify":
        return
    args = message.get_args_list()
    # args are
    # (app_name, notification_id, icon, summary, body, actions, hints, timeout)
    print("Notification from app '%s'" % args[0])
    print("Summary: %s" % args[3])
    print("Body: %s", args[4])


DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()
bus.add_match_string(
    "type='method_call',interface='org.freedesktop.Notifications',member='Notify'")
bus.add_message_filter(filter_cb)
gtk.main()

希望这对某人有帮助,因为似乎没有很多与监视dbus消息相关的简单python示例。


1
它肯定帮助了我!非常感谢你!为您提供一些建议:“ type ='method_call'”不是必需的,因为通知使用方法调用。规格中无信号。另外,“ member ='Notify'”也是不必要的,因为您已经在函数中将其过滤掉了(正如您正确说的那样,由于第一个NameAquired消息您无法避免这种情况)
MestreLion 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.