Android中怎么利用Binder机制实现进程间通信
这篇文章给大家介绍Android中怎么利用Binder机制实现进程间通信,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。
第一步:获取ManagerService服务代理BpBinder(0)和BpManagerService
第二步:通过BpManagerService中得addService方法将服务的一些信息打包,然后通过BpBinder(0)将信息发送到内核,等待ManagerService进程来读取,因为ManagerService进程中有一个Loop一直读取内核信息,所以很快就获取了service发给内核的信息,ManagerService进程就将service服务的一些信息添加到维护的列表中,将添加的结果发送给内核,然后service等到内核有回复后返回,将返回的信息解码分析。
第三步:执行一个Loop来从内核读取client的请求
代码
如下是添加一个service的代码
第一步:
sp
sp
第二步:
defaultServiceManager()->addService(String16("media.player"),new MediaPlayerService());
第三步:
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
代码分析
sp
创建一个ProcessState实例
ProcessState::mDriverFD=open_driver()
ProcessState::mVMstart = mmap(…,mDriverFD,…);
mmap(0,…,mDriverFD,0);//只是让通信更快,可以当作没有,直接用read/write(mDriverFD);
sp
主要执行如下代码
sp
其中PorcessState::self()->getContextObject(NULL)就是执行PorcessState::getStrongProxyForHandle(0);其主要是根据给定的参数(此处为0)创建对应的sp
这边先说明interface_case这个模版类,这个模版类作用是将服务xxxService对应的BpBinder(x)转化为对应的BpxxxService如下:
sp
其本质是调用给定类型参数的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
其中用宏DECLARE_META_INTERFACE(ServiceManager) 和IMPLEMENT_META_INTERFACE(ServiceManager,"android.os.IServiceManager")来实现asInterface方法,这个asInterface方法最终执行new BpServiceManager(new BpBinder(0));
也就是sp
由此得到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
return new BpxxxService
}
当有这个服务的Bpbinder(x)后可通过如下获取BpxxxService
sp
注意:
1:BpxxxService类型为sp
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
{
…
vitural function(){
Parcel data,reply;
data.writeInterfaceToken(IxxxService::getInterfaceDescriptor());
data.writeInt32(pid);
remote()->transact(命令码,data,&reply);
}
}
class BnxxxService: public BnInterface
{
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
下面分析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
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
这里面会根据获取的mIn中得命令码和数据来调用不同的业务逻辑,然后派发到派生类MediaService(自己创建的)的函数,由他们完成实际的工作
常用有如下情形2:client访问某个服务service
过程
第一步:获取ManagerService服务代理BpBinder(0)和BpManagerService
第二步:通过BpManagerService中得getService方法将服务的一些信息打包,然后通过BpBinder(0)将信息发送到内核,等待ManagerService进程来读取,因为ManagerService进程中有一个Loop一直读取内核信息,所以很快就获取了client发给内核的信息,ManagerService进程将client想知道的东西发送给内核,client等到内核有回复后返回,将返回的信息解码分析已得知有无某个service服务,如果有这个service则返回的信息中有这个service的Bpbinder(x),client可以通过sp
第三步:访问服务
client访问这些服务前先调BpService中对应特定服务其将数据及命令打包,通过Bpbinder(x)将信息发送到内核,应为service也有一个Loop一直在读取内核信息,所以service很快就获取了client发来的信息,解析后根据信息中得命令码将数据发送到Bnservice对象包含的方法中进行解析,然后将处理后的数据发送给内核,client等到内核的受到的消息后返回,将返回的消息解码然后处理
代码
如下是client获取service的的代码
第一步:
sp
sp
见上
第二步:
sp
sp
关于Android中怎么利用Binder机制实现进程间通信就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。