分类: Android平台
2014-10-30 16:02:50
摘要:Android系统服务提供系统最基本、最核心的功能,比如设备控制、地理位置信息提供、定时设置等。这些系统服务都是使用Android的Service Framework实现的,Android Service Framework是Android系统的重要组成部分。探索Service Framework内部原理,理解并掌握Service Framework的运作方式,有助于我们开发出各种新功能,例如视频通话、DMB服务等非基本的系统服务。本文将重点学习Android Service Framework,分析各个构成元素,理解其原理与运行机制,以便开发出各种服务。
Android Service Framework是一系列类的集合,它用来开发运行在Android平台上的各种服务。Service Framework提供了设计精良、复用度高的服务设计与实现,开发者可以使用Service Framework提供的各种类与接口,快速开发出可靠优良的服务。
在使用Service Framework开发服务时,开发者只要把主要精力集中在开发服务的核心功能上即可,服务核心功能之外的部分Service Framework会帮我们处理。例如,在开发服务时,服务注册、服务Binder IPC等功能都由系统提供,开发者不需要实现这些功能。总之,开发者在使用Service Framework开发服务时,只要集中精力开发服务要提供的功能即可。
之前,读者可能听说过Android Application Framework这个词,但什么是Service Framework,有些读者可能不太明白。在Android平台中,Service Framework大致由两大部分构成,一部分是使用C++语言编写的本地服务框架,另一部分是使用Java语言编写的Java服务框架。既然已经存在“应用程序框架”这一术语了,为什么还要使用“服务框架”(Service Framework)这个术语呢?
首先在说明由C++语言编写的系统服务以及由Java编写的系统服务时,有必要将两者合在一起来说明。在使用应用程序框架(Application Framework)时,由Java实现的服务将被包含进去,所以在开发服务时需要一个通用的术语来指代所使用的框架(Framework)。并且,应用程序框架中构成要素十分庞大,为了说明的方便,也需要一个术语将实现服务所需要的素有框架元素表达出来。
其次,在“服务框架”中包含了所有框架的特征。框架有两个代表性的特征,一是通过扩展而非修改框架添加新的功能;二是使用框架实现的应用程序控制流由框架而非程序自身控制。在Android平台中,许多服务通过扩展而非修改服务框架来实现,并且服务的动作流也是由服务框架所决定,所实现的服务只是按照内部定义的方式进行运作。若开发者采用任意的方法开发服务,那么开发出的服务将无法再系统中正常运行,即只有使用Android提供的类与已经定义好的方法开发,才能够开发出可以再系统中正常运行的服务。
在分析“服务框架”时,将Binder IPC各抽象层的作用以及相应的类联系起来,有助于我们更容易地理解“服务框架”中的各个类。“服务框架”各个层的组成元素以及它们各自的作用如表1:
|
服务客户端(Service Client) |
Service Server |
|||||||||||||||||
服务层 |
配置 |
|
|
||||||||||||||||
功能 |
■ FooService 服务的公用接口 ■ 提供FooService服务的foo()函数接口 |
■ FooService服务的公用接口 ■ 运行FooService服务的foo()函数 |
|||||||||||||||||
RPC层 |
配置 |
|
|
||||||||||||||||
功能 |
■ 支持Binder RPC ■ 调用foo()函数,转换成RPC数据 |
■ 支持Binder RPC ■ 分析RPC代码与数据,调用foo()服务的Stub函数 |
|||||||||||||||||
IPC层 |
配置 |
|
|
||||||||||||||||
功能 |
■ 支持Binder IPC ■ 将RPC代码与数据转换成IPC数据,传递给Binder Driver |
■ 支持Binder IPC ■ 接收Binder IPC数据,转换成RPC代码与数据 |
表1
首先服务客户端与Service Server在Service Framework的构成元素配置上存在不同。在服务层的服务客户端有服务接口,而在Service Server中不仅有服务接口,还有相应的服务。在RPC层的服务客户端只有名称为“BpFooService”的服务代理,而在Service Server中有BnFooService服务Stub。在IPC层,服务客户端与Service Server的构成元素都是一样的。
其次,服务客户端与Service Server中构成元素的功能有所不同。在服务层的服务客户端服务使用者调用IFooService foo()函数,而在Service Server端运行的是FooService的foo()服务的Stub函数。在RPC层的服务客户端纯在有BpFooService服务代理,并且将调用foo()代理函数的信息转换成RPC代码与数据。但在Service Server端有BnFooService服务的Stub,分析接收到的RPC代码与数据,并调用foo()服务的Stub函数。在IPC层,服务客户端与Service Server的构成元素都是一样的,但是服务客户端会将RPC代码与数据转换成IPC数据,而Service Server则将IPC数据转换成RPC代码与数据。
“服务框架”中的各个类之间是如何相互作用的呢?首先服务客户端与Service Server中使用的Service Framework的类与位于同一层的对等类产生相互作用(同层相互作用)。比如,在服务客户端与Service Server中,位于RPC层的服务代理与服务Stub类相互对应,并相互作用;位于IPC层的BpBinder与BBinder类相互对应并发生作用。各层相互作用的类如下。
第一,位于服务层中的服务接口使服务使用者与服务使用统一的接口进行相互作用。
第二,处于RPC层的入伍代理与服务Stub支持Binder RPC操作。从Binder RPC观点来看,服务代理将函数调用信息转换成RPC代码与数据,服务Stub分析服务代理发送来的RPC代码与数据,而后调用服务Stub函数。
第三,位于IPC层的BpBinder类与BBinder类支持Binder IPC操作。
“服务框架”主要的类如下:
■ IBinder、BBinder、BpBinder:IBinder类是对Android Binder的抽象,它有BBinder、BpBinder两个子类。BBinder类负责接收RPC代码与数据,并在Binder Driver内部生成Binder节点。BpBinder类保存着目标服务的Handle信息,用于Binder Driver查找Service Server的Binder节点的过程中。
■ IInterface、BnInterface、BpInterface:IInterface类提供类型变换功能,将服务或服务代理类转换为IBinder类型。实际的类型转换是由BnInterface、BpInterface两个类完成的,BnInterface将服务类转换成IBinder类型,而BpInterface则将服务代理类转换成IBinder类型。在通过Binder Driver传递Binder对象时,必须进行类型转换,比如在想系统注册服务时,需要先将服务类转换成IBinder,在将其传递给Context Manager。
■ ProcessState、IPCThreadState:ProcessState类用来管理Binder Driver,IPCThreadState类用来支持服务客户端、Service State与Binder Driver间的Binder IPC通信。
■ Parcel:在服务与服务代理间进行Binder IPC时,Parcel类负责保存Binder IPC数据。Parcel类可以处理的数据有C语言的基本数据结构、基本数据结构数组、Binder对象、未见描述等。
开发运行在系统中的服务时,若想提高开发水平,开发出类似内置于Android的系统服务,就必须对组成Service Framework的各种类有充分的掌握与理解。幸运的是,Android是一个开源项目,我们通过分析系统服务的源码就能了解Service Framework 中的各个类是如何使用、如何运作的。下面以Audio Flinger系统服务为例来分析类的构成以及各个类是如何协作的,Audio Flinger是Android系统典型的系统服务之一,它负责Android系统中的声音处理。
图2是组成Audio Flinger系统服务的类图。Audio Flinger系统服务由IAudioFlinger服务接口、BnAudioFlinger服务stub、AudioFlinger服务、BpAudioFlinger服务代理构成
服务函数在服务接口中声明,并分别在服务与服务代理中实现。例如,在IAudioFlinger服务接口中有一个setMasterVolume()服务函数的声明,该服务函数分别在AudioFlinger服务与BpAudioFlinger服务代理中实现。在服务接口中还存在一些函数,这些函数能够把服务接口转换成IBinder类型,或把IBinder类型转换成服务接口。
例如,在IInterface类中,asBinder()函数用来将服务接口类型转换为IBinder类型,而asInterface()函数而用来将IBinder类型转换为服务接口类型。
在Audio Flinger服务中存在名称为IAudioFlinger的服务接口,如下代码1所示,并且服务提供的功能由IAudioFlinger的成员函数声明。
class IAudioFlinger : publi IInterface
{
public :
DECLARE_META_INTERFACE(AudioFlinger);
/* set the audio hardware state. This will probably be used by
* the preference panel , mostly.
*/
Virtual status_t setMasterVolume(float value) = 0;
}
代码1
IAudioFlinger类的主要特征如下:
■ IAudioFlinger类继承自IInterface类。
■ 类的内部使用DECLARE_META_INTERFACE宏。
■ 声明IAudioFlinger的setMasterVolume()成员函数(服务函数)
代码1第一行:IInterface类的作用
IInterface类是IAudioFlinger类的父类,它的主要功能之一就是支持服务与IBinder类型间的显式转换。即IInterface类通过asBingder()函数将IAudioFlinger类型转换为IBinder类型。在进行Binder IPC通信时,IBinder对象要被保存到RPC数据中并传递给Binder Driver,所以在实现服务时需要进行类型转换。例如,在想系统注册Audio Flinger服务时,S而vice Manager首先要将BBinder类型的服务对象包含到RPC数据中,再将其传递给Context Manager,在这一过程中需要先把服务转换成IBinder类型后,再传递给Binder Driver。
IAudioFlinger类型是如何被转换成IBingder类型的呢?下面看一下源代码。如下代码2所示,IInterface类中仅声明了一个名称为asBinder()的public成员函数,该函数的返回值为IBinder指针。
class IInterface :public virtual RefBase
{
public:
IInterface();
sp
sp
protected;
virtual ~IInterface();
virtual IBinder onAsBinder() = 0;
代码2
代码3是asBinder()函数的实现代码。若存在IInterface类型的接口,就会调用onAsBinder()函数,该成员函数式一个虚拟函数,子类中必须实现该虚拟函数。
sp
{
Return this ? onAsBinder() : NULL;
}
代码3
代码1第四行:DECLARE_META_INTERFACE宏的作用
asInterface()函数由DECLARE_META_INTERFACE(AudioFlinger)与IMPLEMENT_META_INTERFACE(AudioFlinger)宏生成,该函数接收IBinder类型的参数,通过判断参数的具体类型(BBinder类型或BpBinder类型),调用相应函数,返回IAudioFlinger类型的服务代理,即将IBinder类型转换为IAudioFlinger类型后返回。
代码1第八行:服务函数声明
在服务接口中,服务与服务代理声明了所使用的服务函数。在IAudioFlinger中声明了许多虚拟函数,这些函数对应Audio Flinger提供的各种功能,例如setMasterVolume()函数,它提供系统音量设置功能。
小结
前面我们分析了Audio Flinger服务的IAudioFlinger类,概括起来,IAudioFlinger服务接口提供如下三种功能。
第一,在IAudioFlinger与IBingder类型间进行类型转换。在将IAudioFlinger类型转换为IBinder类型时,需要调用IInterface类的asBinder()函数,而后调用BnInterface或BpInterface的onAsBinder()函数进行处理。
第二,调用IAudioFlinger类的asInterface()函数,可以将IBinder类型转换为IAudioFlinger类型。该函数由Service Framework提供的DECLARE_META_INTERFACE与IMPLEMENT_META_INTERFACE宏进行声明与实现。
第三,在IAudioFlinger类中声明了多种纯虚函数,对应Audio Flinger服务提供的各项功能。并且,继承了该类的服务与服务用户全部通过相同的接口来提供或使用服务。
服务函数在服务类中被实现,例如用于控制系统声音的setMasterVolume()函数,它在AudioFlinger类中被具体实现。并且,还需要服务stub类,以便通过Binder RPC运行服务类的服务stub函数。下面分析一下Audio Flinger服务的AudioFlinger类,以及BnAudioFlinger服务stub类。
AudioFlinger类基继承了IAudioFlinger类,它具体实现Audio Flinger的服务功能。代码4是AudioFlinger类的主要代码。
class AudioFlinger : public BnAudioFlinger
{
public :
// IAudioFlinger interface
uirtual status_t setMasterVolume(float value);
static void instantiate();
};
代码4
代码4第一行:BnAudioFlinger服务stub的功能
BnAudioFlinger服务stub类负责分析Audio Flinger服务中使用的RPC代码,并调用AudioFlinger类的相应函数。
代码4第五行:服务功能的实现
SetMasterVolume()函数提供系统音量调节功能。
代码4第六行:注册Audio Flinger服务
一个系统服务必须先将自身注册到Android系统中才能提供给用户使用。一般地,服务注册将在服务生成的同时进行,调用AudioFlinger类的instantiate()函数会生成AudioFlinger实例,并通过Service Manager将其注册到系统之中。
服务代理函数用来传递Binder RPC所需要的RPC代码与数据,这些函数具体在服务代理类中实现。比如BpAudioFlinger服务代理的setMasterVolume()函数会将SET_MASTER_VOLUME(RPC代码)与音量值(RPC数据)发送到BpBinder中。下面分析一下Audio Flinger服务的BpAudioFlinger服务代理类。
BpAudioFlinger服务代理类继承了IAudioFlinger类,服务用户通过它来使用Audio Flinger服务。代码5是BpAudioFlinger类的代码。
class BpAudioFlinger :public BpInterface
{
public:
virtual status_t setMasterVolume(float value)
{
Parcel data,reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeFloat(value);
remote()->transact(SET_MASTER_VOLUME,data,&reply);
return reply.readInt32();
}
BpAudioFlinger(const
sp
:
BpInterface
};
代码5
代码5第一行:BpAudioFlinger的继承关系
由代码5可以看出,BpAudioFlinger类继承了BpInterface类。BpInterface类被声明为类模板,它继承了IAudioFlinger接口。
代码5第四行:setMasterVolume()函数
SetMasterVolume()是BpAudioFlinger服务代理类的一个函数,它将自身的调用信息以Binder RPC代码、RPC数据的形式返回。
代码5第十二行:获取BpBinder对象
BpBinder 对象时以BpAudioFlinger构造函数的参数形式获取的。
ProcessState
ProcessState类提供的主要功能概括如下:
■ ProcessState类生成后,将打开Binder Driver,以便在Binder IPC中使用。
■ 创建BpBinder类的实例。也可以生成目的地为Context Manager的BpBinder实例。
IPCThreadState
在与Binder Driver进行交互,执行Binder IPC通信时,IPCThreadState类负责传递Binder IPC数据。
Parcel
Parcel是Binder IPC数据的容器,这些数据由发送端传送到接收端。Parcel专为传递IPC设计,设计精良而高效。Parcel中有多种读写各种类型数据的成员函数,其中最基本的函数用来读写基本数据类型的数据,支持的数据类型有int、double、float、string。int类型支持32位与64位,string支持C风格的字符串、UTF-8以及UTF-16字符串。此外,Parcel还可以读写文件描述符与IBinder类对象的引用。
①调用BpAudioFlinger的setMasterVolume()函数,将SET_MASTER_VOLUME(RPC代码)作为第一个参数传入BpBinder的transact()函数中,而后将“Android.media.IAudioFlinger”字符串与音量值保存到Parcel实例中,再将其作为第二个参数传入函数中。
②在BpAudioFlinger的setMasterVolume()函数中调用BpBinder的transact()函数时,目的地信息将被作为首个参数传入IPCThreadState的transact()函数中,并且Parcel实例将被作为第二个参数传入函数中。
③在BpBinder的transact()函数中,调用IPCThreadState的transact()函数时,BC_TRANSACTION(Binder协议)与②—③中传递过来的所有数据都将被作为参数体,以供Binder Driver使用,并且将接收到的RPC代码、RPC数据,以及目的地信息保存到结构体之中。
接着,生成Binder IPC数据,这些数据是要被传递给Binder Driver的。
在Android系统中存在着各种各样的服务,如管理音频设备的Audio Flinger服务、管理帧缓冲设备的Surface Flinger,还有管理相机设备的Camera服务等。这些服务的信息与目录都是由“上下文管理器”负责管理的。
我们知道,服务与服务用户是不同的进程,它们分别运行在各自独立的内存空间中,在两个进程中若想实现信息共享,进程间必须进行IPC通信。
在服务被注册到Context Manager的过程中,Binder Driver将生成Binder节点,该节点中包含服务连接的信息。并且Service Framework会以服务Handle值的形式引用Binder及诶单。服务用户若想访问服务,必须首先从Context Manager中获取服务的Handle值,以便连接到要使用的服务上。
Service Framework提供了用于处理BinderPRC的服务代理(Service Proxy),这些服务代理帮主服务用户使用Audio Flinger、Surface Flinger、相机服务等各种服务提供的功能。服务用户通过服务代理使用相关服务,服务代理与服务间复杂的Binder RPC由底层的Service Framework完成,在上层服务用户看来,服务代理与服务就像同一个进程,如同在同一个进程中使用服务一样。事实上,我们完全可以吧服务代理想象成服务。
前面曾经讲到过,Context Manager的服务代理即是Service Manager,并且Service Manager分为C/C++层与Java层两种。本节将讲解位于C/C++层的Service Manager
首先BpServiceManager继承了Iservice Manager服务接口,实现了创建Binder RPC数据的方法,这些Binder RPC数据用于向Context Manager提出服务注册或获取服务信息请求。其次,BpServiceManager还继承了BpInterface,以便通过指向Context Manager的BpBinder,向Context Manager传递Binder RPC数据。
作为一项服务,Context Manager提供哪些功能呢?首先,Service Manager与Context Manager通过基于IServiceManager服务接口的Binder RPC进行交互操作。因此我们可以通过分析IServiceManager来了解Context Manager提供的功能。IServiceManager是如何定义Context提供的各种功能的呢?请参看表2,表中列出了IServiceManager中主要的成员函数。
sp |
此函数以服务名称(name)作为参数,接收到服务名称后,调用chenkService()成员函数。当Binder IPC失败,重新尝试。该函数的返回值是一个指向BpBinder实例的指针。 |
sp |
接收服务名称,并从Context Manager获取相关服务的信息,而后生成BpBinder实例,返回指向该实例的指针。 |
status_t addService(const String
16&name,const
sp |
以服务名称与服务实例的指针为参数,向Context Manager请求注册服务,其返回值表示服务是否注册成功。 |
Vector |
该函数是无参函数,获取注册在Context Manager中的服务的列表,并将,并将其返回。 |
如同上表所列的一样,Context Manager提供以上四种方法的功能,BpService Manager中有相应的服务代理函数来实现这四种功能,每个函数的功能通过函数的名称即可知道。
前面已经了解了Service Manager的大概。在本节中,将通过一些示意图与源代码的分析来具体地了解Service Manager主要行为动作。
Service Manager初始化
服务或服务用户在使用Service Manager注册或检索服务之前,需要先创建Process State实例,该实例中拥有Binder Driver的信息
为了通过Binder IPC使用Context Manager的功能,首先生成ProcessState实例,。在生成ProcessState实例的同时,Binder Driver即被打开,并且相关信息被保存在ProcessState对象中。
由于Context Manager的服务Handle值为0,所以直接生成BpBinder。对于其他服务,由于不知道这些服务的Handle值,需要先从Context Manager获取服务信息后,再生成相应的服务。
在通过服务Handle向特定服务发送Binder IPC数据时,将会用到BpBinder,并且通过ProcessState可以防止在同一进程中重复生成BpBinder对象。因此,当应用程序访问某个使用中的服务时,不必创建新的BpBinder对象,直接使用已有的BpBinder对象即可。
至此,BpServiceManager与Context Manager之间就可以进行Binder RPC操作了。
服务Handle与BpBinder,以及与BpServiceManager的连续就像拼插积木一样,在连接其他服务与服务代理时也采用这样的结构形式。
服务注册
为了让其他进程使用自身提供的功能,服务必须先注册到Context Manager之中。下面通过分析Audio Flinger的instantiate()函数代码来说明服务注册的过程。
void AudioFlinger::instantiate(){
defaultServiceManager()->addService(
String16(“media.audio_fliger”),new AudioFlinger());
}
代码6
代码6第三行:调用defaultServiceManager()函数,获取BpServiceManager的实例指针。而后调用BpServiceManager的addService()成员函数,并将Audio Flinger的服务名称以及新生成的Audio Flinger的实例指针传入函数中。
下面来分析BpServiceManager的addService()成员函数,函数源代码如下。
status_t addService(const String16& name, const
sp
{
Parcel data,reply;
data.writeInterfaceToken(
IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
status_t err = remote()->transact(ADD_SERICE_TRANSACTION, data,&reply);
return err == NO_ERROR ? reply.readInt32() : err;
}
代码7
代码7第三行:Parcel类是信息的容器,该语句声明了两个Parcel类型的变量,以便存放数据。
代码7第八行:该语句先调用remote()函数,返回持有Context Manager的BpBinder对象,再传递生成的Binder RPC数据与Binder RPC代码(ADD_SERVICE_TRANSACTION),执行Binder IPC处理。
代码7倒数第二行:从Context Manager 发送的Binder RPC 应答数据中,读取大小为int32的数据,并将其返回。
本文首先介绍了什么事Service Framework,它提供的四项功能,各层构成元素、各个类的结构以及它们之间是如何相互作用的。为了阐述Service Framework的运行机制,以Audio Flinger为示例分析了服务接口、服务、服务代理类的源代码。
其次,介绍了本地服务Framework中的Service Manager,它用来将运行在Android平台中的系统服务注册到Context Manager之中。
Context Manager是Android平台中最初运行的服务,它在Service Framework中的服务Handle为0,且在服务与服务用户间提供服务注册于获取服务等本身特有的功能。
服务代理BpServiceManager与Context Manager通过Binder RPC进行调用,分析了服务注册于获取的郑国过程,在该过程中,我们了解了服务用户在访问服务时是如何连接服务Handle、BpBinder,以及服务代理的