初识Android进程间通信Binder机制

先大概描述下AndroidS/C架构的基本面貌

由于采用linux内核,所以用户空间中得进程地址空间都是独立的,如果用户空间进程AB之间想进行通信,可以先将用户空间进程A要发送信息发送到内核,由于内核中得地址空间对于每个进程都是一样的,所以用户空间进程B可以读取内核收到的信息。

Android中得binder机制就是将这种调用进行了封装,将用户空间的进程分为三类,client,service,ManagerService

其中的ManagerService作用是记录所有的service信息,client访问service前先到ManagerService处去查询有无此服务

 

常用有如下情形1:添加service服务

过程

第一步:获取ManagerService服务代理BpBinder(0)和BpManagerService

第二步:通过BpManagerService中得addService方法将服务的一些信息打包,然后通过BpBinder(0)将信息发送到内核,等待ManagerService进程来读取,因为ManagerService进程中有一个Loop一直读取内核信息,所以很快就获取了service发给内核的信息,ManagerService进程就将service服务的一些信息添加到维护的列表中,将添加的结果发送给内核,然后service等到内核有回复后返回,将返回的信息解码分析。

第三步:执行一个Loop来从内核读取client的请求

 

代码

如下是添加一个service的代码

第一步:

sp<ProcessState> proc(ProcessState::self());

sp<IServiceManager> sm = defaultServiceManager();

第二步:

defaultServiceManager()->addService(String16("media.player"),new MediaPlayerService());

第三步:

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

 

代码分析

sp<ProcessState> proc(ProcessState::self());

创建一个ProcessState实例

ProcessState::mDriverFD=open_driver()

ProcessState::mVMstart = mmap(…,mDriverFD,…);

mmap(0,…,mDriverFD,0);//只是让通信更快,可以当作没有,直接用read/write(mDriverFD);

sp<IServiceManager> sm = defaultServiceManager();

主要执行如下代码

sp<IServiceManager> gDefaultServiceManager =interface_cast<IServiceManager>(PorcessState::self()->getContextObject(NULL));

其中PorcessState::self()->getContextObject(NULL)就是执行PorcessState::getStrongProxyForHandle(0);其主要是根据给定的参数(此处为0)创建对应的sp<IBinder>  b = new BpBinder(0);

 

这边先说明interface_case这个模版类,这个模版类作用是将服务xxxService对应的BpBinder(x)转化为对应的BpxxxService如下:

sp<IxxxService> BpxxxService= interface_cast<IxxxService>(newBpBinder(x));

其本质是调用给定类型参数的asInterface方法,也就是IxxxService::asInterface(new BpBinder(x)),IxxxService继承publicIInterface

IxxxService用宏DECLARE_META_INTERFACE(xxxService)和IMPLEMENT_META_INTERFACE(xxxService,”android.os.IxxxService”)来实现asInterface方法,展开后如 new BpxxxService(new BpBinder(x)),这样就从BpBinder(x)得到了BpxxxService

 

如本例中给定的类型参数是IServiceManager,所以上述等价于

sp<IServiceManager> gDefaultServiceManager =IServiceManager::asInterface(new BpBinder(0)); IServiceManager继承publicIInterface

其中用宏DECLARE_META_INTERFACE(ServiceManager) 和IMPLEMENT_META_INTERFACE(ServiceManager,”android.os.IServiceManager”)来实现asInterface方法,这个asInterface方法最终执行new BpServiceManager(new BpBinder(0));

也就是sp<IServiceManager> sm = newBpServiceManager(new BpBinder(0));

由此得到BpBinder(0)和BpServiceManager

 

从这里可以得出,如果自己创建服务xxxService,按如下步骤

创建类 class IxxxService:publice IInterface

{

    DECLARE_META_INTERFACE(xxxService);//声明asInterface方法

    virtual function();//虚函数,由BpxxxService实现

    …

}

IMPLEMENT_META_INTERFACE(xxxService,”android.os.IxxxService”);//定义asInterface

展开相当于sp<IxxxService>IxxxService::asInterface(BpBinder){

    return new BpxxxService

}

当有这个服务的Bpbinder(x)后可通过如下获取BpxxxService

sp<IxxxService>sm = new BpxxxService (new BpBinder(x));   

 

注意:

1:BpxxxService类型为sp<IxxxService>

2:BpBinder(x)相当于xxxService对应binder实体的代理

3:客户端为什么要通过BpBinder(X)再创建一个BpxxxService呢?因为BpxxxService对象的基类中的一个mRemote变量就是Bpbinder(x),那为什么不直接用BpBinder(x)呢?因为BpxxxService对象中还实现了一些BpBinder(x)没有的业务逻辑(实现基类IxxxService中的方法)BpServiceManager中提供了addService方法,这些方法在服务端有对应的服务,如addService方法将请求的命令”addService”和数据打包成Parcel类型,然后通过BpBinder(x)发送给xxxService其实先发给驱动中binder设备,xxxService服务中会有Loop循环一直读取binder设备的消息,读取消息后解析成命令+数据,然后根据命令如”addService”会调取对应的服务,然后将结果反馈给binder设备,客户端接收到binder设备的反馈后将返回的数据也解析成命令+数据,然后根据命令和数据执行相应的逻辑

 

客户端 通过BpxxxService中方法将数据打包 -->Bpbinder(x)--> binder设备 --> 服务端Loop 获取数据解析成命令+数据-->调取命令指定的服务其中会涉及BBinder和BnxxxService,返回数据

客户端 解析返回的数据并执行相应逻辑     <--Bpbinder(x)<-- binder设备 <-- 服务端返回数据

 

由上可知,创建的服务还需创建BnxxxService和BpxxxService

class BpxxxService : public BpInterface<IxxxService>

{

    …

    vitural function(){

        Parcel data,reply;

        data.writeInterfaceToken(IxxxService::getInterfaceDescriptor());

        data.writeInt32(pid);

        remote()->transact(命令码,data,&reply);

}

}

 

class BnxxxService: public BnInterface<IxxxService>

{

    public:

        vitrual status_t onTransact(uint32_tcode,const Parcel& data,Parcel* reply,uint32_t flags = 0);

}

IMPLEMENT_META_INTERFACE(xxxService,”android.xxxService.IxxxService”);

status_t BnxxxService::onTransact(uint32_tcode,const Parcel& data,Parcel* reply,uint32_t flags)

{

    switch(code){

        case 命令码:

            CHECK_INTERFACE(IxxxService,data,reply);

            function()//自己实现的逻辑

break;

}

 

defaultServiceManager()->addService(String16("media.player"),new MediaPlayerService());

通过BpServiceManager(类型为sp<IServiceManager>)将数据打包成含”addService”命令,类型为parcel data的数据,调用BpBinder(0)这个对象的transact(),最终调到IPCThreadState::self()->transact(),

下面分析IPCThreadState,你暂时只需要知道每个线程有一个IPCThreadState实例,实例有属性mIn,mOut,其中mIn用来接受来自binder设备的parcel类型数据,mOut用来存储发往binder设备的parcel类型数据,IPCThreadState::self()->transact()最终完成与binder设备的交互,这个接口中先调用writeTransactionData把parcel类型的数据和int32_t类型的命令码封装成binder_transaction_data类型数据放到IPCThreadState实例的mOut中去,接下来IPCThreadState::self()->transact()会调用IPCThreadState::self()->waitForResponse接口,其中会调用talkWithDriver()与binder设备交换数据(talkwithDriver主要是实现是ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)),将返回来的数据存于IPCThreadState实例的mIn,然后调用executeCommand()根据mIn中得命令码和数据来解析,来调用各种业务逻辑

 

ServiceManager这个服务的Loop循环实现代码见下面:

struct binder_state *bs;

void *svcmgr = BINDER_SERVICE_MANAGER;

bs = binder_open(128*1024);//应该是打开binder设备吧

binder_become_context_manager(bs) //成为manager

svcmgr_handle = svcmgr;

binder_loop(bs, svcmgr_handler);//Loop

 

new MediaPlayerService(),MediaPlayerService继承BnMediaPlayService,BnMediaPlayService继承BnInterface, BnInterface继承BBinder ,BBinder继承 IBinder,所以MediaPlayerService继承了IBinder,addService第二个参数类型是IBinder 实例一个MediaPlayService也就是实例一个BnMediaPlaySerivce

 

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

创建一个MediaPlayerService服务后(也就是创建一个BnMediaPlaySerivce)后,将其加入serviceManage维护的一个列表中,接下来,BnMediaPlaySerivce也该起到服务的作用,创建一个Loop等待客户端client的请求,所以应该也有一个循环,也就是如下两段代码的作用

ProcessState::self()->startThreadPool();

IPCThreadState::self()->joinThreadPool();

先分析ProcessState::self()->startThreadPool();

其调用

sp<Thread> t = new PoolThread(isMain);isMain是TRUE

t->run(buf);//这句话会导致t->threadLoop调用,这里面执行了IPCThreadState::self()->joinThreadPool(mIsMain);

所以归根结底最后都调用IPCThreadState::self()->joinThreadPool(mIsMain);

这里面主要是执行一个循环,

    do {

        int32_tcmd;

        result =talkWithDriver();

        result =executeCommand(cmd);

     }

} while (result != -ECONNREFUSED && result !=-EBADF);

总结:调用talkWithDriver()与binder设备交换数据(talkwithDriver主要是实现是ioctl(mProcess->mDriverFD,BINDER_WRITE_READ, &bwr)),将返回来的数据存于IPCThreadState实例的mIn,然后调用executeCommand()根据mIn中得命令码和数据来解析,来调用自己(此处是BnMediaPlaySerivce)的各种业务逻辑,例如如果受到的命令是BR_TRANSACTION则会调用reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code,buffer, &reply, tr.flags);结果调用BnMediaPlaySerivce的oNTransact方法

这里面会根据获取的mIn中得命令码和数据来调用不同的业务逻辑,然后派发到派生类MediaService(自己创建的)的函数,由他们完成实际的工作

 

 

常用有如下情形2client访问某个服务service

过程

第一步:获取ManagerService服务代理BpBinder(0)和BpManagerService

第二步:通过BpManagerService中得getService方法将服务的一些信息打包,然后通过BpBinder(0)将信息发送到内核,等待ManagerService进程来读取,因为ManagerService进程中有一个Loop一直读取内核信息,所以很快就获取了client发给内核的信息,ManagerService进程将client想知道的东西发送给内核,client等到内核有回复后返回,将返回的信息解码分析已得知有无某个service服务,如果有这个service则返回的信息中有这个service的Bpbinder(x),client可以通过sp<Iservice>Bpservice = interface_cast<Iservice>( Bpbinder(x));来获取BpService,BpService中有与service对应的服务

第三步:访问服务

client访问这些服务前先调BpService中对应特定服务其将数据及命令打包,通过Bpbinder(x)将信息发送到内核,应为service也有一个Loop一直在读取内核信息,所以service很快就获取了client发来的信息,解析后根据信息中得命令码将数据发送到Bnservice对象包含的方法中进行解析,然后将处理后的数据发送给内核,client等到内核的受到的消息后返回,将返回的消息解码然后处理

代码

如下是client获取service的的代码

第一步:

sp<ProcessState> proc(ProcessState::self());

sp<IServiceManager> sm=defaultServiceManager();

见上

第二步:

sp<IBinder> binder = sm->getServices(String16(“media.player”));

sp<IMediaPlayService> sMediaPlayService =interface_cast<IMediaPlayService>(binder);

见上

第三步:

千里马8年Android系统及应用开发经验,曾担任过美国unokiwi公司移动端技术总监兼架构师,对系统开发,性能优化,应用高级开发有深入的研究,Android开源定制ROM Lineage的贡献者之一,国内首家线下开辟培训Android Framework课程,拥有2年的Android系统培训经验。成为腾讯课堂专业负责android framework课程分享第一人,致力于提高国内android Framework水平Android Framework领域内是国内各大手机终端科技公司需要的人才,应用开发者都对Android系统充满着好奇,其中的binder是重中之重,都说无binderAndroidbinde是Android系统的任督二脉。课程水平循序渐进,由中级再到高级,满足各个层次水平的android开发者。1、灵活使用binder进程通信,在app端对它的任何api方法等使用自如2、可以单独分析android系统源码中任何binder部分,分析再也没有难度3、掌握binder驱动本质原理,及对应binder驱动怎么进行跨进程通信,及内存等拷贝方式数据等4、对binder从上层的java app端一直到最底层的内核binder驱动,都可以顺利理通5、针对系统开发过程中遇到的binder报错等分析方法,及binder bug案例学习6、针对面试官任何的binder问题都可以对答自如7、socket这种跨进程通信实战使用8、针对android源码中使用的socket源码轻松掌握9、android系统源码中最常见的socketpair中双向跨进程通信10、使用socket实现一个可以让app执行shell命令的程序
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值