Android利用Binder进行通信
Binder作为Android使用最广泛的IPC通信机制之一,其重要性不言而喻。Binder的实现思想与原理各路大神已经分析的十分透彻了,个人觉得最好以及最详细的是老罗的Android之旅系列里面关于Binder的讲解:
[ Android进程间通信(IPC)机制Binder简要介绍和学习计划]
Binder作为一种高效的IPC通信手段,其使用也十分的简单,本文参考Android MediaPlay的架构实现了一个简单的server与client通信Demo,具体代码结构如下:
代码结构:
├── AndroidClient
│ ├── AndroidManifest.xml
│ ├── Android.mk
│ ├── jni
│ │ ├── Android.mk
│ │ ├── com_test_androidclient_MainActivity.cpp
│ │ └── com_test_androidclient_MainActivity.h
│ ├── proguard-project.txt
│ ├── project.properties
│ ├── res
│ │ ├── drawable-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-ldpi
│ │ ├── drawable-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── layout
│ │ │ └── activity_main.xml
│ │ ├── menu
│ │ │ └── main.xml
│ │ ├── values
│ │ │ ├── dimens.xml
│ │ │ ├── strings.xml
│ │ │ └── styles.xml
│ │ ├── values-v11
│ │ │ └── styles.xml
│ │ ├── values-v14
│ │ │ └── styles.xml
│ │ └── values-w820dp
│ │ └── dimens.xml
│ └── src
│ └── com
│ └── test
│ └── androidclient
│ └── MainActivity.java
├── Android.mk
├── client
│ ├── MyClient.cpp
│ └── test.cpp
├── include
│ ├── IMyService.h
│ ├── MyClient.h
│ └── MyService.h
└── server
├── IMyService.cpp
├── main_myserver.cpp
└── MyService.cpp
IMyService.h中声明Service端BnMyService与Client端代理BpMyService以及三个函数
#ifndef ANDROID_IMYSERVICE_H
#define ANDROID_IMYSERVICE_H
#include <utils/Errors.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <stdint.h>
#include <utils/String8.h>
namespace android {
class IMyService: public IInterface
{
public:
DECLARE_META_INTERFACE (MyService);
virtual String8 getStr() = 0;
virtual void setStr(String8 str) = 0;
virtual int32_t doAdd(int32_t a, int32_t b) = 0;
}; //class IMyService
class BpMyService: public BpInterface<IMyService>
{
public:
BpMyService(const sp<IBinder>& impl): BpInterface<IMyService>(impl) {}
virtual String8 getStr();
virtual void setStr(String8 status);
virtual int32_t doAdd(int32_t a, int32_t b);
}; //class BpMyService
class BnMyService: public BnInterface<IMyService>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
}; //class BnMyService
}; //namespace android
#endif
MyService.h,MyService继承自BnMyService
#ifndef ANDROID_MyService_H
#define ANDROID_MyService_H
#include <utils/Errors.h> // for status_t
#include "IMyService.h"
namespace android {
class MyService: public BnMyService {
public:
static void instantiate();
virtual String8 getStr();
virtual void setStr(String8 status);
virtual int32_t doAdd(int32_t a, int32_t b);
private:
static String8 mStr;
MyService();
virtual ~MyService();
}; //class MyService
}; //namespace android
#endif
MyClient.h中包含一个MyService端代理gMyService,由binder经过interface_cast转化而成,实际是一个BpMyService的remote对象
#ifndef ANDROID_MYCLIENT_H_
#define ANDROID_MYCLIENT_H_
#include <utils/threads.h>
#include "IMyService.h"
namespace android {
class MyClient : public RefBase
{
public:
static String8 getStr();
static void setStr(String8 str);
static int32_t doAdd(int32_t a, int32_t b);
private:
class DeathNotifier: public IBinder::DeathRecipient {
public:
DeathNotifier() {}
virtual ~DeathNotifier();
virtual void binderDied(const wp<IBinder>& who);
};
private:
static Mutex gMutex;
static sp<DeathNotifier> gDeathNotifier;
static sp<IMyService> gMyService;
static const sp<IMyService>& getMyService();
};
}; //namespace android
#endif
服务端与客户端通信,实际上是BnMyService与BpMyService经由binder进行通信。
IMyService.cpp
#define LOG_TAG "IMyService"
#include <utils/Log.h>
#include <string.h>
#include "IMyService.h"
namespace android {
enum {
GET_STR = IBinder::FIRST_CALL_TRANSACTION,
SET_STR,
DO_ADD,
};
String8 BpMyService::getStr()
{
Parcel data, reply;
data.writeInterfaceToken(IMyService::getInterfaceDescriptor());
status_t status = remote()->transact(GET_STR, data, &reply);
String8 str;
if (status == NO_ERROR) {
str = reply.readString8();
}
return str;
}
void BpMyService::setStr(String8 str)
{
Parcel data, reply;
data.writeInterfaceToken(IMyService::getInterfaceDescriptor());
data.writeString8(str);
status_t status = remote()->transact(SET_STR, data, &reply);
}
int32_t BpMyService::doAdd(int32_t a, int32_t b)
{
Parcel data, reply;
data.writeInterfaceToken(IMyService::getInterfaceDescriptor());
data.writeInt32(a);
data.writeInt32(b);
status_t status = remote()->transact(DO_ADD, data, &reply);
int32_t c;
if (status == NO_ERROR) {
c = reply.readInt32();
}
return c;
}
IMPLEMENT_META_INTERFACE(MyService, "IMyService");
//-----------------------------------------------------------------------------
status_t BnMyService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case GET_STR:
{
CHECK_INTERFACE(IMyService, data, reply);
String8 str = getStr();
reply->writeString8(str);
return NO_ERROR;
} break;
case SET_STR:
{
CHECK_INTERFACE(IMyService, data, reply);
String8 str = data.readString8();
setStr(str);
return NO_ERROR;
} break;
case DO_ADD:
{
CHECK_INTERFACE(IMyService, data, reply);
int32_t a = data.readInt32();
int32_t b = data.readInt32();
int32_t c = doAdd(a, b);
reply->writeInt32(c);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
}; //namespace android
MyService.cpp很简单,最关键的是instantiate函数,把MyService加入到ServiceManager中,句柄是一个String16类型的字符串“my.service”,除此之外,具体业务是在这里面实现的
#define LOG_TAG "MyService"
#include <stdio.h>
#include <string.h>
#include <utils/Log.h>
#include <utils/Errors.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include "MyService.h"
namespace android {
String8 MyService::mStr;
void MyService::instantiate() {
defaultServiceManager()->addService(String16("my.service"), new MyService());
}
MyService::MyService() {
ALOGD("MyService bind Construct");
}
MyService::~MyService() {
ALOGD("MyService bind deConstruct");
}
String8 MyService::getStr() {
return mStr;
}
void MyService::setStr(String8 str) {
mStr = str;
}
int32_t MyService::doAdd(int32_t a, int32_t b) {
return a+b;
}
};
main_myserver.cpp,server端main函数,通过MyService::instantiate()把MyService加入到安卓服务总管ServiceManager的管控中
#define LOG_TAG "main_myserver"
#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include "MyService.h"
using namespace android;
int main(int argc, char** argv)
{
signal(SIGPIPE, SIG_IGN);
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
MyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
MyClient.cpp,实现了Client获取服务端代理的过程,通过向安卓服务总管ServiceManager查询“my.service”句柄然后再加以转换得到一个远程对象gMyService,然后通过gMyService与服务端通信,实现Client的业务函数
#define LOG_TAG "MyClient"
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include "MyClient.h"
namespace android {
Mutex MyClient::gMutex;
sp<IMyService> MyClient::gMyService;
sp<MyClient::DeathNotifier> MyClient::gDeathNotifier;
const sp<IMyService>& MyClient::getMyService()
{
Mutex::Autolock _l(gMutex);
if (NULL == gMyService.get())
{
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("my.service"));
if (binder != 0)
break;
ALOGW("my.service not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
if (NULL == gDeathNotifier.get())
{
gDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(gDeathNotifier);
gMyService = interface_cast<IMyService>(binder);
}
return gMyService;
}
MyClient::DeathNotifier::~DeathNotifier() {
Mutex::Autolock lock(gMutex);
if (NULL != gMyService.get()) {
#if PLATFORM_SDK_VERSION < 23
gMyService->asBinder()->unlinkToDeath(this);
#else
gMyService->asBinder(gMyService)->unlinkToDeath(this);
#endif
}
}
void MyClient::DeathNotifier::binderDied(const wp<IBinder>& who) {
Mutex::Autolock lock(gMutex);
MyClient::gMyService.clear();
ALOGW("MyClient binder server died!");
}
//--------------------------------------------------------------------------------------
String8 MyClient::getStr()
{
return getMyService()->getStr();
}
void MyClient::setStr(String8 str)
{
return getMyService()->setStr(str);
}
int32_t MyClient::doAdd(int32_t a, int32_t b)
{
return getMyService()->doAdd(a, b);
}
}; //namespace android
Android使用Binder通信的实现到此已经差不多完成了,接下来是测试过程:
—-C应用测试
test.cpp , C++应用程序,简单的调用,可以通过logcat查看结果,测试的时候记得先把Server端跑起来
#define LOG_TAG "test"
#include <stdio.h>
#include <utils/Log.h>
#include "MyClient.h"
using namespace android;
int main(){
MyClient m;
m.setStr(String8("hello world"));
String8 result;
result = m.getStr();
ALOGW("getStr , result = %s", result.string());
int32_t sum = m.doAdd(10, 20);
ALOGW("doAdd, sum = %d", sum);
return 0;
}
结果:
—- Android应用测试
要想在Android应用层调用C层的客户端,必须通过JNI接口函数才能实现。
Java中声明JNI方法,然后通过javah生成jni头文件,调用上面Client端的业务函数实现jni头文件声明的方法,就打通了Java与C++的桥梁。
com_test_androidclient_MainActivity.h文件,通过javah静态生成的
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_test_androidclient_MainActivity */
#ifndef _Included_com_test_androidclient_MainActivity
#define _Included_com_test_androidclient_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_test_androidclient_MainActivity
* Method: setStr
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_test_androidclient_MainActivity_setStr
(JNIEnv *, jobject, jstring);
/*
* Class: com_test_androidclient_MainActivity
* Method: getStr
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_test_androidclient_MainActivity_getStr
(JNIEnv *, jobject);
/*
* Class: com_test_androidclient_MainActivity
* Method: doAdd
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_test_androidclient_MainActivity_doAdd
(JNIEnv *, jobject, jint, jint);
#ifdef __cplusplus
}
#endif
#endif
com_test_androidclient_MainActivity.cpp, jni桥梁的实现
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
#include "MyClient.h"
/* Header for class com_test_androidclient_MainActivity */
#ifdef __cplusplus
extern "C"
{
#endif
using namespace android;
/*
* Class: com_test_androidclient_MainActivity
* Method: setStr
* Signature: (Ljava/lang/String;)V
*/
JNIEXPORT void JNICALL Java_com_test_androidclient_MainActivity_setStr
(JNIEnv *env, jobject thiz, jstring jstr){
MyClient *m = new MyClient();
sp<MyClient> client(m);
const char *str = env->GetStringUTFChars(jstr, NULL);
client->setStr(String8(str));
}
/*
* Class: com_test_androidclient_MainActivity
* Method: getStr
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_test_androidclient_MainActivity_getStr
(JNIEnv *env, jobject thiz){
MyClient *m = new MyClient();
sp<MyClient> client(m);
String8 str = client->getStr();
return env->NewStringUTF(str.string());
}
/*
* Class: com_test_androidclient_MainActivity
* Method: doAdd
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_test_androidclient_MainActivity_doAdd
(JNIEnv *env, jobject thiz, jint a, jint b){
MyClient *m = new MyClient();
sp<MyClient> client(m);
return client->doAdd(a, b);
}
#ifdef __cplusplus
}
#endif
结果:
可以看到,c或者Android的客户端都能正确与server端进行交互。
以上就是在Android中使用Binder的简单步骤,本例中Server端在native世界中,而Client端在native世界与Java世界都有实现,其实也可以把Server端放在Java世界中,native世界的Client也可以通过Binder与其进行通信。如果Server端和Client端都在Java世界中,那就可以用著名的AIDL来实现了。
本文代码地址:
http://download.youkuaiyun.com/download/email_jade/9962184
源代码直接mm编译即可生成所有的文件