dbus实例讲解2

来源:互联网 发布:javascript es6 编辑:程序博客网 时间:2024/05/09 00:20

目录(?)[+]

应用程序A和消息总线连接,这个连接获取了一个众所周知的公共名(记作连接A)。应用程序A中有对象A1提供了接口I1,接口I1有方法M1。应用程序B和消息总线连接,要求调用连接A上对象A1的接口I1的方法M1。

在上一讲的加法例子中,上面这段话可以实例化为:应用程序example-service和会话总线连接。这个连接获取了一个众所周知的公共名“org.fmddlmyy.Test”。应用程序example-servic中有对象“/TestObj”提供了接口“org.fmddlmyy.Test.Basic”,接口“org.fmddlmyy.Test.Basic”有方法“Add”。应用程序d-feet和会话总线连接,要求调用连接“org.fmddlmyy.Test”上对象“/TestObj”的接口“org.fmddlmyy.Test.Basic”的方法“Add”。

应用程序B调用应用程序A的方法,其实就是应用程序B向应用程序A发送了一个类型为“method_call”的消息。应用程序A通过一个类型为“method_retutn”的消息将返回值发给应用程序B。我们简单介绍一下D-Bus总线上的消息。

1、D-Bus的消息

上一讲说过最基本的D-Bus协议是一对一的通信协议。与直接使用socket不同,D-Bus是面向消息的协议。 D-Bus的所有功能都是通过在连接上流动的消息完成的。

1.1、消息类型

D-Bus有四种类型的消息:

  • method_call 方法调用
  • method_return 方法返回
  • error 错误
  • signal 信号

前面介绍的远程方法调用就用到了method_call和method_return消息。顾名思义,在发生错误时会产生error消息。如果把method_call看作打电话,那么signal消息就是来电了。后面还会详细讨论。

1.2、dbus-send和dbus-monitor

dbus提供了两个小工具:dbus-send和dbus-monitor。我们可以用dbus-send发送消息。用dbus-monitor监视总线上流动的消息。让我们通过dbus-send发送消息来调用前面的Add方法,这时dbus-send充当了应用程序B。用dbus-monitor观察调用过程中的消息。

启动example-service:

$ ./example-service 

在另一个控制台启动dbus-monitor:

$ dbus-monitor

dbus-monitor默认监视会话总线。执行:

$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test /TestObj org.fmddlmyy.Test.Basic.Add int32:100 int32:999

输出为:

method return sender=:1.21 -> dest=:1.22 reply_serial=2   int32 1099

dbus-monitor的相关输出包括:

signal sender=org.freedesktop.DBus -> dest=(null destination) path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged   string ":1.22"   string ""   string ":1.22"method call sender=:1.22 -> dest=org.freedesktop.DBus path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=Hellomethod call sender=:1.22 -> dest=org.fmddlmyy.Test path=/TestObj; interface=org.fmddlmyy.Test.Basic; member=Add   int32 100   int32 999method return sender=:1.21 -> dest=:1.22 reply_serial=2   int32 1099signal sender=org.freedesktop.DBus -> dest=(null destination) path=/org/freedesktop/DBus; interface=org.freedesktop.DBus; member=NameOwnerChanged   string ":1.22"   string ":1.22"   string ""

:1.22就是dbus-send在本次调用中与会话总线所建立连接的唯一名。:1.21是连接“org.fmddlmyy.Test”的唯一名。在以上输出中我们可以看到:1.22向“org.fmddlmyy.Test”发送method_call消息,调用Add方法。 :1.21通过method_return消息将调用结果发回:1.22。其它输出信息会在以后说明。

dbus-send的详细用法可以参阅手册。调用远程方法的一般形式是:

$ dbus-send [--system | --session] --type=method_call --print-reply --dest=连接名 对象路径 接口名.方法名 参数类型:参数值 参数类型:参数值

dbus-send支持的参数类型包括:string, int32, uint32, double, byte, boolean。

2、消息总线的方法和信号

2.1、概述

消息总线是一个特殊的应用,它可以在与它连接的应用之间传递消息。可以把消息总线看作一台路由器。正是通过消息总线,D-Bus才在一对一的通信协议基础上实现了多对一和一对多的通信。

消息总线虽然有特殊的转发功能,但消息总线也还是一个应用。其它应用与消息总线的通信也是通过1.1节的基本消息类型完成的。作为一个应用,消息总线也提供了自己的接口,包括方法和信号。

我们可以通过向连接“org.freedesktop.DBus ”上对象“/”发送消息来调用消息总线提供的方法。事实上,应用程序正是通过这些方法连接到消息总线上的其它应用,完成请求公共名等工作的。

2.2、清单

消息总线对象支持第一讲中提到的标准接口"org.freedesktop.DBus.Introspectable",我们可以调用org.freedesktop.DBus.Introspectable.Introspect方法查看消息总线对象支持的接口。例如:

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

输出为:

method return sender=org.freedesktop.DBus -> dest=:1.20 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">    <method name="Hello">      <arg direction="out" type="s"/>    </method>    <method name="RequestName">      <arg direction="in" type="s"/>      <arg direction="in" type="u"/>      <arg direction="out" type="u"/>    </method>    <method name="ReleaseName">      <arg direction="in" type="s"/>      <arg direction="out" type="u"/>    </method>    <method name="StartServiceByName">      <arg direction="in" type="s"/>      <arg direction="in" type="u"/>      <arg direction="out" type="u"/>    </method>    <method name="NameHasOwner">      <arg direction="in" type="s"/>      <arg direction="out" type="b"/>    </method>    <method name="ListNames">      <arg direction="out" type="as"/>    </method>    <method name="ListActivatableNames">      <arg direction="out" type="as"/>    </method>    <method name="AddMatch">      <arg direction="in" type="s"/>    </method>    <method name="RemoveMatch">      <arg direction="in" type="s"/>    </method>    <method name="GetNameOwner">      <arg direction="in" type="s"/>      <arg direction="out" type="s"/>    </method>    <method name="ListQueuedOwners">      <arg direction="in" type="s"/>      <arg direction="out" type="as"/>    </method>    <method name="GetConnectionUnixUser">      <arg direction="in" type="s"/>      <arg direction="out" type="u"/>    </method>    <method name="GetConnectionUnixProcessID">      <arg direction="in" type="s"/>      <arg direction="out" type="u"/>    </method>    <method name="GetConnectionSELinuxSecurityContext">      <arg direction="in" type="s"/>      <arg direction="out" type="ay"/>    </method>    <method name="ReloadConfig">    </method>    <method name="GetId">      <arg direction="out" type="s"/>    </method>    <signal name="NameOwnerChanged">      <arg type="s"/>      <arg type="s"/>      <arg type="s"/>    </signal>    <signal name="NameLost">      <arg type="s"/>    </signal>    <signal name="NameAcquired">      <arg type="s"/>    </signal>  </interface></node>"

从输出可以看到会话总线对象支持标准接口“org.freedesktop.DBus.Introspectable”和接口“org.freedesktop.DBus”。接口“org.freedesktop.DBus”有16个方法和3个信号。下表列出了“org.freedesktop.DBus”的12个方法的简要说明:

 

org.freedesktop.DBus.RequestName (in STRING name, in UINT32 flags, out UINT32 reply)请求公众名。其中flag定义如下:
DBUS_NAME_FLAG_ALLOW_REPLACEMENT 1
DBUS_NAME_FLAG_REPLACE_EXISTING 2
DBUS_NAME_FLAG_DO_NOT_QUEUE 4

返回值reply定义如下:
DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1
DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2
DBUS_REQUEST_NAME_REPLY_EXISTS 3
DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4org.freedesktop.DBus.ReleaseName (in STRING name, out UINT32 reply)释放公众名。返回值reply定义如下:
DBUS_RELEASE_NAME_REPLY_RELEASED 1
DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2
DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3 org.freedesktop.DBus.Hello (out STRING unique_name)一个应用在通过消息总线向其它应用发消息前必须先调用Hello获取自己这个连接的唯一名。返回值就是连接的唯一名。dbus没有定义专门的切断连接命令,关闭socket就是切断连接。
在1.2节的dbus-monitor输出中可以看到dbus-send调用消息总线的Hello方法。org.freedesktop.DBus.ListNames (out ARRAY of STRING bus_names)返回消息总线上已连接的所有连接名,包括所有公共名和唯一名。例如连接“org.fmddlmyy.Test”同时有公共名“org.fmddlmyy.Test”和唯一名“:1.21”,这两个名称都会被返回。org.freedesktop.DBus.ListActivatableNames (out ARRAY of STRING bus_names)返回所有可以启动的服务名。dbus支持按需启动服务,即根据应用程序的请求启动服务。org.freedesktop.DBus.NameHasOwner (in STRING name, out BOOLEAN has_owner)检查是否有连接拥有指定名称。org.freedesktop.DBus.StartServiceByName (in STRING name, in UINT32 flags, out UINT32 ret_val)按名称启动服务。参数flags暂未使用。返回值ret_val定义如下:
1 服务被成功启动
2 已经有连接拥有要启动的服务名org.freedesktop.DBus.GetNameOwner (in STRING name, out STRING unique_connection_name)返回拥有指定公众名的连接的唯一名。org.freedesktop.DBus.GetConnectionUnixUser (in STRING connection_name, out UINT32 unix_user_id)返回指定连接对应的服务器进程的Unix用户id。org.freedesktop.DBus.AddMatch (in STRING rule)为当前连接增加匹配规则。org.freedesktop.DBus.RemoveMatch (in STRING rule)为当前连接去掉指定匹配规则。org.freedesktop.DBus.GetId (out STRING id)返回消息总线的ID。这个ID在消息总线的生命期内是唯一的。

 

接口“org.freedesktop.DBus”的3个信号是:

 

org.freedesktop.DBus.NameOwnerChanged (STRING name, STRING old_owner, STRING new_owner)指定名称的拥有者发生了变化。org.freedesktop.DBus.NameLost (STRING name)通知应用失去了指定名称的拥有权。org.freedesktop.DBus.NameAcquired (STRING name)通知应用获得了指定名称的拥有权。

 

2.3、练习

让我们来试试消息总线提供的方法。

2.3.1、从ListName到d-feet的基本逻辑

用dbus-send调用:

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

输出为:

method return sender=org.freedesktop.DBus -> dest=:1.23 reply_serial=2   array [      string "org.freedesktop.DBus"      string "org.freedesktop.Notifications"      string "org.freedesktop.Tracker"      string "org.freedesktop.PowerManagement"      string ":1.7"      string ":1.8"      string "org.gnome.ScreenSaver"      string ":1.9"      string ":1.10"      string ":1.22"      string ":1.11"      string "org.gnome.GnomeVFS.Daemon"      string ":1.23"      string ":1.12"      string ":1.13"      string ":1.0"      string ":1.14"      string ":1.1"      string ":1.15"      string ":1.2"      string ":1.16"      string ":1.3"      string "org.gnome.GkbdConfigRegistry"      string ":1.4"      string "org.fmddlmyy.Test"      string ":1.5"      string "org.gnome.SettingsDaemon"      string ":1.6"   ]

这是会话总线当前已连接的连接名。在d-feet窗口的左侧窗口显示的就是ListNames返回的连接名。聪明的读者也许已经想到使用消息总线的“org.freedesktop.DBus.ListNames”方法和各连接的“org.freedesktop.DBus.Introspectable.Introspect”,我们就可以像d-feet一样查看总线上所有连接的所有对象的所有接口的所有方法和信号。

你的想法很好。但有一个问题,我们必须对连接中的对象调用“org.freedesktop.DBus.Introspectable.Introspect”方法。 ListNames只列出了连接名,我们怎么获取连接中的对象路径呢?

答案很简单,如果我们不知道对象路径就从根目录开始吧。连接中的对象是按照树型结构组织的。我们遍历连接的对象树就可以找到所有的对象。调用对象的“org.freedesktop.DBus.Introspectable.Introspect”方法就可以查看对象的所有接口的所有方法和信号。例如:假设我们不知道连接"org.fmddlmyy.Test"里有什么对象,我们可以对根对象"/"执行:

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

输出为:

method return sender=:1.22 -> dest=:1.25 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="TestObj"/></node>"

"org.fmddlmyy.Test"的对象树的根节点只有一个子节点"TestObj",再查看"/TestObj":

$ dbus-send --session --type=method_call --print-reply --dest=org.fmddlmyy.Test /TestObj org.freedesktop.DBus.Introspectable.Introspect

输出为:

method return sender=:1.22 -> dest=:1.26 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.fmddlmyy.Test.Basic">    <method name="Add">      <arg name="arg0" type="i" direction="in"/>      <arg name="arg1" type="i" direction="in"/>      <arg name="ret" type="i" direction="out"/>    </method>  </interface></node>"

作为一个练习,让我们来查看系统总线的上的bluez接口。执行:

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

输出为:

method return sender=org.freedesktop.DBus -> dest=:1.30 reply_serial=2   array [      string "org.freedesktop.DBus"      string ":1.7"      string ":1.8"      string ":1.9"      string "org.freedesktop.SystemToolsBackends"      string ":1.30"      string "org.freedesktop.NetworkManagerInfo"      string ":1.20"      string "org.freedesktop.Avahi"      string ":1.21"      string "org.bluez"      string ":1.22"      string "org.freedesktop.NetworkManager"      string "org.freedesktop.ConsoleKit"      string ":1.23"      string "com.redhat.dhcp"      string ":1.13"      string ":1.0"      string ":1.14"      string ":1.1"      string ":1.15"      string ":1.2"      string "org.freedesktop.Hal"      string "com.redhat.NewPrinterNotification"      string ":1.16"      string ":1.3"      string ":1.17"      string ":1.4"      string ":1.18"      string ":1.5"      string ":1.19"      string ":1.6"   ]

我们看到连接"org.bluez"。查看它的根对象:

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

输出为:

method return sender=:1.7 -> dest=:1.31 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>"

接着查对象"/org":

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

输出为:

method return sender=:1.7 -> dest=:1.32 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="bluez"/></node>"

接着查对象"/org/bluez":

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

输出为:

method return sender=:1.7 -> dest=:1.33 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 name="/org/bluez">        <interface name="org.bluez.Manager">                <method name="InterfaceVersion">                        <arg type="u" direction="out"/>                </method>                <method name="DefaultAdapter">                        <arg type="s" direction="out"/>                </method>                <method name="FindAdapter">                        <arg type="s" direction="in"/>                        <arg type="s" direction="out"/>                </method>                <method name="ListAdapters">                        <arg type="as" direction="out"/>                </method>                <method name="FindService">                        <arg type="s" direction="in"/>                        <arg type="s" direction="out"/>                </method>                <method name="ListServices">                        <arg type="as" direction="out"/>                </method>                <method name="ActivateService">                        <arg type="s" direction="in"/>                        <arg type="s" direction="out"/>                </method>                <signal name="AdapterAdded">                        <arg type="s"/>                </signal>                <signal name="AdapterRemoved">                        <arg type="s"/>                </signal>                <signal name="DefaultAdapterChanged">                        <arg type="s"/>                </signal>                <signal name="ServiceAdded">                        <arg type="s"/>                </signal>                <signal name="ServiceRemoved">                        <arg type="s"/>                </signal>        </interface>        <interface name="org.bluez.Database">                <method name="AddServiceRecord">                        <arg type="ay" direction="in"/>                        <arg type="u" direction="out"/>                </method>                <method name="AddServiceRecordFromXML">                        <arg type="s" direction="in"/>                        <arg type="u" direction="out"/>                </method>                <method name="UpdateServiceRecord">                        <arg type="u" direction="in"/>                        <arg type="ay" direction="in"/>                </method>                <method name="UpdateServiceRecordFromXML">                        <arg type="u" direction="in"/>                        <arg type="s" direction="in"/>                </method>                <method name="RemoveServiceRecord">                        <arg type="u" direction="in"/>                </method>                <method name="RegisterService">                        <arg type="s" direction="in"/>                        <arg type="s" direction="in"/>                        <arg type="s" direction="in"/>                </method>                <method name="UnregisterService">                        <arg type="s" direction="in"/>                </method>                <method name="RequestAuthorization">                        <arg type="s" direction="in"/>                        <arg type="s" direction="in"/>                </method>                <method name="CancelAuthorizationRequest">                        <arg type="s" direction="in"/>                        <arg type="s" direction="in"/>                </method>        </interface>        <interface name="org.bluez.Security">                <method name="RegisterDefaultPasskeyAgent">                        <arg type="s" direction="in"/>                </method>                <method name="UnregisterDefaultPasskeyAgent">                        <arg type="s" direction="in"/>                </method>                <method name="RegisterPasskeyAgent">                        <arg type="s" direction="in"/>                        <arg type="s" direction="in"/>                </method>                <method name="UnregisterPasskeyAgent">                        <arg type="s" direction="in"/>                        <arg type="s" direction="in"/>                </method>                <method name="RegisterDefaultAuthorizationAgent">                        <arg type="s" direction="in"/>                </method>                <method name="UnregisterDefaultAuthorizationAgent">                        <arg type="s" direction="in"/>                </method>        </interface>        <node name="service_audio"/>        <node name="service_input"/>        <node name="service_network"/>        <node name="service_serial"/></node>"

我们看到了对象"/org/bluez"的所有接口。对象"/org/bluez"还有子节点"service_audio"、"service_input"、"service_network"和"service_serial"。必要时我们可以接着查下去。d-feet的基本逻辑就是这样。后面我们会自己实现一个dteeth。dteeth是命令行程序,可以遍历指定连接的对象树,列出所有对象的所有接口的方法和信号。

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 pu管两头固定了中间换截怎么办 自己架设的传奇不能注册帐号怎么办 天堂2第八章读取服务端错误怎么办 苹果手机王者荣耀下了不能玩怎么办 苹果手机摔了一下触屏失灵怎么办 华为机回复出厂设置帐号忘了怎么办 华为手机里突然有个pp助手怎么办 华为手机与电脑连接不上怎么办 买房交了首付贷不了款怎么办 手机买贵了实体店不肯退怎么办 在实体店里手机买贵了怎么办 红米手机开启不了安装系统怎么办? 捡个荣耀8双清后要账号怎么办 荣耀7x升级8.0后耗电快怎么办 手机提示当前为耳机播放模式怎么办 华为手机进水了显示耳机模式怎么办 苹果6s突然变成耳机模式怎么办 华为手机出现耳机标志没声音怎么办 苹果手机微信变成耳机模式怎么办 5s不能用4g网络怎么办 华为麦芒四手机系统乱了好卡怎么办 信翼路由器登录密码忘了怎么办 苹果手机电信4g信号变3g怎么办 苹果7手机4g变3g怎么办 朵唯v3逆客手机不支持计步怎么办 移动卡升级4g后网络不好怎么办 电信办宽带送的手机卡不用了怎么办 移动华为悦盒遥控器丢了怎么办 移动签了两年套餐不想用了怎么办 华为手机隐私空间密码忘记了怎么办 华为的隐私空间密码忘记了怎么办 格力新机没密码开不了怎么办 百度下载谷歌浏览器网页错误怎么办 华为手机进水开不了机怎么办开 华为7x金属外壳掉漆了怎么办 华为麦芒6连接蓝牙音响卡顿怎么办 华为芒麦6恢复出厂设置怎么办 华为麦芒4下拉通知栏没反应怎么办 怎么看华为麦芒6信号差怎么办 华为手机锁屏密码忘了怎么办 苹果手机进水后手机卡无服务怎么办