JAVA服务框架是一系列类的集合, 这些类用于支持开发JAVA系统服务, 这些服务运行在基于JAVA的应用程序框架中。
JAVA服务框架通过JNI与本地框架进行交互, 这样可以重用一些由C/C++编写的代码。
JAVA服务框架与本地服务框架的不同有如下两点:
<1>服务生成:
在JAVA服务框架中, 开发JAVA服务的方法有两种。
第一种是集成Binder类进行开发,这种方式常常用于开发可以实现精确控制的服务中,开发JAVA系统服务时常用这种方式。
Android提供了AIDL语言及编译器,使得编写JAVA系统服务比编写本地系统服务要容易得多。
第二种是继承Service类进行开发, 常常用来开发一些周期执行某些任务的后台服务。
<2>Binder IPC处理:
为了支持Binder IPC, JAVA服务框架将通过JNI使用本地服务框架中的相应组成部分。
JAVA服务管理
<1>与本地系统服务一样, JAVA系统服务注册到Context Manager中, 而后通过Service Manager使用服务。
<2>JAVA应用程序服务由Activity Manager Service而非Context Manager进行管理。
1. JAVA服务框架的层次结构
JAVA服务框架由服务层, RPC层, IPC层三个层构成。
图 JAVA服务框架构成
<1>服务层
与本地服务不同, 需要自己实现FooManager类, 因为SDK包中并不包含ServiceManager类, 应用程序服务使用ServiceManager类来注册或检索服务。
为了让应用程序开发者能够使用系统服务,服务开发者必须将包装类包含到SDK中。
例如, 为了让应用程序开发者能够使用FooService, 系统服务开发者就要编写FooManager包装类, 添加使用ServiceManager获取FooService的功能。
并将其编入SDK中。然后应用程序开发者就可以通过包含在SDK中的FooManager类来使用FooService系统服务了。
图 FooManager包装类的作用
<2>RPC层
JAVA服务框架使用Android平台中的AIDL语言与编译器自动生成服务代理和服务Stub。
首先编写IFooService.aidl文件, 在其中定义服务接口。
然后编译器会自动生成IFooService.Stub与IFooService.Stub.Proxy两个类。
<3>IPC层
使用JAVA服务框架开发的服务与服务代理通过Binder IPC进行交互
为了支持Binder IPC, 本地服务框架提供了BpBinder和BBinder两个类, JAVA服务框架则提供了BinderProxy与Binder两个类。
JAVA服务框架也可以通过JNI使用本地服务框架的Binder IPC,即BidnerProxy与Binder通过JNI使用本地服务框架的BpBinder与BBinder类的功能。
图 BinderProxy与Binder的Binder IPC
2. JAVA服务框架中各个类间的相互作用
首先先看一下客户端
服务客户端与本地服务框架相比, JAVA服务框架在服务客户端中多了两个调用过程
分别是服务用户调用FooManager的foo方法 与BinderProxy的transact方法通过JNI本地函数android_os_BinderProxy_transact调用BpBinder的transact函数的过程。
当BpBinder的transact函数调用执行后, 接下来的过程就与在本地服务框架中的内容一样了。
图客户端内部相互作用
接着再看一下Java系统服务所在的Service Server
在Java服务框架中多了BBinder的transact函数使用JavaBBinder本地服务Stub调用Binder的exacTransact方法的过程。
图Service Server内部相互作用
下面分析一下FooService服务注册到系统以及使用的过程。
图使用FooService时各个部分间的相互作用
<1> 请求服务注册:在向系统注册服务时, 本地服务框架将通过本地服务管理器BpServiceManager来处理服务注册,
而Java服务框架则使用JAVA服务管理器ServiceManager来处理服务注册。
FooService服务在向系统注册时将调用ServiceManager的addService方法, 在ServiceManager内部存在BinderProxy对象,
它通过JIN与持有ContextManager指针的BpBinder连接在一起。
<2>注册服务:ServiceManagerProxy服务代理将调用addService方法的信息转换为RPC数据。
Binder RPC数据被存储在Parcel(Java)类中传递给BinderProxy,而后通过JNI传递给BpBinder,最后通过Binder IPC传递给Context Manager,
如此, FooService服务即被注册到系统之中。
<3>请求服务检索:在使用FooService服务时, 本地服务用户将通过BpServiceManager来检索服务,
而JAVA服务则会调用SDK中的getSystemService方法来检索服务。
<4>服务检索:调用getSystemService方法将引起ServiceManager的getService方法的调用, 在系统中检索FooService服务。
若检索到FooService, 则会向服务用户返回FooManager对象, 该对象可以引用IFooService.Stub.Proxy服务代理。
<5>调用foo服务代理方法:服务用户调用FooManager的foo方法,而后IFooService.Stub.Proxy将foo方法的调用信息转换为RPC数据,
通过BinderProxy传递给BpBinder。
<6>执行foo服务Stub方法:BBinder从Binder Driver接收Binder RPC数据后, 通过JavaBBinder调用Binder的execTransact方法,
而后RPC数据传递给IFooService.Stub服务Stub的onTransact方法, 经过分析后, 调用FooService的foo服务Stub方法。
Java服务框架最重要的特征就是通过JNI复用本地服务框架提供的功能。
使用Java服务框架实现的系统服务被包含在应用程序中, 其中一部分可以使用在SDK中, 在开发应用程序时,
应当额外提供服务管理器(Service Manager)的包装类, 以便使用系统服务。
Android系统也提供了一种接口描述语言AIDL用来自通为服务接口生成服务Stub与代理。
3. 运行机制
下面通过源码分析Java服务框架使用本地服务框架的运作机制。
<1>Java服务框架初始化
在app_process进程启动时, AndroidRuntime类就会调用startReg函数, 将JNI函数加载到Dalvik虚拟机中。
使用register_android_os_Binder函数注册的JNI本地函数就是与JAVA服务框架有关联的本地函数。
图register_android_os_Binder函数
<2>Binder类
注册完JNI函数后, Binder类的本地方法将被映射到JNI本地函数中。
图Binder类的本地方法与JNI本地函数的映射关系。
<3>生成Binder对象
为了进行Binder IPC, 使用BBinder提供的功能, Binder类中生成Binder对象的同时将生成BBinder对象。
Binder类中构造方法中调用init本地方法, init本地方法与JNI的android_os_Binder_init函数映射在一起。
android_os_Binder_init函数首先生成JavaBBinderHolder类的对象, 而后调用名称为SetIntField的JNI函数,
将刚创建的JavaBBinderHolder对象的地址保存到Binder的mObject变量中。
图 android_os_Binder_init函数
<4>生成JavaBBinder对象
在创建Binder对象的同时会生成BBinder对象,JavaBBinder是对象是在JavaBBinderHolder的get函数中创建的,
在get函数中直接调用JavaBBinder类的构造函数, 生成了JavaBBinder对象。
JavaBBinder类继承并实现了父类BBinder, 创建JavaBBinder对象时也会生成BBinder对象。
图 JavaBBinderHolder的get函数
下面简单描述了生成BBinder对象的过程
图 生成BBinder对象
<5>Binder类与JavaBBinder服务Stub的相互作用
BBinder的transact函数将引起对JavaBBinder的onTransact函数的调用。除了基本的Binder RPC函数外, 若想扩展BBinder的功能,
需要在继承BBinder的服务Stub类中重新定义onTransact方法。
JavaBBinder服务Stub类继承了BBinder类, 重定义了onTransact方法,在其中调用了Binder的execTransact方法。
4. BinderProxy
<1>BinderProxy类的JNI设定
如同Binder类, 使用BinderProxy类之前, 也需要先将BinderProxy类本地方法对应的JNI本地函数注册到虚拟机中。
调用int_register_android_os_BinderProxy函数时, BinderProxy类的本地方法与JNI本地函数映射在一起。
<2>生成BinderProxy对象
BinderProxy类中执行Binder IPC时需要使用本地服务框架的BpBinder功能, 因此在创建BinderProxy对象时将同时生成BpBinder对象。
前面讲过BpBinder对象是由Parcel(c++) 的readStrongBinder函数创建的。
因此, BinderProxy对象是在调用Parcel(java)的readStrongBinder方法时生成的。当调用Parcel(java)的readStrongBinder方法时,
Parcel(c++)的readStrongBinder函数以及javaObjectForBinder函数将一次被调用, 从而生成BpBinder与BinderProxy对象。
如下图
图 生成BinderProxy对象-调用Parcel(java)的readStrongBinder方法
<3>BinderProxy类与 BpBinder类的相互作用
由于BinderProxy的transact本地方法与JNI本地函数android_os_BinderProxy_transact映射在一起
所以,当调用BinderProxy的transact本地方法时, android_os_BinderProxy_transact函数即会被调用。
在android_os_BinderProxy_transact函数中,获取到mObejct变量中的BpBinder对象地址, 而后调用transact函数。
5. Parcel
在BinderIPC期间, Parcel(java)类用来保存由发送端向接收端发送的数据。
特别地, Parcel(java)内部缓冲区中持有IBinder对象的引用, 并且在进程间移动时需要维持这个引用。
<1>Parcel(java)类的JNI设定
Parcel(java)类的本地方法通过JNI与Parcel(c++)类中的同名的本地成员函数映射在一起,
调用int_register_android_os_BinderProxy函数时, Parcel(java)类的部分信息就被保存到gParcelOffsets全局变量中,
并且将Parcel(java)类的本地方法与JNI本地函数映射在一起。
<2>生成Parcel(java)对象
生成Parcel(java)对象的过程与Binder和BinderProxy略有不同,
首先看Parcel(java)的构造方法, 它有一个私有方法, 外部代码不能使用new Parcel语句创建Parcel(java)的实例对象。
但是Parcel(java)类提供了一个名称为obtain方法, 使用该方法即可创建Parcel(java)类的实例对象。
obtain方法调用Parcel(java)的私有构造方法, 构造方法将调用init本地方法, 从而引起对本地函数
android_os_Parcel_init的调用,本地函数创建了Parcel(c++)类的实例对象。
<3>Parcel(java)类与Parcel(c++)类间的相互作用
一般地, Parcel(java)类用来在服务代理中保存Binder RPC数据,
例如,FooService服务用户在调用IFooService.Stub.Proxy服务代理的foo代理方法时, 就会调用Parcel(java)类的
obtain函数创建出Parcel(java)对象, 并将其传入到transact方法中。
图 Parcel(java)类与Parcel(c++)类的相互作用
6 JAVA系统服务的实现
下面以闹钟服务为基础, 分析系统服务的结构
<1>闹钟服务分析
下图显示了实现闹钟服务的类图结构。
图 实现闹钟服务的类图
<1.1>闹钟服务的实现方式
在编写本地系统服务时, 开发者必须亲自实现服务接口, 服务代理, 服务Stub, 服务。
而在编写Java系统服务时,开发者可以使用AIDL语言自动生成他们。
首先编写AIDL接口文件, IAlarmManager.aidl,系统会自动编译生成IAlarmManager.Stub类。
应该编写服务类继承Stub类,重新定义IAlarmManager.Stub类Binder类的onTransact方法, 并添加系统Binder RPC功能。
AlarmManagerService的服务Stub类重定义了onTransact方法, 并且实现了与IAlarmManager接口中5个方法相关的代码。
<1.2>使用闹钟服务(AlarmManagerService)
应用程序开发者若要使用系统服务, 需要调用SDK中的getSystemService方法。
首先调用ServiceManager的getService方法, 请求AlarmManagerService服务,返回一个指向AlarmManagerService服务的BinderProxy对象。
调用IAlarmManager.Stub服务Stub的asInterface方法,获取IAlarmManager.Stub.Proxy服务代理类的对象。
创建并返回AlarmManager对象。
调用getSystemService方法获取AlarmManager对象, 以Context的ALARM_SERVICE变量为参数, 通过强制类型转换, 获得AlarmManager对象。
注意: ServiceManager 在android.os包中, ServiceManager类被标记成@hide
在SDK中没有对外开放,Context在android.app包中, 对外开放,
所以不能APP开发者不能使用ServiceManager获取系统服务。需要写AlarmManager包装类, 使APP开发者能够通过Context获取AlarmManager,
从而使用服务。
7. 编写HelloWorldService系统服务
图 HelloWorldService系统服务类图
首先编写HelloWorldService服务接口aidl文件,
然后系统自动生成HelloWorldService服务接口, 服务代理, 服务Stub
之后再实现HelloWorldService与HelloWorldManager类。
实现HelloWorldService服务
HelloWorldService服务实现类 HelloWorldService.java在com.android.app包中。
HelloWorldService要继承并实现服务IHelloWorld.Stub类(由编译器根据aidl文件自动生成)。
注册HelloWorldService服务
在SystemServer.java的ServerThread的run方法中注册HelloWorldService服务。
helloWorldService = new HelloWorldService(context);
ServiceManager.addService(Context.HELLO_SERVICE, helloWorldService);
使用HelloWorldService系统服务
编写HelloWorldManager包装类, 构造方法接收IHelloWorld.Stub.Proxy类的实例对象,
HelloWorldManager类的构造方法访问权限为default, 只有同一个包(android.app)中的类才能调用它。
获取HelloWorldManager
应用程序开发者可以通过ContextImpl的getSystemService方法来使用系统服务。
调用getSystemService方法接收一个字符串参数, 若字符串与HELLO_SERVICE变量中的字符串相同, 则调用getHelloWorldManager方法。
getHelloWorldManager方法向ServiceManager请求检索HelloWorldService服务, 若ServiceManager检索到HelloWorldService服务,
则返回一个指向它的BinderProxy对象。getHelloWorldManager方法将接收到的BinderProxy对象传递给HelloWorld.Stub服务Stub的asInterface方法。
生成IHelloWorld.Stub.Proxy服务代理对象。并将这个服务代理对象传递给HelloWorldManager构造方法, 生成HelloWorldManager对象,
并且其mService变量中保存着IHelloWorld.Stub.Proxy服务代理对象的引用。
最后返回HelloWorldManager对象。
为了使用HelloWorldService服务, 应用程序将调用ContextImpl的getSystemService方法, 把Context.HELLO_SERVICE传入方法中,
然后将返回值转换成HelloWorldService类型, 这样就可以使用HelloWorldService服务了。
8 Java Service Manager
Java系统服务于本地服务一样都是由Context Manager进行管理的, 通常使用Java服务框架编写的系统服务都是通过Java Service Manager注册到系统中的。
<1>Java Service Manager简介
Java Service Manager由服务层,RPC层, IPC层组成, IServiceManager服务接口与ServiceManager包装类位于服务层中,
它们由Service Manager用户使用。 ServiceManagerProxy服务代理位于RPC层, 它将方法的调用信息转换为Binder RPC数据。
Binder Proxy位于IPC层, 它通过JNI 与BpBinder类连接在一起。