花了3天时间 ,研究了在android中如何搭建客户端服务端,利用binder机制进行通信。网上资料还是很多的,这里先不深入探讨binder驱动相关的东西,一切还是以应用为主。后续会带来binder的深入研究。
服务的创建和客户端的访问简单的如下图的流程:
其中会发现客户端和服务端的通信就是通过binder来实现的(其实也不是binder,还有幕后黑手但这里不讨论)。简单的就理解是通过binder来通信的吧!
PBbinder: 很简单,就是客户端要访问服务端的时候需要的工具
Bbinder : 同上相反
这里我个人理解是这两个东西就像是两个端口,就像是socket里面的端口号类似,实际代码中调用的通讯方法还不是这个。
好了,开始介绍上面的流程,在Android的世界里,都是客户端通过服务端请求到数据来完成工作的,所以这就需要一个想servicemanager一样的管理模块来管理service。
具体的代码流程就不说了,网上多的事,主要通过接口调用来讲解使用方法.
当客户端要像服务端请求数据的时候,都需要像servicemanager询问服务信息,当然了,这个服务信息需要在创建服务的时候进行注册,android在启动的时候,会运行所有的服务进程,而这些服务进程的创建过程中就完成了向servicemanager的注册工作
点击(此处)折叠或打开
sp proc(ProcessState::self());
//get service manager
sp sm = defaultServiceManager();
sm->addService(String16("service.testmanager"),new Test());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
spsm=defaultServiceManager()
这个函数就是用来获取IServiceManager的子类对象的。这里可能有点疑惑 这个是什么东西,看过源码的话就会比较清楚,其实defaultServiceManager就是通过servicemanager的binder号0来获取到BPServiceManager这个类的,而这个类其实就是真正用于通信用的接口类.
这个类和IServiceManager稍后再说,往下看,addService就是增加自定义的服务接口了,注意到后面的new Test了吗 这个也稍后再说,这里就是注册服务了。
前面提到了IServiceManager,那这个到底是什么呢?其实andorid里是通过创建一个纯虚的接口,随后使客户端和服务端的业务都用同一套,具体设计原因不清楚,在我浏览源码的过程中总结下来就是你不得不用I开头来创建你自己的春虚类,应为andorid对此做了限制,这点稍后再说。
源码进去看到最后就会发现defaultServiceManager返回回来的正是重载了IServicemanager方法的子类。所以知道了吧。addservice其实就是一个用于像servicemanager服务通信的借口,通过这个借口想服务器发送注册信息完成注册。那BPserviceManager这个子类又是干什么的呢?这个子类也是需要完全按照android的框架来实现。
有了这些概念
现在通过代码来看看具体的实现:
点击(此处)折叠或打开
namespace android
{
class ITest : public IInterface
{
public:
DECLARE_META_INTERFACE(Test);
virtual void getTest() = 0;
};
class BnTest: public BnInterface
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
}
这个头文件是服务端和客户端都会用公用接口类,可以看到是用I开头的。DECLARE_META_INTERFACE(Test);这个宏就是andorid的限制所在了,里面主要是申明了一个很重要的接口,用于返回Bpxxx对象,这个对象的作用之前也了解过了就是通信用的接口类。
BnTest这个类的创建,可以发现也是继承自ITest,这个类是服务端的通信类,主要需要重载onTrancsact,这个函数用于接受客户端发来的消息已进行调用服务端重载接口来处理业务。
点击(此处)折叠或打开
enum {
8 PRINT = IBinder::FIRST_CALL_TRANSACTION,
9 };
10
11
12
13
14 class BpTest : public BpInterface
15 {
16 public:
17 BpTest(const sp& impl ):BpInterface(impl)
18 {
19
20 }
21 virtual void getTest()
22 {
23 printf("in the get Test\n");
24 Parcel data, reply;
25 data.writeInterfaceToken(ITest::getInterfaceDescriptor());
26 remote()->transact(PRINT, data, &reply);
27 printf("send Print %d\n",reply.readInt32());
28 }
29
30 };
31
32 IMPLEMENT_META_INTERFACE(Test,"android.TestServer.ITest");
33
34
35 status_t BnTest::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
36 {
37
38 switch(code)
39 {
40 case PRINT:
41 {
42 printf("got the client msg\n");
43 CHECK_INTERFACE(ITest, data, reply);
44 getTest();
45 reply->writeInt32(100);
46 return NO_ERROR;
47
48
49 }break;
50 default:break;
51 }
52 return NO_ERROR;
53 }源文件的实现可以很清楚的发现,Bptest重载了ITest里的get方法,这个方法就是给客户端用的,而onTrancat函数就是处理客户端发送过来的消息已实现逻辑业务处理的,而getTest()这个函数的调用其实就是调用的服务端继承ITest的方法,那这个方法是那里实现的呢?
点击(此处)折叠或打开
namespace android
{
class Test : public BnTest
{
public:
Test();
~Test();
void getTest();
void print();
};
}
原来是在我们自己创建的服务端的处理类的时候继承Bntest,重载ITest的方法,那是怎么在运行的时候,BnTest知道要调用重载的方法呢? 原来就是在之前注册服务的时候new Test()的时候通知到的。
现在就清楚了,接下来就是处理消息返回给客户端的事情了
点击(此处)折叠或打开
case PRINT:
41 {
42 printf("got the client msg\n");
43 CHECK_INTERFACE(ITest, data, reply);
44 getTest();
45 reply->writeInt32(100);
46 return NO_ERROR;
47
48
49 }break;
android中通过parcel类来打包数据通过binder进行传输,所以上面的代码在接受到print消息之后就会执行一系列操作,
而客户端在发送消息后也是从parcel中获取到返回消息的
点击(此处)折叠或打开
virtual void getTest()
22 {
23 printf("in the get Test\n");
24 Parcel data, reply;
25 data.writeInterfaceToken(ITest::getInterfaceDescriptor());
26 remote()->transact(PRINT, data, &reply);
27 printf("send Print %d\n",reply.readInt32());
28 }
这里有个地方要注意,remote()这个函数其实返回的就是pbbinder,所以最后看到还是要通过bninder发送消息。
点击(此处)折叠或打开
root@android:/data # ./Test &
[1] 893
root@android:/data # ./Testclient
in the get Test
got the client msg
wahahaha
send Print 100
机器运行效果如上,起了服务端后,启动客户端,进行通信。 个人总结,参考就可