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编译即可生成所有的文件

更多相关文章

  1. 2014-11-8Android学习------Android(安卓)实现图片的旋转-------
  2. Android(安卓)init源代码分析(1)概要分析
  3. Android小項目之---ListView实现论坛管理效果
  4. Android的按钮监听事件&自定义回调函数
  5. Android热补丁技术—dexposed原理简析(手机淘宝采用方案)
  6. [置顶] Android实现数据存储技术集锦
  7. 浅谈Java中Collections.sort对List排序的两种方法
  8. 箭头函数的基础使用
  9. Python技巧匿名函数、回调函数和高阶函数

随机推荐

  1. ImageButton 边框问题
  2. Android(安卓)ScrollView反弹效果的实现
  3. android 中 startActivityForResult 的使
  4. Android系统编译so库提示error undefined
  5. Activity简介
  6. Android实现RecyclerView的下拉刷新和上
  7. 详解Android中通过Intent类实现组件间调
  8. HashMap 的 7 种遍历方式与性能分析!「修
  9. Android(java)学习笔记108:通过反射获取私有
  10. android点击查看大图(长按保存图片)