需求
最近公司需要在native层写一个c++服务,用来与上层通讯,由于自己并不是很精通c++,所以决定从简单的入手,先尝试写一个binder服务。
具体实现
实现一个binder通信实例,需要经过以下步骤:
1、获得ServiceManager的对象引用
2、向ServiceManager注册新的Service
3、在Client中通过ServiceManager获得Service对象引用
4、在Client中发送请求,由Service返回结果。
具体代码:
1、编写myservic.h文件
#include <utils/threads.h>
#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/BpBinder.h>
#include <binder/Parcel.h>
namespace android {
class MyService : public BBinder
{
mutable Mutex mLock;
int32_t mNextConnId;
public:
static int instantiate();
MyService();
virtual ~MyService();
virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);
};
}; //namespace
2、编写myservice.cpp文件
#include "myservice.h"
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
namespace android {
static struct sigaction oldact;
static pthread_key_t sigbuskey;
int MyService::instantiate()
{
LOGE("MyService instantiate");
// defaultServiceManager ()获得ServiceManager的对象引用,addService()可向ServiceManager注册新的服务
int r = defaultServiceManager()->addService(String16("android.myservice"), new MyService());
LOGE("MyService r = %d/n", r);
return r;
}
MyService::MyService()
{
LOGV("MyService created");
mNextConnId = 1;
pthread_key_create(&sigbuskey, NULL);
}
MyService::~MyService()
{
pthread_key_delete(sigbuskey);
LOGV("MyService destroyed");
}
// 每个系统服务都继承自BBinder类,都应重写BBinder的onTransact虚函数。当用户发送请求到达Service时,系统框架会调用Service的onTransact函数,该函数分析接收到的数据包,调用相应的接口函数处理请求
status_t MyService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code)
{
case 0: {
pid_t pid = data.readInt32();
int num = data.readInt32();
num = num + 100;
reply->writeInt32(num);
return NO_ERROR;
}
break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
}; //namespace
3、编写Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := myservice.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := libutils libbinder
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := libmyservice
include $(BUILD_SHARED_LIBRARY)
mk文件写完之后进行编译,编译完生成libmyservice.so文件。
4、编写myserver.cpp文件与相应的mk文件
#include <sys/types.h>
#include <unistd.h>
#include <grp.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
#include <private/android_filesystem_config.h>
#include "../libmyservice/myservice.h"
using namespace android;
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();//获得ServiceManager接口
LOGI("ServiceManager: %p", sm.get());
MyService::instantiate();
//执行addService()函数,注册服务
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
//进入循环,等待客户端的请求
return 0;
}
mk文件:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
myserver.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := \
libutils libbinder libmyservice
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := myserver
include $(BUILD_EXECUTABLE)
编译生成可执行文件myserver。5、编写myclient.h文件
namespace android
{
class MyClient {
public:
void add100(int n);
private:
static const void getMyService();
//通过ServiceManager获取服务接口
};
}; //namespace
6、编写myclient.cpp文件
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "myclient.h"
namespace android
{
sp<IBinder> binder;
void MyClient::add100(int n)
{
getMyService();
Parcel data, reply;
int answer;
data.writeInt32(getpid());
data.writeInt32(n);
LOGE("BpMyService::create remote()->transact()/n");
binder->transact(0, data, &reply);
answer = reply.readInt32();
printf("answner=%d/n", answer);
return;
}
const void MyClient::getMyService()
{
sp<IServiceManager> sm = defaultServiceManager();
binder = sm->getService(String16("android.myservice"));
LOGE("MyClient::getMyService %p/n",sm.get());
if (binder == 0) {
LOGW("MyService not published, waiting...");
return;
}
}
}; //namespace
using namespace android;
int main(int argc, char** argv)
{
MyClient* p = new MyClient();
p->add100(1);
return 0;
}
7、编写client端的Android.mk文件
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
myclient.cpp
LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
LOCAL_SHARED_LIBRARIES := \
libutils libbinder libmyservice
LOCAL_MODULE_TAGS := optional
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := myclient
include $(BUILD_EXECUTABLE)
写完之后编译生成myclient可执行文件。
一个binder的服务端与客户端的例子就写好了,生成的so文件push到system/lib/下面,两个可执行文件push到system/bin/目录下。