OSGI服务层

来源:互联网 发布:淘宝天猫开店要求 编辑:程序博客网 时间:2024/04/29 17:48

5.1. 简介

OSGi服务层定义了一个和生命周期层紧密结合的动态协作模型。服务模型包括发布、查找和绑定模型。一个服务(service)就是一个在服务注册中心注册的在一个或者多个Java接口下的Java对象。bundle可以注册服务,查找服务,接收注册服务状态改变的通知。

5.1.1.    要点

l         协作性 服务层必须为bundle提供一种机制来发布、查找和绑定到其它服务,而无需事先知道其它bundle的信息。

l         动态性 服务层机制必须能够直接处理外界或者是底层结构的变化。

l         安全 必须能够限定对服务的访问。

l         深入性 对服务层的内部状态可以进行完全控制。

l         版本控制 提供对bundle以及对它们服务更新的控制。

l         唯一性标识 在框架重启过程中帮助bundle跟踪服务。

5.1.2.    名词

l         服务(Service在一个或多个接口下并在服务注册中心已注册的具有属性值的类。可以被bundle查找发现并使用。

l         服务注册中心(Service Registry 保持服务注册。

l         服务引用(Service Reference对一个服务的引用。提供对一个服务属性的访问但不是对实际的服务对象。对服务对象的访问必须要通过bundleBundleContext来进行。

l         服务注册(Service Registration)项当一个服务注册之后提供的凭据。服务注册项允许对服务属性进行更新和取消注册。

l         服务权限(Service Permission当注册或者使用一个服务的时候,使用一个接口名的权限。

l         服务工厂(Service Factory由提供服务的bundle来为每一个使用服务的bundle定制一个服务对象的便捷方法。

l         服务监听器(Service Listener服务事件监听器。

l         服务事件(Service Event一个包含了服务对象的注册、更改、取消注册信息的事件。

l         过滤器(Filter实现了一个简单但是功能强大的过滤器语言的对象。可以用于属性选择。

l         语法错误异常(Invalid Syntax Exception当一个过滤器表达式包含错误的时候抛出的异常。

5.2. 服务

OSGi服务平台下,bundle建立在一系列的相互协作的可用服务之上,这些服务共享一个服务注册中心。这样一个OSGi服务在语义上通过它的服务接口来定义,并实现为一个服务对象。

在服务接口中应该尽可能少的指定实现细节。OSGi规定了很多常用的服务接口,以后还会增加。

服务对象是属于bundle的,而且在bundle之内运行。bundle必须要将服务对象注册到框架的服务注册中心,这样,才可以在框架的控制下来为其他bundle提供服务。

提供服务的bundle和使用服务的bundle之间的依赖关系由框架来进行管理。例如,当停止一个bundle后,这个bundle在框架中注册的服务必须要自动的取消注册。

框架将服务映射到底层的服务对象,并提供了一种简单而强大的查询机制,通过使用这种机制,bundle就可以请求它需要的服务。框架也提供了一种事件机制,这样,bundle就可以接收到服务注册、更改和取消注册的消息。

5.2.1.    服务引用

通常,注册的服务是通过一个ServiceReference对象来引用的。这样,在bundle只需要一个服务而不是一个服务对象的情况下,就可以避免创建bundle之间的不必要的动态服务依赖关系

可以把一个ServiceReference对象保存并发送给其他bundle,而不会带来依赖关系。当bundle需要使用服务时,就可以通过将ServiceReference对象作为方法getService的参数来获取服务,即为BundleContext. getService(ServiceReference)。详情参阅服务定位一节。

ServiceReference对象中封装了服务对象的属性和其他元数据信息。其他bundle可以通过查找元数据信息来选择最合适的服务。

bundle在框架的服务注册中心查找服务时,框架必须将请求服务目标的ServiceReference对象发送给发出查找请求的bundle,而不是直接发送服务对象本身。也可以通过ServiceRegistration对象来得到一个ServiceReference对象。

只有当服务对象注册之后,ServiceReference对象才是有效的。不过只要ServiceReference对象存在,那么它的属性就是可用的。

5.2.2.    服务接口

在服务接口中定义了服务的公有方法。实际上,bundle的开发人员通过实现服务接口来创建一个服务对象,并将其注册到框架的服务注册中心。一旦bundle通过一个接口名称注册了一个服务对象,那么bundle就可以通过这个接口名称来获得相关服务,并可以通过接口中定义的方法来使用服务。同时,框架也支持使用类名称来注册服务,因此,在本规范中,服务接口可以理解为接口或者类。

当从框架来请求一个服务时,bundle可以指定提供服务的对象必须要实现的服务接口名称。在请求中,bundle也可以通过一个过滤器字符串来限定搜索范围。

5.2.3.    注册服务

bundle通过在框架的服务注册中心注册一个服务对象来发布一个服务。那么安装在OSGi环境下的其它bundle就可以访问到在框架中注册的服务对象。

每一个注册服务对象都有一个惟一的ServiceRegistration对象,而且有一个或者多个引用的ServiceReference对象。这些ServiceReference对象公开了服务注册的属性,包括服务实现的一系列接口信息。可以使用ServiceReference对象来获取实现了特定接口的服务对象。

在框架中,允许bundle动态的注册和取消注册服务对象。因此,bundle可以在STARTINGACTIVE 或者 STOPPING状态下注册服务对象。

bundle通过使用BundleContext.registerService方法,在框架中注册一个服务对象:

l         registerService(String,Object,Dictionary) – 一个服务对象注册在一个服务接口名下。

l         registerService(String[],Object,Dictionary) – 一个服务对象注册在多个服务接口名下。

bundle需要将注册的服务对应的服务接口名称以参数形式提供给registerService方法。框架必须要确保服务对象是指定的服务接口的一个实例,或者这个对象是一个服务工厂。参阅服务工厂一节。

为了进行上述检查,框架必须要从bundle或者一个共享包中为每一个指定的服务接口加载Class对象。对于每一个Class对象,必须以服务对象为参数并调用其Class.isInstance方法,返回结果必须为true

以后,需要注册的服务对象可能会进一步使用一个Dictionary对象来补充描述,在这个Dictionary 对象中,包含了服务的属性的键值对序列。

如果一个服务对象成功注册,则将它注册的服务接口名称自动添加到服务对象的objectClass属性下。这个值必须由框架来自动设置并覆盖由bundle提供的值。

服务对象成功注册之后,框架必须给调用者返回一个ServiceRegistration对象。对服务的取消注册只能由ServiceRegistration对象(参阅unregister方法)的持有者进行。即使对一个服务对象进行了多次注册,每次成功注册都必须产生一个惟一的ServiceRegistration对象。

在服务对象注册后对它的属性进行可靠更改的惟一途径是使用ServiceRegistration对象(参考setProperties方法)。在服务对象注册之后对它的Dictionary对象进行更改可能不会对服务属性有任何影响。

服务对象的注册处理过程包含了权限检查。注册服务的bundle必须要有ServicePermission权限:ServicePermission [<interface name>,REGISTER],用来注册一个指定了所有服务接口的服务对象。否则不能注册服务对象,并抛出一个安全异常(SecurityException)。

5.2.4.    服务注册对象的过早请求

服务对象注册会通知所有已注册的ServiceListener对象。这是一个同步发送的过程。也就是说监听器可以在registerService方法返回SeviceRegistration对象之前就访问服务并调用它的方法。特定情况下,在这种回调中需要访问到ServiceRegistration对象。但是,注册服务的bundle还没有接收到ServiceRegistration对象。下图展示了这样一个序列:

在前面的例子中,可以通过ServiceFactory对象来获取对注册对象的访问。如果已经注册了一个ServiceFactory对象,框架必须在通过ServiceFactorygetService(Bundle,ServiceRegistration)方法回调正在注册的bundle。所需的ServiceRegistration将作为参数传递给该方法。

5.2.5.    服务属性

属性信息保存在键值对中。键值为一个字符串对象,值则为Filter对象可以识别的类型。如果一个属性有多个值,则可以使用数组和Vector对象。

属性值应该限定为标准或原始的Java类型,以防止对bundle内部的依赖。框架不能检测到bundle之间通过交换服务属性产生的依赖关系。

属性键名称是不区分大小写的。ObjectClassOBJECTCLASSobjectclass都是指同样的含义。如果调用方法ServiceReference.getPropertyKeys,那么框架必须返回它上次设置的属性值。如果Dictionary对象中存在只是大小写不同的键,那么框架必须要抛出一个异常。

服务属性提供了服务对象的信息,不应该将这些属性值用于服务的实际功能中。对注册服务的属性值更改是一种潜在的代价颇高的操作。例如,框架可能会提前将属性值加入到索引中以加快以后的查找速度。

Filter接口支持复杂的过滤规则;可以用于查找匹配的服务对象。因此,框架的服务注册中心中所有属性共享一个名称空间。因此为了防止产生名称冲突,需要使用描述性名称或者是形式化定义的更短的名称来区别不同的属性。所有的属性名称前缀为service.同时在OSGi规范中保留了objectClass属性关键字。

下表描述了预定义的标准服务属性:

属性

类型

常量

描述

objectClass

String[]

OBJECTCLASS

objectClass属性包含了注册到框架中的服务对象所对应的接口的集合。这个属性必须由框架自动设置。框架必须要保证通过BundleContextgetService方法获取的服务对象可以造型(cast)为属性中指定的任何接口名称。

service.description

 

String

SERVICE_DESCRIPTION

service.description属性用于文档性的描述,这个属性是可选的。在框架和bundle中可以利用这个属性来对其提供的服务注册对象作一个简短的描述。这个属性的主要目的在于进行调试,这是由于没有对这个属性的本地化支持。

service.id

 

Long

SERVICE_ID

每一个注册了的服务对象都由框架分配了一个惟一的service.id。这个标识数字被添加到服务对象的属性中。框架给每一个注册的服务对象分配一个惟一的标志值,这个值要比之前注册的所有服务对象所分配的值都要大,也就是说是递增分配的。

service.pid

 

String

SERVICE_PID

service.pid属性是可选的,标记了服务对象的持久惟一标记。

service.ranking

 

Integer

SERVICE_RANKING

当注册一个服务对象时,bundle可以选择性地指定一个service.ranking数字作为服务对象的属性值。如果存在多个可用的服务接口,那么如果一个服务对象具有最大的SERVICE_RANKING值或者是它的值等于最小的SERVICE_ID值,那么就由框架返回这个服务对象。

service.vendor

 

String

SERVICE_VENDOR

这是一个可选属性,描述服务对象的开发商信息。

5.2.6.    持久标识符(PID

持久标识符(PID)可在在框架重启之后标识服务。对于每次注册引用同一个实体的服务来说,应该使用包含了PID的服务属性。PID的服务属性名定义为service.pidPID是服务横跨框架的多次启动的惟一标记。对于给定的服务,应该总是使用相同的PID。如果停止了一个bundle之后又重新启动它,那么必须使用相同的PID

PID的格式如下所示:

pid ::= symbolic-name  // 参考 1.4.2

PID对于每一个服务来说是惟一的。bundle不能使用同样的PID来注册多个服务,而且也不能和其他bundle使用相同的PID,如果使用了相同的PID,那么这是一种错误的用法。

5.2.7.    服务定位

为了使用一个服务对象并调用它的方法,bundle必须首先获得服务的ServiceReference对象,在接口BundleContext中定义了两个方法来从框架中获取一个ServiceReference对象:

l         getServiceReference(String) – 这个方法返回一个引用某服务对象的ServiceReference对象,该服务对象实现并以指定的接口进行注册。如果存在多个这样的服务对象,将返回具有最大SERVICE_RANKING值的服务对象。如果在队列中存在多个符合这样条件的服务对象,将返回具有最小SERVICE_ID值的服务对象(也就是最先注册的)。

l         getServiceReferences(String,String) – 这个方法返回一个ServiceReference对象数组,返回数据符合以下条件:

l         实现并以指定的服务接口进行注册

l         符合指定的查找过滤器条件。在Filter一节中将详细解释过滤器语法。

如果没有找到符合条件的服务对象,那么上述两个方法都返回null值。否则,调用者接收到一个或多个ServiceReference对象。可以通过ServiceReference对象来取得底层服务对象的属性值,ServiceReference对象还可以用于BundleContext对象获取实际的服务对象。

这两种方法的调用都需要调用者具有ServicePermission[<接口名>, GET]来通过指定服务接口获得服务对象。如果调用者没有权限,那么这两个方法都是返回null值。

5.2.8.    获取服务属性

为了允许访问服务对象,ServiceReference接口定义了以下两种方法:

l         getPropertyKeys() – 返回所与可用的属性键数组。

l         getProperty(String) – 返回指定键名称的键值。

即使从框架中取消注册了引用的服务对象,也可以通过上述方法来获得服务对象的信息。当ServiceReference对象和日志服务关联时,这种机制就非常有用。

5.2.9.    获取服务对象

通过使用BundleContext对象来获取一个实际的服务对象,这样框架就可以来管理这些依赖关系了。如果一个bundle获取一个服务对象,这样这个bundle就依赖于注册的服务对象的生命周期。对于这种依赖可以通过可以获取服务对象的BundleContext对象来跟踪,这也就是为什么在bundle之间共享BundleContext对象需要非常的小心。

BundleContext.getService(ServiceReference)方法返回的对象实现了objectClass属性中定义的接口。getService方法有以下特征:

l         如果服务对象取消注册之后,那么方法返回null值。

l         检查调用者是否有权限:ServicePermission[<接口名>,GET],至少需要有一个注册的服务接口的权限。权限检查是非常有必要的,这样就可以传递ServiceReference对象而无须考虑泄密这样的安全问题。

l         BundleContext中对服务对象的使用计数加一。

l         如果服务对象没有实现ServiceFactory接口,那么直接返回该对象。否则如果BundleContext中该服务对象的使用计数为0,该对象造型(cast)为一个ServiceFactory 对象,并调用getService方法创建并返回一个定制的服务对象。否则返回该定制对象的缓存拷贝。关于ServiceFactory对象参阅服务工厂一节。

5.2.10.             服务的其它信息

Bundle接口中定义了以下两种方法来返回bundle中与服务使用有关的信息:

l         getRegisteredServices() – 返回bundle在框架中注册的服务对象。

l         getServicesInUse() – 返回bundle使用的服务对象。

5.3. 服务事件

l         ServiceEvent – 报告服务对象的注册、取消注册和属性改变事件。所有这些事件都是同步发送的。可以通过getType方法来获取事件的类型,这个方法返回的类型是int类型的,关于事件类型的定义以后可能会扩充,而不可识别的事件类型则被忽略。

l         ServiceListener – 当对一个服务对象已注册或改变,或者是在取消注册的过程中时调用ServiceListener。。当一个ServiceEvent发生之后,对于每一个注册的监听器必须要对其进行安全检查。只有注册监听器的bundle对服务对象注册对应的接口中的至少一个接口具有以下权限时:ServicePermission[<接口名>,GET],才可以调用监听器。

使用服务对象的bundle应该注册一个ServiceListener对象来跟踪服务对象的可用性,并在取消注册服务对象时采取合适的动作。

5.4. 过期引用

框架必须要管理bundle之间的依赖关系。这种管理受限于框架的结构。bundle通过监听框架产生的事件来清理和移除过期引用。

过期引用是指对这样一个Java对象的引用,这个对象所在的类加载器所属的bundle已经停止,或者所关联的服务对象已经是取消注册了。标准Java处理中并没有提供任何方法来清除这些过期引用,这就需要bundle的开发人员必须对他们的代码进行分析,并确保删除了过期引用。

过期引用存在潜在的危害,这是由于它们阻止了Java的垃圾收集器对已经停止的bundle的类以及可能的实例进行回收。这样就会导致显著的内存消耗,并可能使得对本地代码的更新失败。因此,强烈建议使用服务的bundle使用服务跟踪器(Service Tracker)或者是公布服务(Declarative Services)。

服务开发人员可以通过使用如下机制来减小(并不能完全消除)过期引用的危害:

l         通过使用ServiceFactory接口来实现服务对象。ServiceFactory接口中的方法可以简单跟踪使用服务对象的bundle。参阅服务工厂一节。

l         间接使用服务对象。服务对象提供给其他bundle的应该是一个对实际服务对象的一个指针。当服务对象不可用之后,将指针设置为null值,这样就有效的移除了对实际服务对象的引用。

一个已经取消注册的服务的行为是不确定的。这些服务也许可以正常工作,也许会抛出一个异常。应该将这种类型的错误记录到日志中。

5.5. 过滤器

框架提供了一个Filter接口,并且在方法getServiceReferences中使用过滤器语法(在过滤器语法一节中定义)。通过调用BundleContext.createFilter(String)方法或者是FrameworkUtil.createFilter(String)方法来创建一个Filter对象,方法参数为一个过滤规则字符串。过滤字符串支持以下匹配方法:

l         match(ServiceReference) – Service Reference的属性进行匹配,匹配不区分大小写。

l         match(Dictionary) – 对给定的Dictionary对象中的条目进行匹配,也是不区分大小写的。

l          matchCase(Dictionary) –对给定的Dictionary对象中的条目进行匹配,不同之处在于是区分大小写的。

一个Filter对象可反复使用,判断参数ServiceReference对象或者Dictionary对象是否和通过过滤器字符串创建的过滤器相匹配。

匹配的过程需要将过滤器中的字符串和来自服务属性或者是Dictionary的目标对象进行比较。如果目标对象的类实现了带有一个字符串参数的构造方法,并且实现了Comparable接口,那么就可以通过Comparable接口来进行比较。也就是说,如果目标对象是一个Target类,那么这个Target类必须实现:

l         构造方法Target(String)

l         实现了接口java.lang.Comparable

如果目标类没有实现接口Comparable,那么当对象相等(使用equals方法),对对象使用操作符=~=<=>=将只能返回trueTarget类不一定要是public类,下面的例子说明了类可以通过过滤器对一个枚举分类进行校验:

public class B implements Comparable {

String keys[] = {"bugs", "daffy", "elmer", "pepe"};

int index;

public B(String s) {

for ( index=0; index<keys.length; index++ )

if ( keys[index].equals(s) )

return;

}

public int compareTo( Object other ) {

B vother = (B) other;

return index - vother.index;

}

}

可以对这个类使用如下过滤器:

(!(enum>=elmer)) -> matches bugs and daffy

方法Filter.toString必须返回一个不带空格的过滤字符串。

5.6. 服务工厂

通过服务工厂,可以在bundle调用方法BundleContext.getService(ServiceReference)时返回一个定制的服务对象。

通常,对一个bundle注册的服务对象的调用是直接返回这个服务对象。但是,如果这个注册的服务对象实现了ServiceFactory接口,那么框架必须调用这个服务对象的方法来为每一个使用服务的bundle创建一个惟一的服务对象。当bundle不再使用服务对象——比如停止了bundle之后——那么框架必须要将事件通知ServiceFactory对象。

可以用ServiceFactory来管理bundle间的依赖关系,而框架并没有很明确的管理这种依赖关系。通过绑定一个请求bundle的返回服务对象,那么当bundle停止使用服务之后,比如停止bundle,服务对象就可以接收到事件通知,然后就可以释放提供给那个bundle的服务资源。

ServiceFactory接口中定义了以下方法:

l         getService(Bundle,ServiceRegistration) –如果调用BundleContext.getService方法且满足下述条件,则由框架调用这个方法:

l         BundleContext.getService中的参数ServiceReference关联的服务对象实现了ServiceFactory接口。

l         bundle对那个服务对象的使用计数是0,也就说bundle当前并没有对这个服务对象的任何依赖。

对方法BundleContext.getService的调用请求最终由框架转发到getService方法,并传入调用者的bundle对象。框架必须缓存请求的bundle-to-service映射,一旦以后bundle对这个服务对象的使用计数大于0BundleContext.getService方法调用直接返回已缓存的服务对象。

框架必须检查方法返回的服务对象。如果它不是服务工厂注册时的类的一个实例,那么getService方法的返回值为null。这种检查必须遵循注册服务一节中描述的规范。

l         ungetService(Bundle,ServiceRegistration,Object) – 如果调用BundleContext.ungetService方法且满足下述条件,则由框架调用这个方法:

l         BundleContext.getService中的参数ServiceReference关联的服务对象实现了ServiceFactory接口。

l         调用返回之后,bundle对服务对象的使用计数降为零,也就说bundle即将释放对这个服务对象的依赖。

对方法BundleContext.getService的调用请求最终由框架转发到getService方法,这样ServiceFactory对象就可以将之前创建的服务对象释放。

另外,服务对象之前创建的缓存拷贝必须是和框架无引用关联关系,这样就可以通过gc进行回收。

5.7. 服务释放

如果bundle需要释放一个服务对象,那么bundle必须移除它和注册服务的bundle之间的动态依赖。在接口BundleContext中定义了一个方法来释放服务对象:ungetService(ServiceReference),这个方法的参数为一个ServiceReference对象。

该方法返回一个布尔值:

l         false:如果调用方法时,bundle对服务对象的使用计数为0,或者服务对象已经取消注册。

l         true:如果调用方法时,bundle对服务对象的使用计数大于0

5.8. 取消注册服务

在接口ServiceRegistration中定义了方法unregister()来取消注册一个服务对象。这个方法必须从框架的服务注册中心移除指定服务对象。ServiceRegistration对象的ServiceReference对象不能再用于访问服务对象。

ServiceRegistration对象中的这个方法的实际作用在于确保了只有拥有这个对象的bundle才可以取消注册相关的服务对象。但是取消服务注册的bundle与注册服务的bundle可能不是同一个bundle。例如,注册服务的bundleServiceRegistration对象发送给另一个bundle,这样,就将取消注册服务的职责赋予给另一个bundle。对ServiceRegistration对象的传递应该特别小心。

方法ServiceRegistration.unregister成功返回之后,服务对象必须满足如下要求:

l         从框架的服务注册中心完全的移除了。因此,服务对象的ServiceReference对象也就不能再用于进行访问服务对象了。对方法BundleContext.getService的调用也将返回null值。

l         处于未注册状态,即使存在其他bundle的依赖。所有的bundle都应该接收到取消注册的事件通知,事件类型是ServiceEvent.UNREGISTERING。这个事件是同步发送的,这样其他bundle就有机会释放服务对象。

bundle接收到ServiceEvent.UNREGISTERING事件之后,bundle应该释放服务对象,释放对这个对象的任何引用,这样Java VMgc就可以回收服务对象的资源。

l         被所有使用该服务对象的bundle释放。对于调用事件监听器之后, bundle对服务对象的使用计数仍然大于0的情况,由框架负责对使用计数清零,并释放服务对象。

5.9. 多版本导出

允许多个bundle导出同名的包给框架实现和bundle开发带来了复杂度:类名不能用来惟一标识导出的类。这影响到了服务注册中心和权限的检查。

5.9.1.    服务注册中心

bundle不能暴露存在冲突的类加载器的服务。bundle获取的服务应该是可以安全的造型(cast)为服务注册时登记的接口或者类,并且应该是可以访问获取的服务。而不能因为这些接口来自于不同的类加载器就抛出类声明异常(ClassCastExceptions)。而服务注册中心应该确保bundle所访问的服务都是和自己没有冲突的。bundle获取的服务是没有冲突的是指:和注册服务的bundle相比较,这个bundle没有和接口包的另一个类加载器进行连接。也就是说,它要么连接到同一个类加载器,要么就和那个包没有进行连接。

要求bundle中不能有存在冲突的服务是非常重要的,因此,可以通过以下方法来过滤那些和bundle冲突的ServiceReferenc对象。通过BundleContext对象来标记bundle

l         getServiceReference(String) – 返回和调用bundle的指定接口不冲突的一个ServiceReference对象。

l         getServiceReferences(String,String) – 返回和调用bundle的指定接口不冲突的多个ServiceReference对象。

方法getAllServiceReferences(String,String)提供了对服务注册中心的所有没有任何兼容约束的服务的访问,通过这个方法获取的服务可能会导致抛出ClassCastException

ServiceReference类中定义的方法isAssignableTo(Bundle,String)也可以用来测试这个ServiceReference对象所关联的注册服务对应的bundle和指定的bundle是否连接到了同一个指定接口源。

5.9.2.    服务事件

服务事件只发送到和ServiceReference不冲突的事件监听器。

而有一些bundle需要监听所有的服务事件而不考虑是否存在冲突的问题。因此增加了一种新的服务监听器:AllServiceListener。这是一个标记接口,扩展自ServiceListener。使用了这个标记接口的监听器向框架标明了它们需要可以访问到所有的服务,包括存在冲突的服务。

5.10.    安全

5.10.1.             服务权限控制

ServicePermission中包括以下参数:

l         接口名(Interface Name) – 接口名可能以一个通配符结尾,可匹配多个接口名称(关于通配符详见java.security.BasicPermission)。

l         Action – 支持的Action包括:

l         REGISTER – 权限的持有者可以注册这个服务对象。

l         GET – 权限持有者可以获取服务。

当使用BundleContext.registerService来注册一个服务对象时,申请注册的bundle必须对要注册的所有的命名类拥有ServicePermission权限。参阅服务注册一节。

当通过BundleContext.getServiceReference或者BundleContext.getServiceReferences来获取一个ServiceReference对象时,申请调用的bundle必须对指定命名类的服务对象拥有ServicePermission[<接口名>, GET]权限。参阅服务引用一节。

当通过BundleContext.getService(ServiceReference)方法来获取一个服务对象,调用方法的代码必须对服务对象所注册的类拥有至少一个类的ServicePermission[<name>, GET]权限:

ServicePermission必须当作服务监听器接收的服务事件的过滤器,同时也是列举服务方法的过滤器,方法包括了Bundle.getRegisteredServicesBundle.getServicesInUse。框架必须要确保bundle不能够检测到它没有权限访问的服务的状态。

原创粉丝点击