2372|1

492

帖子

1

TA的资源

一粒金砂(高级)

楼主
 

【Android 开发学习之路】三 -- Binder初实现 [复制链接]

本帖最后由 Bingqi23 于 2020-4-6 11:22 编辑

    时间过去了挺久了,直到现在才更新,是遇到了两个问题,一是代码是实际运行的时候报错,排错用了挺长时间,再一个就是一直没有倒出来时间写。
    言归正传,现在进行到了Binder的初体验。

    Binder的测试代码的编写,主要参考了https://blog.csdn.net/qq_25269161/article/details/86477368这篇帖子。在实际动手的时候遇到了一些理论问题,又主要参考了邓神的深入浅出系列https://www.cnblogs.com/innost/archive/2011/01/09/1931456.html。

    根据我的理解,Binder实质上是通过了一个虚拟设备来进行中转,然后是一种CS的模式的IPC通信方式。它的实现是,在客户端和服务端创建两个相同的接口方法,客户端的只是空壳子,而服务端的是具体的实现。当在客户端调用这个方法时,实际上通过binder的转手调用到了服务端的这个方法。在用户层看起来就好像我在客户端的A进程里面直接远程调用了服务端的B进程里面的方法函数似的。

    关于binder的原理之后再单独开贴描述,现在还是只重实践。

首先,代码结构如下:

main_server代码如下:

  • #define LOG_TAG "main_server"
  • #include<binder/IPCThreadState.h>
  • #include<binder/ProcessState.h>
  • #include<binder/IServiceManager.h>
  • #include<utils/Log.h>
  • #include"BinderTestService.h"
  • using namespace android;
  • int main(/*int argc,char *argv[]*/){
  • sp<ProcessState> proc(ProcessState::self());
  • sp<IServiceManager> sm = defaultServiceManager();
  • BinderTestService::instantiate();//注册进servicemanager中
  • //开启线程池,接收处理Client发送的进程间通信请求
  • ProcessState::self()->startThreadPool();
  • printf("ProcessState startThreadPool\n");
  • IPCThreadState::self()->joinThreadPool();
  • printf("IPCThreadState joinThreadPool\n");
  • return 0;
  • }

BinderTestService代码如下:

  • #include<binder/IServiceManager.h>
  • #include<binder/IPCThreadState.h>
  • #include<utils/Log.h>
  • #include"BinderTestService.h"
  • namespace android{
  • //这个函数是将自己注册进servicemanager
  • void BinderTestService::instantiate(){
  • int ret = 0;
  • ret = defaultServiceManager()->addService(String16("android.test.IBinderTest"),new BinderTestService());
  • printf("addService ret=%d\n",ret);
  • }
  • //这个函数是我们要实现的功能,其在BnBinderTest的onTransact中被调用
  • status_t BinderTestService::binderTest(const char *str)
  • {
  • printf("print string:%s\n",str);//简单的打印一个字串
  • return NO_ERROR;
  • }
  • BinderTestService::BinderTestService()
  • {
  • printf("BinderTestService is created\n");
  • }
  • BinderTestService::~BinderTestService()
  • {
  • printf("BinderTestService is destroyed\n");
  • }
  • status_t BinderTestService::onTransact(uint32_t code,const Parcel &data,Parcel *reply,uint32_t flags)
  • {
  • printf("BinderTestService onTransact\n");
  • return BnBinderTest::onTransact(code,data,reply,flags);//调用父类的函数
  • }
  • };

BnBinderTest代码如下:

  • #include <binder/Parcel.h>
  • #include "BnBinderTest.h"
  • namespace android {
  • //对BnBinderTest的onTransact实现,还会在后面其子类BnBinderTestService中重写此方法
  • status_t BnBinderTest::onTransact(uint32_t code,const Parcel &data,Parcel *reply,uint32_t flags)
  • {
  • switch(code){
  • case HW_HELLOWORLD2:{//在IBinderTest.h接口中定义
  • CHECK_INTERFACE(IBinderTest,data,reply);//检查接口
  • const char *str;
  • str = data.readCString();
  • reply->writeInt32(binderTest(str));//这里调用执行我们定义的binderTest函数
  • return NO_ERROR;
  • }break;
  • default:
  • return BBinder::onTransact(code,data,reply,flags);
  • }
  • }
  • };

    大概的代码调用流程是这样的:

    首先创建ProcessState和ServiceManger,然后启动BinderTestService的instantiate,这里面最关键的一步,就是defaultServiceManager()->addService(String16("android.test.IBinderTest"),new BinderTestService());将BinderTestService注册到ServiceManger中,起了个名叫android.testIBinderTest来标记一下。之后启动ProcessState进行,然后将IPCThreadState添加到线程池中。服务端的代码启动完成了。

 

    客户端代码,main_client代码如下:

  • #define LOG_TAG "main_helloworldclient"
  • #include <binder/IPCThreadState.h>
  • #include <binder/ProcessState.h>
  • #include <binder/IServiceManager.h>
  • #include <utils/Log.h>
  • #include <utils/RefBase.h>
  • #include "../common/IBinderTest.h"
  • using namespace android;
  • int main(void/*int argc,char *argv[]*/)
  • {
  • printf("HelloWorldSevice client is starting now");
  • //获取ServiceManager,从而能得到远程IBinder,实现通信
  • sp<IServiceManager> sm =defaultServiceManager();
  • sp<IBinder> b;
  • sp<IBinderTest> sBinderTest;
  • do{
  • b=sm->getService(String16("android.test.IBinderTest"));
  • if(b != 0){
  • break;
  • }
  • printf("BinderTest is not working,waiting...\n");
  • usleep(500000);
  • }while(true);
  • sBinderTest = interface_cast<IBinderTest>(b);
  • sBinderTest->binderTest("Hello,World!\n");
  • return 0;
  • }

    通过b=sm->getService(String16("android.test.IBinderTest"));获取了刚才在serviceManger中注册的BinderTestService。然后调用sBinderTest->binderTest("Hello,World!\n");传参Hello,World。
实际上binderTest的实现如下:

  • status_t BpBinderTest::binderTest(const char *str)
  • {
  • Parcel data,reply;
  • data.writeInterfaceToken(IBinderTest::getInterfaceDescriptor());
  • data.writeCString(str);
  • //通过code调用远程BinderTest方法,传递data
  • status_t status = remote()->transact(HW_HELLOWORLD2,data,&reply);
  • if(status != NO_ERROR){
  • printf("BinderTest error: %s",strerror(-status));
  • }else{
  • status = reply.readInt32();
  • }
  • return status;
  • }

这里面就用到了binder机制中的东西了,通过这个transact,将参数传递给service。

  而在Server中,通过onTransact来处理传递过来的事件。

  • status_t BnBinderTest::onTransact(uint32_t code,const Parcel &data,Parcel *reply,uint32_t flags)
  • {
  • switch(code){
  • case HW_HELLOWORLD2:{//在IBinderTest.h接口中定义
  • CHECK_INTERFACE(IBinderTest,data,reply);//检查接口
  • const char *str;
  • str = data.readCString();
  • reply->writeInt32(binderTest(str));//这里调用执行我们定义的binderTest函数
  • return NO_ERROR;
  • }break;
  • default:
  • return BBinder::onTransact(code,data,reply,flags);
  • }
  • }
  • };

简单说来,就是client调用transact发送请求,service通过onTransact接收到请求。刨除中间的实现来看,就像是Client端直接调用了binderTest方法似的。

运行结果如下:

先运行main_server,后台运行。然后执行main_client,通过binder,调用到了BinderTestService的binderTest方法,打印输出了Hello,World。

 

之前遇到的卡住的问题是这样,当直接执行的时候,现场如下:

addService时,直接返回-1。调查的过程比较曲折,结果却很简单,原因是由于main_server的权限不够,没有权限使用binder设备,所以返回了-1。这里用了临时性的对策,使用命令su将用户切换成超级用户,然后再执行可执行程序即可。

 

 


此内容由EEWORLD论坛网友Bingqi23原创,如需转载或用于商业用途需征得作者同意并注明出处

查看本帖全部内容,请登录或者注册
此帖出自Linux开发论坛
点赞 关注

回复
举报

492

帖子

1

TA的资源

一粒金砂(高级)

沙发
 

嗯。。。没找到上传附件的地方。需要原代码包的私信吧

此帖出自Linux开发论坛
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
有奖直播:当AI遇见仿真,会有什么样的电子行业革新之路?
首场直播:Simcenter AI 赋能电子行业研发创新
直播时间:04月15日14:00-14:50

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 8

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表