在上一篇博客中,我们借助ServiceManager从源码的角度简要分析了一下Binder的使用机制;接下来,我们就可以按照ServiceManager的实现套路,实现一个自己的Binder服务。
先列出代码目录结构:
1、服务业务接口:/mybinder/extra/IMyService.cpp
/mybinder/extra/IMyService.h
2、Server组件接口:/mybinder/server/IMyServer.cpp
/mybinder/server/Android.mk
3、Client组件接口:/mybinder/client/IMyClient.cpp
/ mybinder/client/Android.mk
下面直接上源代码。
IMyService.h:
#ifndef _MY_SERVICE_
#define _MY_SERVICE_
#include
#include
#include
#include
#define MY_SERVICE "coder.core.MyService"
using namespace android;
//定义业务函数接口,声明DECLARE_META_INTERFACE()宏模板函数
class IMyService : public IInterface
{
public:
DECLARE_META_INTERFACE(MyService);
public:
virtual void sendInt(int32_t val) = 0;
virtual String8 getString() = 0;
public:
//业务函数的标号,用以区分是调用哪个业务,值对应的就是onTransact()、transact()
//中的code参数,用在switch...case...判断中
enum{
SEND_INT = IBinder::FIRST_CALL_TRANSACTION,
GET_STRING
};
};
//定义Server组件
class BnMyService : public BnInterface
{
public:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
};
#endif
IMyService.cpp:
#include
#include
#include "IMyService.h"
class BpMyService : public BpInterface
{
public:
BpMyService(const sp& impl) : BpInterface(impl){}
public:
void sendInt(int32_t val){
Parcel data, reply;
data.writeInterfaceToken(IMyService::getInterfaceDescriptor());
data.writeInt32(val);
remote()->transact(SEND_INT, data, &reply);
}
String8 getString(){
Parcel data, reply;
data.writeInterfaceToken(IMyService::getInterfaceDescriptor());
remote()->transact(GET_STRING, data, &reply);
String8 res = reply.readString8();
return res;
}
};
//实现IMPLEMENT_META_INTERFACE()宏模板函数
IMPLEMENT_META_INTERFACE(MyService, MY_SERVICE);
status_t BnMyService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code){
case SEND_INT:
{
CHECK_INTERFACE(IMyService, data, reply);
int32_t val = data.readInt32();//去除传入的参数,调用服务类的函数
sendInt(val);
return NO_ERROR;
}
break;
case GET_STRING:
{
CHECK_INTERFACE(IMyService, data, reply);
String8 res = getString();//调用服务类的函数
reply->writeString8(res);//将结果存入reply,BpMyService端可以读出该结果
return NO_ERROR;
}
break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
};
#include
#include
#include "../extra/IMyService.h"
class MyService : public BnMyService
{
public:
MyService(){option = 0;}
virtual ~MyService(){}
public:
static void instance(){
defaultServiceManager()->addService(String16(MY_SERVICE), new MyService());
}
void sendInt(int32_t val)
{
option = val;
}
String8 getString()
{
if(option <= 0)
return String8("you may not set val, or the value you set is <= 0.");
else
return String8("you have set the option with the value > 0.");
return String8("this is default string value.");
}
private:
int32_t option;
};
int main(int argc, char** argv)
{
//注册MyService服务到系统中
MyService::instance();
//开启线程池,接收处理Client发送的进程间通信请求
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
return 0;
}
Server组件编译的Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGSS := optional
LOCAL_SRC_FILES := ../extra/IMyService.cpp \
MyServer.cpp
LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder
LOCAL_MODULE := MyService
include $(BUILD_EXECUTABLE)
MyClient.cpp:
#include
#include "../extra/IMyService.h"
int main()
{
sp binder = defaultServiceManager()->getService((String16(MY_SERVICE));
if(binder == NULL){
printf("Failed to get the MyService binder object.\n");
return -1;
}
sp service = IMyService::asInterface(binder);
if(service == NULL){
printf("Failed to get the MyService service.\n");
return -1;
}
String8 str1 = service->getString();
printf("we get string value: %s \n",str1.string());
service->sendInt(2);
String8 str2 = service->getString();
printf("we get string value: %s\n",str2.string());
}
Client组件编译的Android.mk文件:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGSS := optional
LOCAL_SRC_FILES := ../extra/IMyService.cpp \
MyClient.cpp
LOCAL_SHARED_LIBRARIES := libcutils libutils libbinder
LOCAL_MODULE := MyClient
include $(BUILD_EXECUTABLE)
代码组织完成后,我们可以将工程目录放到源码的external/目录下,使用mmm命令将Server组件、Client组件编译成两个可执行文件来运行、验证。
我们需要先运行Server组件,再运行Client组件;平台上验证的效果如图所示:
再附一张这个简单服务的类继承关系图:
由于公司办公电脑限制,即使是自己写的一些demo程序都会被加密,在外部电脑上无法正常查看;所以,在公司平台上验证完成后,又手动敲了一遍到文档中......,所以代码中可能会有些错误(啥符号忘写之类的,总的代码程序应该是没有大问题的)。如果发现有错误,欢迎提出,我会及时修改,欢迎交流。
总之,这里就是借助Binder API实现了一个简单的服务,也没啥其他的内容。