Android中怎么利用Binder机制实现进程间通信

这篇文章给大家介绍Android中怎么利用Binder机制实现进程间通信,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

创新互联2013年开创至今,是专业互联网技术服务公司,拥有项目成都网站设计、成都网站建设、外贸网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元北安做网站,已为上家服务,为北安各地企业和个人服务,联系电话:13518219792

第一步:获取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(自己创建的)的函数,由他们完成实际的工作

常用有如下情形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<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);

关于Android中怎么利用Binder机制实现进程间通信就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

当前标题:Android中怎么利用Binder机制实现进程间通信
网页网址:https://www.cdcxhl.com/article12/ijhsgc.html

成都网站建设公司_创新互联,为您提供自适应网站动态网站网站排名网站导航移动网站建设建站公司

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

成都app开发公司