dbus-monitor出力の読み方


20

私はdbus-monitorをいじって、Ubuntu環境でdbusがどのように機能しているかを理解しようとしています。これに関していくつか質問があります。

  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番目のものはメソッドであることがわかります。宛先は、信号の特定の受信機/スロットが存在できることを意味しますか?何メンバー?また、シグナルに続くリストの項目は、シグナルで渡される引数ですか?センダシリアルとは何ですか?

  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を使用しているので、もっと学びたいと思っています。私はdbus-pythonチュートリアルを見てすべての信号をリッスンする方法を教えています(インターフェイスやパスなどを指定しないことによって)。しかし、dbus-monitorのように、メソッドが呼び出されたときにメソッドを追跡する方法は?

それがどのように機能するかを教える忍耐力があれば、大歓迎です。

回答:


24

D-Busの紹介

  • D-Busは、サービス間で通信する手段を提供します。サービスは、することができ、匿名、およびサービスがAQUIREすることができます(1.6のように、バス・アドレスによってのみ識別される)のよく知られた名前を同じように、org.freedesktop.Notificationsまたはorg.freedesktop.NetworkManager。ログで確認できる送信者と宛先はサービスです。「ヌル宛先」とは、ブロードキャスト:すべてのサービスへの配信を意味します。

  • サービスは、1つまたは複数のオブジェクトをバスにエクスポートできます。オブジェクトには、またはなどのオブジェクトパスが与えられます。オブジェクトパスは、ファイルシステムパスのように、スラッシュを区切り記号として使用します。/org/freedesktop/NetworkManager/ActiveConnection/1/org/ayatana/menu/DA00003

  • 各オブジェクトは、1つまたは複数のインターフェイスをサポートできます。インターフェースは、一般的にメンバーとして知られているメソッドとシグナルのセットにすぎません(OOPインターフェースに非常に似ています)。メソッドとシグナルのシグネチャは固定されています。メンバーは、既知のインターフェイス名内で常に名前空間になります。

  • 公開されると、既知の名前は変更さません

  • すべてのサービスは、別のサービスの信号に接続し、そのメソッドを非同期的に呼び出すことができます。どのサービスも信号を発信できます。

信号

次に、具体的な質問に進みます。

signal sender =:1.1948-> dest =(null destination)serial = 1829990 path = / org / ayatana / menu / DA00003; interface = org.ayatana.dbusmenu; member = ItemPropertyUpdated
int32 23
文字列「有効」
バリアントブールtrue

はい、そうです、これはシグナルです。サービスによってブロードキャストされ:1.1948、「自己」オブジェクトは/org/ayatana/menu/DA00003です。シグナルの名前ItemPropertyUpdatedは、インターフェースで定義されていますorg.ayatana.dbusmenuorg.ayatana.dbusmenu::ItemPropertyUpdatedC ++など)。シリアルは、バス上のイベントの一種の一意の識別子です。

次に、シグナル引数が表示されます。インターフェイスのドキュメントによると、最初のint32引数はアイテムのID、2番目の文字列はプロパティ名、3番目のバリアントはプロパティ値です。そのため、/org/ayatana/menu/DA00003オブジェクトは、アイテムID#23がenabledプロパティをtrueに変更したことを通知しています。


信号の別の例:

signal sender =:1.1602-> dest =(null destination)serial = 20408 path = / im / pidgin / purple / PurpleObject; interface = im.pidgin.purple.PurpleInterface; member = SendingChatMsg
   int32 47893
   文字列「テスト」
   uint32 1
signal sender =:1.1602-> dest =(null destination)serial = 20409 path = / im / pidgin / purple / PurpleObject; interface = im.pidgin.purple.PurpleInterface; member = IrcSendingText
   int32 64170
   文字列「PRIVMSG #chat:test

Iは、IRCチャンネルにピジンを使用してテキストメッセージ「テスト」を送信し、/im/pidgin/purple/PurpleObject下に2つの信号を放射されたim.pidgin.purple.PurpleInterfaceインタフェース:最初の一般的なSendingChatMsg、その後、より特定IrcSendingText

方法

今メソッド。メソッドは、D-Busオブジェクトに何らかの処理を依頼する方法、または何らかのクエリを実行してデータを返す方法です。D-Busメソッドが非同期的に呼び出されることを除いて、従来のOOPメソッドと非常に似ています。

プログラムで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で簡単に実行できます。:)


ディスカッションは大歓迎ですが、1〜2日で連絡が取れない場合があります。
ウリトコ

ありがとう:)これは多くを明確にします。送信者が匿名になる可能性があり、DFeetを使用すると、各送信者に対応するプロセス名がありますが、dbus-monitor出力には反映されません。プロセスをトレースできますか?Pythonを使用して、シグナルを送信したり、メソッドを提供したり、他のパーティのメソッドをトリガーしたりすることができます。メソッドを傍受することも可能ですか?プログラムAがBのDbusメソッドをトリガーし、それで何かをするかどうかを見たいと思いますか?
ベンジャミン

通知について:notify-osdは、信号を積極的に探すのではなく、他のアプリケーションによって受動的にトリガーされます。それは非実用的ではありませんか、またはDbusについて何かを誤解していますか?notify-osdを置換し、一種の受信トレイで通知を収集するアプリケーションを作成したいと思います。信号を聞くことで通知を傍受できますか?
ベンジャミン

@Benjamin、まあ、あなたが外国のサービスに向けられたメソッド呼び出しをインターセプトしたいとき、あなたはおそらく壊れたデザインを考えるでしょう。notify-osdを置き換えるためにすべきことorg.freedesktop.Notificationsサービスを提供するプログラムを書くことです。このようにして、このサービスへのすべてのメソッド呼び出しはコードによって処理されます。
-ulidtko

「自己」オブジェクトとは何ですか?
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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.