在前面是小节中,讲解了C程序的使用示例,又深入的分析了binder驱动程序。接下来我们讲解怎么使用C++去使用这个binder服务,使用C++的目的,就是为了能够去复用别人的代码,让我们的程序更加的简单。
在这个课时的第一个小节,我们将使用C++编写一个服务,并且使用这个服务。在这个之前,我们先回顾一下之前有C程序写的代码,下面是回顾知识的简单框图:
我们知道binderi系统涉及三个方面,service_manager,test_server.c以及test_client.c,其中: 1.test_server提供服务:sayhello(),sayhello_to() 2.test_client使用服务:sayhello(),sayhello_to() 3.service_manager管理服务:
test_server会通过addService向service_manager注册服务,test_client通过getService获取服务。在test_client中也存在与test_server提供服务的同名函数,如sayhello(),sayhello_to()。但是他们两者的实现几乎是完全不一样的: test_client中sayhello()或sayhello_to():构造数据,发送数据。 test_server中sayhello()或sayhello_to():一个循环,接收数据,解析数据,调用sayhello()或sayhello_to()函数 这种程序结构的编写是非常的差的,因为都集中在一个.c文件之中,我们看看能做哪些改进。
下面是一个改进之后的框图,我们将围绕着这个框图进行讲解: 我们发现server与client都会调用sayhello(),sayhello_to()。我们可以他sayhello(),sayhello_to()写在一个头文件之中IHelloService.h,其中声明sayhello(),sayhello_to()两个函数。在server与client端我们分别去实现这两个函数: server端:在文件BnHelloService.c(B代表binder,n代表native本地实现)实现sayhello(),sayhello_to()函数,并且包含头文件"IHelloService.h"。server在接收到client的数据,假设调用onTransact进行解析,根据解析得到的信息调用对应的函数,那么我们还需要一个主循环,让这个循环不停的解析数据,这个主循环在test_sevice.c中编写,其中存在man函数,mian函数包括了一个while循环,这个循环主要接受数据,然后代用onTransaction。 client端:在文件BpHelloService.c(B代表binder,p代表proxy,表示代表的意思),其中也包含头文件IHelloService.h,其中也要实现sayhello(),sayhello_to()两个函数(构造,发送数据)。这边也包含了test_client.c,其中照样存在main函数,调用sayhello()或者sayhello_to()函数。
server端与client端的接收,和发送数据,共用bind.c这个文件.或者一个库。下面我们开始编写C++程序。
c++程序编写参考文件:
frameworks\av\include\media\IMediaPlayerService.h (IMediaPlayerService,BnMediaPlayerService)
frameworks\av\media\libmedia\IMediaPlayerService.cpp (BpMediaPlayerService)
frameworks\av\media\libmediaplayerservice\MediaPlayerService.h
frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
frameworks\av\media\mediaserver\Main_mediaserver.cpp (server, addService)
首先创建文件夹APP_004_Binder_CPP_App,在其中创建IHelloService.h,BpHelloService.cpp,BnHelloService.cpp,test_client.cpp,test_server.cpp。
IHelloService.hIHelloService.h,编写内容如下:
/* ²Î¿¼: frameworks\av\include\media\IMediaPlayerService.h */
#ifndef ANDROID_IHELLOERVICE_H
#define ANDROID_IHELLOERVICE_H
#include // for status_t
#include
#include
#include
#include
#include
#include
#define HELLO_SVR_CMD_SAYHELLO 0
#define HELLO_SVR_CMD_SAYHELLO_TO 1
namespace android {
class IHelloService: public IInterface
{
public:
DECLARE_META_INTERFACE(HelloService);
virtual void sayhello(void) = 0;
virtual int sayhello_to(const char *name) = 0;
};
class BnHelloService: public BnInterface
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
virtual void sayhello(void);
virtual int sayhello_to(const char *name);
};
#endif
BnHelloService.cpp
/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */
#include "IHelloService.h"
#define LOG_TAG "HelloService"
namespace android {
status_t BnHelloService::onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0)
{
/* 解析数据,调用sayhello/sayhello_to */
switch (code) {
case HELLO_SVR_CMD_SAYHELLO: {
sayhello();
return NO_ERROR;
} break;
case HELLO_SVR_CMD_SAYHELLO_TO: {
/* 从data中取出参数 */
int32_t policy = data.readInt32();
String16 name16 = data.readString16();
String8 name8(name16);
int cnt = sayhello_to(name8.string());
/* 把返回值写入reply传回去 */
reply->writeInt32(cnt);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
void BnHelloService::sayhello(void)
{
static int cnt = 0;
ALOGI("say hello : %d\n", cnt++);
}
int BnHelloService::sayhello_to(const char *name)
{
static int cnt = 0;
ALOGI("say hello to %s : %d\n", name, cnt++);
return cnt;
}
}
BpHelloService.cpp
/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */
#include "IHelloService.h"
class BpHelloService: public BpInterface
{
public:
BpHelloService(const sp& impl)
: BpInterface(impl)
{
}
void sayhello(void)
{
/* 构造/发送数据 */
Parcel data, reply;
data.writeInt32(0);
remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
}
int sayhello_to(const char *name)
{
/* 构造/发送数据 */
Parcel data, reply;
data.writeInt32(0);
data.writeString16(String16(name));
remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
return reply.readInt32();
}
};
IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService");
test_server.cpp
/* 参考: frameworks\av\media\mediaserver\Main_mediaserver.cpp */
#define LOG_TAG "HelloService"
//#define LOG_NDEBUG 0
#include
#include
#include
#include
#include
#include
#include
#include
using namespace android;
void main(void)
{
/* addService */
/* while(1){ read data, 解析数据, 调用服务函数 } */
/* 打开驱动, mmap */
sp proc(ProcessState::self());
/* 获得BpServiceManager */
sp sm = defaultServiceManager();
sm->addService(String16("hello"), new BnHelloService());
/* 循环体 */
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
test_client.cpp
#define LOG_TAG "HelloService"
//#define LOG_NDEBUG 0
#include
#include
#include
#include
#include
#include
#include
#include
using namespace android;
/* ./test_client hello
* ./test_client hello
*/
int main(int argc, char **argv)
{
int cnt;
if (argc getService(String16("hello"));
if (binder == 0)
{
ALOGI("can't get hello service\n");
return -1;
}
/* service肯定是BpHelloServie指针 */
sp service =
interface_cast(binder);
/* 调用Service的函数 */
if (argc sayhello();
ALOGI("client call sayhello");
}
else {
cnt = service->sayhello_to(argv[2]);
ALOGI("client call sayhello_to, cnt = %d", cnt);
}
return 0;
}
梳理流程
编写以上文件后,我们来梳理一下binder服务c++实现的过程,下面是一个流程图,围绕着该流程图讲解 1.定义接头类IHelloService,在其中声明sayhello()与sayhello_to()函数。 2.server端实现一个BnHelloService,在其中实现接口中的函数,以及一个onTransact函数 3.client端实现BpHelloService,同样实现接口中的函数,函数内容为构建一些数据,然后通过binder发送。其目的是为了调用服务端的函数。 4.实现server:在main函数中,通过addservice()添加服务,然后添加一个while()循环,循环读取,解析数据,然后调用函数。 5.实现client:在main函数中,通过svr=getService()获取服务,然后调用其中svr.sayhello或者svr.sayhello_to函数。
该小节我们只是编写写了代码,但是没有调试,下小节我们去调试代码(实际以上代码,都为已经调试过得代码呢)。