一、对于ServiceManager的理解:
ServiceManager给客户端抛出来的接口是IServiceManager,客户端会得到一个BpServiceManager,通过这个可以把命令请求发送给handle = 0的目的端。
按理说这个一个BpServiceManager就对应了一个BnServiceManager,不过在此,没有BnServiceManager,有的是Service_manager.c完成工作。
在这里,首先它会打开一个驱动设备,binder_open(),之后就是使用binder_Loop()中的svrmgr_handler处理函数来处理问题。其实这里就是注册一些服务信息而已。
ServiceManager本质就是保存了一些服务的信息,没有什么大的动作。但是也要特别注意的是ServiceManager能管理系统中所有的服务,并能施加权限控制。同时,Clients
通过在这里查找就能找到自己需要的服务了,简单方便。
二、mediaplayerService和它的客户端的通信
Clients查找这个ServiceManager,获取到了这个media.player的返回值是一个BpBinder,进一步,interface_cast<>转换,得到BpmediaplayerService。
找到对应的服务之后就可以得到一个BpmediaplayerService (这个BpmediaplayerService是在ImediaDeathNotifier.cpp文件中定义得 来的)
还是要再理解和驱动通信的只能是BpBinder 和BnBinder,这时候已经去掉了加在这两者身上本身的请求的成分,把这样的请求信息已经打包在data里面了。
三、Binder和线程之间的关系:
线程是通过talkwithDriver跟Binder驱动交互的。这里注意的是talkwithDriver这个函数是在IPCThreadState对象中,这个IPCThreadState和binder 的关系很密切。
这里需要注意的是,主线程,工作线程都是通过talkwithDriver和binder设备交互信息的,但是这个有一个特殊的处理,就是发出请求的线程(就是Bp####的Client)
binder设备首先会把它绑定住,直到它得到回复再释放这个线程,这样高效又安全,每个线程都是互不干扰的。
明确一下流程:Bp####的transact()函数是将请求跟数据打包给一个作为它参数的BpBinder,由BpBinder中的transact()函数完成传输任务,其实这些传输的任务都是由
IPCThreadState对象完成的。IPCThreadState的transact()函数中使用writeTransactionData()函数将数据设置成binder驱动设备可以认识的数据结构,同时根据handle的值和对应的目的端建立联系,即(BnBinder),使用waitForResponse(reply)得到处理的回复,在一层追踪的结果是waitForResponse(reply)调用executecommand()来执行任务。
在整个BInder系统中,最后是Bn####来完成任务的,所以对于Bn####对应的Bp####来说,Bn####这个服务端的生死是至关重要的。在android中设计了一个
class DeathNotifiter来告诉 Bp####的生死。我们要做的是首先把class DeathNotifiter注册在系统当中。DeathNotifiter它是和服务端Bn####有对应联系关系的,所有使用这个对象就可以完成告知工作。
if (sDeathNotifier == NULL){
sDeathNotifier = new DeathNotifier();
binder->linkToDeath(sDeathNotifier);//这个binder是BpBinder是和对应端的BnBinder对应的,即,Bn####.
sService = interface_cast<IMediaPlayerService>(binder);
return sService;}
当然,告知Client之后也会有采取一定得措施,Client一般会干掉对应的Bp####。
(这个也是一个值得注意的小问题)
四、我认为的一个特殊处理形式:Clients首先是在ServiceManager中查找已经注册到的服务,getService()完成,像MediaMetadataRetriever.cpp中,
const sp<IMediaPlayerService>& service(getService());这样就得到了处理MediaMetadataRetriever请求的BpMediaPlayerService,同时在使用DeathNotifier这个内部类
创建DeathNotifier对象,建立和对应端Bn####的“告知相关工作”。这是一般的流程。
对应的这个MediaPlayer,MediaRecorder是没有在ServiceManager中注册到的服务,但是依然Binder通信支持者,这就是android中对于这种匿名Service的特殊服务。
例如,在IMediaPlayerService.cpp中,Bn####的transact()这样处理:
sp<IMediaRecorder> recorder = createMediaRecorder(pid);
reply->writeStrongBinder(recorder->asBinder());
当这个reply写到Binder驱动时,可能会为这个特殊处理这个IBinder,可能的操作是为这个BBinder建立特有的handle,这样就在Binder驱动中新注册了一项这个服务。
五、模拟一个本地端的服务:
(把要用的申明都写在一起)
第一步:Main_TestService.cpp
定义一个main()函数,完成注册,创建工作线程,并在主线程中保留自己的信息。
第二步:申明一个对应给clients的接口类ITestService.h,(声明1)描述这个服务给客户端提供的服务项;(声明2)声明这个BnTestService。
在这个声明中特别注意的是使用那个最给力的宏:
class ITestService ::public IInterface
{ //描述这个服务给客户端提供的服务项
DECLARE_META_INTERFACE(TESTSERVICE);
功能1;
功能2;
功能3;
// 声明这个BnTestService
class BnTestService:: BnInterface(ITestService)
public:
onTransact() = 0;// 纯虚函数,下面会实现
}
ITestService.cpp其实就是对BpTestService的定义:
class BpTestService ::public BpInterface //(BpInterface的一个基类就是IInterface)
{
IMPLEMENT_META_INTERFACE(TESTSERVICE);
使用transact();完成;
}
第三步:BnTestService的定义,就是服务的实现;
BnTestService:: BnInterface(ITestService)
{
//完成transact()的内容
ontransact();
}
六、java层利用Binder进程间通信;
(1)类似于ITestService的接口:表现在java层是aidl文件,假设服务端程序在com.test.service包中;
定义这个aidl文件:
//定义一个这样的接口;
interface ITestService {·······};
eclipse编译aidl文件,在gen目录会自动生成com.test.ITestService.java
(2)实现服务端:com.test.ITestService.java是类似BnTestService的,具体业务是实现它的子类ITestService.sub,特别注意ITestService.sub是在aidl文件编译后在gen目录会生成com.test.ITestService.java中定义的,功能是一个BnTestService。
业务类的定义:
class ITestImpl extends ITestService.sub{
功能1;
功能2;
功能3;
}
(3)这样就做好了,当然,这时候的client是在另外的进程中,即实现代理端。假设在com.test.client包中。
首先把在com.test.ITestService的gen目录会自动生成com.test.ITestService.java复制到com.test.client中,这样就可以在client端的例如onServiceConnected()函数中
获得代理啦,这样就可以工作了。
本文深入剖析了Android中的Binder机制,包括ServiceManager的工作原理、mediaplayerService与其客户端的通信过程、Binder与线程间的互动方式、匿名服务的特殊处理以及如何模拟本地服务。此外,还介绍了Java层利用Binder进行进程间通信的方法。
280

被折叠的 条评论
为什么被折叠?



