实例分析android中的Binder通信机制(3)

本文深入剖析了Android中的Binder机制,包括ServiceManager的工作原理、mediaplayerService与其客户端的通信过程、Binder与线程间的互动方式、匿名服务的特殊处理以及如何模拟本地服务。此外,还介绍了Java层利用Binder进行进程间通信的方法。

一、对于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()函数中

获得代理啦,这样就可以工作了。

  

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值