Android利用Binder进行通信
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 #include #include #include #include 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 IMyServiceclass BpMyService: public BpInterface{public: BpMyService(const sp& impl): BpInterface(impl) {} virtual String8 getStr(); virtual void setStr(String8 status); virtual int32_t doAdd(int32_t a, int32_t b);}; //class BpMyServiceclass BnMyService: public BnInterface{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 // 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 #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& who); };private: static Mutex gMutex; static sp gDeathNotifier; static sp gMyService; static const sp& getMyService();};}; //namespace android#endif
服务端与客户端通信,实际上是BnMyService与BpMyService经由binder进行通信。
IMyService.cpp
#define LOG_TAG "IMyService"#include #include #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 #include #include #include #include #include #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 #include #include #include #include "MyService.h"using namespace android;int main(int argc, char** argv){ signal(SIGPIPE, SIG_IGN); sp proc(ProcessState::self()); sp sm = defaultServiceManager(); MyService::instantiate(); ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();}
MyClient.cpp,实现了Client获取服务端代理的过程,通过向安卓服务总管ServiceManager查询“my.service”句柄然后再加以转换得到一个远程对象gMyService,然后通过gMyService与服务端通信,实现Client的业务函数
#define LOG_TAG "MyClient"#include #include #include "MyClient.h"namespace android {Mutex MyClient::gMutex;sp MyClient::gMyService;sp MyClient::gDeathNotifier;const sp& MyClient::getMyService(){ Mutex::Autolock _l(gMutex); if (NULL == gMyService.get()) { sp sm = defaultServiceManager(); sp 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(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& 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 #include #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 /* Header for class com_test_androidclient_MainActivity */#ifndef _Included_com_test_androidclient_MainActivity#define _Included_com_test_androidclient_MainActivity#ifdef __cplusplusextern "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 #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 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 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 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.csdn.net/download/email_jade/9962184
源代码直接mm编译即可生成所有的文件
更多相关文章
- 2014-11-8Android学习------Android(安卓)实现图片的旋转-------
- Android(安卓)init源代码分析(1)概要分析
- Android小項目之---ListView实现论坛管理效果
- Android的按钮监听事件&自定义回调函数
- Android热补丁技术—dexposed原理简析(手机淘宝采用方案)
- [置顶] Android实现数据存储技术集锦
- 浅谈Java中Collections.sort对List排序的两种方法
- 箭头函数的基础使用
- Python技巧匿名函数、回调函数和高阶函数