D-Bus的方式在移动手机操作系统中非常重要,包括Maemo,Moblin等以Linux为基础的操作系统。估计Andriod也大量使用。D-Bus的相关学习资料见:http://www.freedesktop.org/wiki/Software/dbus 。
消息通过D-Bus在进程间传递。有四类消息:
一、Method call消息:将触发对象的一个method
二、Method return消息:触发的方法返回的结果
三、Error消息:触发的方法返回一个异常
四、Signal消息:通知,可以看作为事件消息。
一个消息有消息头header,里面有field,有一个消息体body,里面有参数arguments。消息头包含消息体的路由信息,消息体就是净荷payload。头字段可能包括发送者的bus名,目的地的bus名,方法或者signal名等等,其中一个头字段是用于描述body中的参数的类型,例如“i”标识32位整数,"ii”表示净荷为2个32为整数。
发送Method call消息的场景
一个method call消息从进程A到进程B,B将应答一个method return消息或者error消息。在每个call消息带有一个序列号,应答消息也包含同样的号码,使之可以对应起来。他们的处理过程如下:
- 如果提供proxy,通过触发本地一个对象的方法从而触发另一个进程的远端对象的方法。应用调用proxy的一个方法,proxy构造一个method call消息发送到远端进程。
- 对于底层的API,不使用proxy,应用需要自己构造method call消息。
- 一个method call消息包含:远端进程的bus name,方法名字,方法的参数,远端进程中object path,可选的接口名字。
- method call消息发送到bus daemon
- bus daemon查看目的地的bus name。如果一个进程对应这个名字,bus daemon将method call消息发送到该进程中。如果没有发现匹配,bus daemon创建一个error消息作为应答返回。
- 进程接收后将method call消息分拆。对于简单的底层API情况,将立即执行方法,并发送一个method reply消息给bus daemon。对于高层的API,将检查对象path,interface和method,触发一个native object的方法,并将返回值封装在一个method reply消息中。
- bus daemon收到method reply消息,将其转发到原来的进程中
- 进程查看method reply消息,获取返回值。这个响应也可以标识一个error的残生。当使用高级的捆绑,method reply消息将转换为proxy方法的返回值或者一个exception。
Bus daemon保证message的顺序,不会乱序。例如我们发送两个method call消息到同一个接受方,他们将按顺序接受。接收方并不要求一定按顺序回复。消息有一个序列号了匹配收发消息。
发送Signal的场景
signal是个广播的消息,不需要响应,接收方向daemon注册匹配的条件,包括发送方和信号名,bus守护只将信号发送给希望接受的进程。处理流程如下:
- 一个signal消息发送到bus daemon。
- signal消息包含发布该信号的interface名字,signal的名字,进程的bus名字,以及参数。
- 任何进程都可以注册的匹配条件(match rules)表明它所感兴趣的signal。总线有个注册match rules列表。
- bus daemon检查那些进程对该信号有兴趣,将信号消息发送到这些进程中。
- 收到信号的进程决定如何处理。如果使用高层的捆绑,一个porxy对象将会十分一个native的信号。如果使用底层的API,进程需要检查信号的发送发和信号的名字决定如果进行处理。
Introspection
D-Bus对象可能支持一个接口org.freedesktop.DBus.Introspectable。该接口有一个方法Introspect,不带参数,将返回一个XML string。这个XML字符串描述接口,方法,信号。
D-Bus提供两个命令dbus-monitor,可以查看bus,dbus-send命令,可以发送消息,可以用man来检查:
dbus-send [--system | --session] --type=method_call(或者是signal,缺省是signal) --print-reply --dest=连接名 对象路径 接口名.方法名 参数类型:参数值 参数类型:参数值
我们通过这个接口.方法来更好地了解D-Bus。我们使用到一个方法ListNames来查看:
[wei@wei-desktop ~]$ dbus-send --print-reply --type=method_call --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return sender=org.freedesktop.DBus -> dest=:1.75 reply_serial=2
array [
string "org.freedesktop.DBus"
string ":1.7"
string "org.freedesktop.Notifications "
string "org.freedesktop.Telepathy.Client.EmpathyMoreThanMeetsTheEye"
... ...
string ":1.6"
string ":1.19"
]例如其中有org.freedesktop.Notifications这样一个Name,我们希望进一步查看
[wei@wei-desktop ~]$ dbus-send --print-reply --type=method_call --dest=org.freedesktop.Notifications / org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.19 -> dest=:1.79 reply_serial=2
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<node name="org"/>
</node>
"
例如Node名字,表明路径,从/org开始
[wei@wei-desktop ~]$ dbus-send --print-reply --type=method_call --dest=org.freedesktop.Notifications /org org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.19 -> dest=:1.80 reply_serial=2
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<node name="freedesktop"/>
<node name="moblin"/>
</node>
"Node名字,表明路径,有从/org/freedesktop开始
[wei@wei-desktop ~]$ dbus-send --print-reply --type=method_call --dest=org.freedesktop.Notifications /org/freedesktop org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.19 -> dest=:1.81 reply_serial=2
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<node name="Notifications"/>
</node>"
Node名字,表明路径,有从/org/freedesktop/Notifications开始,可以获取这个接口有什么method和singnal。
[wei@wei-desktop ~]$ dbus-send --print-reply --type=method_call --dest=org.freedesktop.Notifications /org/freedesktop/Notifications org.freedesktop.DBus.Introspectable.Introspect
method return sender=:1.19 -> dest=:1.82 reply_serial=2
string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="org.freedesktop.DBus.Introspectable">
<method name="Introspect">
<arg name="data" direction="out" type="s"/>
</method>
</interface>
<interface name="org.freedesktop.DBus.Properties">
<method name="Get">
<arg name="interface" direction="in" type="s"/>
<arg name="propname" direction="in" type="s"/>
<arg name="value" direction="out" type="v"/>
</method>
<method name="Set">
<arg name="interface" direction="in" type="s"/>
<arg name="propname" direction="in" type="s"/>
<arg name="value" direction="in" type="v"/>
</method>
<method name="GetAll">
<arg name="interface" direction="in" type="s"/>
<arg name="props" direction="out" type="a{sv}"/>
</method>
</interface>
<interface name="org.freedesktop.Notifications">
<method name="GetServerInformation">
<arg name="name" type="s" direction="out"/>
<arg name="vendor" type="s" direction="out"/>
<arg name="version" type="s" direction="out"/>
</method>
<method name="GetCapabilities">
<arg name="caps" type="as" direction="out"/>
</method>
<method name="CloseNotification">
<arg name="id" type="u" direction="in"/>
</method>
<method name="Notify">
<arg name="app_name" type="s" direction="in"/>
<arg name="id" type="u" direction="in"/>
<arg name="icon" type="s" direction="in"/>
<arg name="summary" type="s" direction="in"/>
<arg name="body" type="s" direction="in"/>
<arg name="actions" type="as" direction="in"/>
<arg name="hints" type="a{sv}" direction="in"/>
<arg name="timeout" type="i" direction="in"/>
<arg name="return_id" type="u" direction="out"/>
</method>
<signal name="NotificationClosed">
<arg type="u"/>
<arg type="u"/>
</signal>
</interface>
</node>
"