温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

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

发布时间:2021-06-28 14:59:38 来源:亿速云 阅读:162 作者:Leah 栏目:互联网科技

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

第一步:获取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机制实现进程间通信就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI