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 <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的业务函数

扫描二维码关注公众号,回复: 3913632 查看本文章
#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.csdn.net/download/email_jade/9962184
源代码直接mm编译即可生成所有的文件

猜你喜欢

转载自blog.csdn.net/email_jade/article/details/77817094
今日推荐