介绍
用户进程接口被称这个服务框架是这样的一种IPC机制,这个机制允许应用单元简便地使用或者服务于一个接口。在这个文档,用为“使用者”,而提供者进程接口被称为“提供者”。
这个服务框架的目的如下:
-
为了提供一个可简单使用的IPC机制
-
为了确保在服务的使用者和提供者之间没有运行时二进制依赖关系
-
为了允许用户在使用一个接口时不用担心选择或者连接到一个接口时的具体逻辑
-
为了允许用户能查询提供者的列表,并且能从中选择一个
基本的服务机制
上图展示了当一个服务端的用户(SU)使用一个接口(IF)时将发生什么.
-
服务端使用者举例,一个接口去请求服务映射器给出实现那个接口的服务提供者的名称
-
这个服务器映射器维护着一张服务和接口之间的映射关系表(通过查看dbus服务目录,通常为/usr/share/dbus-1/services这个目录)同时服务器映射器还有一套选择服务的规则.它选择一个服务,然后将服务的名称返回给SU的接口.
-
SU的接口接着创建一个正当的dbus连接到一个已经给出名称的服务,然后调用一个合适的方法
当IF有一个新的SP时,服务映射器就会发送一个信号给适当的SU接口通知他们,或者如果IF没有更多的SP,SU也会发送通知。当有事件发生时,应用程序将会通过连接到在IF中的一个信号得到通知并采取相应的动作。例如,一个图片应用程序可能希望允许一个用户通过EMAIL去发送一个照片,它可以监听“没有更多的SP给IF”这个信号,从而知道什么时候去使这个操作失效。
服务框架的典型使用案例
-
从一个应用程序的界面启动或显示另一个应用程序的指定画面。
-
在设备上得到一个有效的视频内容的列表或者缩略图
-
启动一个网页浏览器显示指定的页面
-
从一个有效的内容里选择或者显示指定图片
-
显示最近的联系人记录
-
显示2042年第13个星期五的日程安排
服务框架不应该被使用做一般的IPC通讯或者例如介于两个小程序之间的通讯,这些应该使用其他方法来完成,例如,使用像DuiValueSpace一样可以提供数值改变通知的数据后端的方法。
用法
作为一个服务提供者(SP)
SP的开发者需要准备2样东西:
二进制文件
当一个服务端用户应用程序试图连接到这个服务时,这个二进制文件将被加载(如果它没有正在运行)。
接口
服务端用户应用程序的开发者需要的文件包括如下内容:
-
duiservicefwbaseif.h/cpp文件,这些文件对于所有的接口层都是通用的
duiservicefwbaseif.h文件是libdui-dev包的一部分,duiservicefwbaseif.cpp会被编译到libdui,所以他们都是libdui0包的一部分 -
需要给接口提供XML文件,头文件,库和一个.serveice文件
接口特定的头文件和接口的XML文件将共同成为maemo-interfaces-dev包的一部分,然后相应的cpp文件需要编译到接口特定的库文件里面,这些库又是maemo-interfaces包的一部分。.service文件也将会成为maemo-interfaces包的一部分。
二进制文件
-
创建一个用于定义接口的XML文件.
如果你希望一个方法连接到当前的应用,你可以添加一个chainTask="true"属性到这个方法标签。如果你希望一个方法是异步的,你可以添加一个asyncTask="true"属性到这个方法的标签里。注意这些方法必须不含有任何的'out'参数。
例如:
<node>
<interfacename="com.nokia.TextProcessorInterface">
<methodname="reverse" chainTask="true">
<arg name="message"type="s" direction="in"/>
<arg name=""type="s" direction="out"/>
</method>
<method name="blinkScreen"asyncTask="true">
<arg name="message"type="s" direction="in"/>
</method>
</interface>
</node>
运行dui-servicefwgen工具,产生相关.h和.cpp文件,命令如下:
-
修改你的代码。
修改主要分为三个步骤,如下面的代码段所示:
MyService myService;
//2.创建一个适配器去连接dbus和myService中的方法
//按照QDBusAbstractAdaptor(),它必须是创建在堆上的,
//并且内存是由QDBusAbstractAdaptor管理的,因此不需要保存指针
new MyServiceIfAdaptor( &myService );
//3.连接到会话并注册这个服务
QDBusConnection connection =QDBusConnection::sessionBus();
boolret=connection.registerService("com.nokia.TextProcessor");
//继续程序剩余的部分编写
return app.exec();
接口
定义一个接口有三个步骤:
-
创建一个定义接口的XML文件与上面描述的是同一个XML文件.
-
运行dui-servicefwgen这个工具,产生.h和.cpp文件,命令如下:
- 需要产生服务相关的库.
以上的文件需要被放进maemo-interfaces包,库需要包含在maemo-interfaces里面,头文件和XML文件也需要包含在maemo-interfaces-dev中。
接口和方法的文档说明可以加在'<doc>''</doc>'之间,例如:
<doc>
<argtag="brief">brief documentation for the interface</arg>
<argtag="details">detailed documentation for theinterface</arg>
</doc>
<method name="showPage">
<doc>
<argtag="brief">brief documentation for showPage()method</arg>
<argtag="details">detailed documentation for showPage()method</arg>
</doc>
<arg name="targetPage"type="s" direction="in" />
<arg name="previousPage"type="s" direction="in" />
<arg name="" type="b"direction="out"/>
</method>
....etc
作为一个服务使用者
-
安装libdui-dev debian包,它会提供给你服务映射dbus守护进程,头文件和库文件。
-
安装maemo-interfaces-dev包(包含代理头、库和封装包的头文件)
-
添加-ldui和-l<接口名字>到你工程文件的LIBS中。
-
在你的源文件中,包含这个接口头文件,接着创建一个接口实例,然后调用serviceName()方法去得到这个接口的提供者
-
通过'isValid()'方法确认这个服务是否可用。
-
调用想要用的接口方法。
-
实现并连接slots以处理有服务映射器发送出来'serviceAvailable()','serviceUnavailable()' 和'serviceChanged()'这些signals
演示和代码例子
在libdui/demos/servicefw/中,有个例子示范了3个服务提供者和一个服务使用者。com.nokia.textprocessor和org.maemo.textprocessor服务都实现了相同的接口-com.nokia.TextProcessorInterface.因为有2个服务,所以我们可以尝试去移除服务,然后观察服务用户从一个服务转换到另一个。有一个脚本工具/dui-servicefwgen,这个脚本工具被用来产生源文件,这些源文件是被用来给服务用户定义接口的。下面开始运行这个演示:
-
cd libdui
-
qmake && make && make instal(或者在duiservicemapper目录中至少执行一个make iinstall的操作)
-
cd demos/servicefw
-
pushd misc; sudo ./INSTALL; popd(这个操作将把dbus服务的相关文件安装到/usr/share/dbus-1/services目录中)
-
LD_LIBRARY_PATH=lib bin/user
-
这一步将打开一个小窗口允许你输入字符,这些字符将通过接口发送到一个服务中,而服务将返回被反转后的字符。
在这个演示中,你可以从/usr/share/dbus-1/services中移除若干个服务去模拟服务被移除的情况(然后再添加),以此来验证服务使用者程序是否能执行正确的操作。