DBusイントロスペクション メモ

Web::Dashを作るときにLensサービスのインタフェースを調べたりLensの通信を傍受したりしたのでそのメモ。

そもそもDBusとはなんたるかについてはうすださんの記事が詳しくて分かりやすい。

バスを見つける

DBusを使うにはまずは使いたいサービスがつながっているバスを見つける必要がある。標準のバスとしてはsystem busとsession busがあり、大抵のサービスはどちらかのバスにつながっている。

system busはシステム全体で共有されるバス。Ubuntuのデフォルトの設定ではdbus-daemonが/var/run/dbus/system_bus_socketにUNIXドメインソケットを作ってそいつを通じて通信するみたい。

session busはユーザセッションごとに作成されるバスで、デスクトップアプリケーションなんかは普通こっちのバスを使う。session busを使うプロセスは、環境変数DBUS_SESSION_BUS_ADDRESSで示される接続先につなぐことで通信を行う。Ubuntuの場合、DBUS_SESSION_BUS_ADDRESSは「抽象名前空間」に属する独特のUNIXドメインソケットとなるようだ。なのでファイルシステムのどこを探してもそれらしいソケットは見当たらない。

まれに、system busもsession busも使わず独自のバスを立てるアプリケーションが存在する。例えばiBusは自前でバスを立てる。iBusのバス名は~/.config/ibus/busディレクトリ以下のファイルに記述されている。(参考: http://linux.lsdev.sil.org/blog/?p=58)

サービスとオブジェクトを見つける

次に、バスに接続されているサービス及びサービス内のオブジェクトを見つける。

とりあえず確認したい場合はGUIアプリケーションのD-Feetを使うといい。

D-Feetはバス名を指定すればそのバスにつながっているサービスとオブジェクトを列挙して表示してくれる。また、オブジェクトの持つメソッドとシグナルも列挙してくれるし、メソッドを実行することもできる。

プログラムからサービス名のリストを取得したい場合は、org.freedesktop.DBus.ListNamesメソッドを使う。

$ dbus-send --system --dest=org.freedesktop.DBus --type=method_call --print-reply
            /org/freedesktop/DBus org.freedesktop.DBus.ListNames

あるサービス内のオブジェクトを全て列挙したい場合は、ルートオブジェクト(/)を起点として再帰的にorg.freedesktop.DBus.Introspectable.Introspectメソッドを呼び出せばいい。Introspectメソッドの戻り値(XMLドキュメント)にはそのオブジェクトの子オブジェクトの名前が含まれるので、それを利用して木構造を走査できる。

$ dbus-send --system --dest=org.freedesktop.DBus --type=method_call --print-reply
            / org.freedesktop.DBus.Introspectable.Introspect

DBus通信を傍受する

既存のプロセスが行っているDBus通信(メソッドコールやシグナル)を傍受するにはdbus-monitorコマンドを使う。

com.canonical.Unity.Lens.Filesサービスを宛て先とする通信を傍受する。

$ dbus-monitor --session "destination='com.canonical.Unity.Lens.Files'" 

com.canonical.Unity.Lens.Filesサービスが送信元の通信を傍受する。シグナルでブロードキャストされる通信も傍受できる。

$ dbus-monitor --session "sender='com.canonical.Unity.Lens.Files'" 

多分、セキュリティ上の理由で傍受できない通信もあるんだと思う。

まとめ

とりあえず接続先のバスアドレスさえ分かればD-Feetとdbus-monitorでかなり細かい調査はできる。ただ、DBusで公開されているオブジェクトのAPI仕様そのものが複雑で分かりにくかったりするので、その場合はなかなか分析が大変になったりする。