手写一个C++ Android Binder服务及源码分析

前言

之前我写了三篇文章深入内核讲明白Android Binder,这三篇文章可以理解为是Android Binder的原理篇,本篇文章算是应用篇,讲明白如何使用C++语言编写自己的binder服务(C++只是利用语言优势,更好的封装了C语言实现的Android binder,方便开发人员使用binder),并深入源码搞清楚C++编写binder服务的逻辑。
深入内核讲明白Android Binder【一】
深入内核讲明白Android Binder【二】
深入内核讲明白Android Binder【三】

阅读建议:

  1. 如果有余力建议去阅读下我之前写的三篇【深入内核讲明白Android Binder】系列的文章,这三篇文章深入linux内核解析android binder源码,如果搞清楚了这三篇文章,再来看这篇使用C++应用Android binder的文章就非常容易理解。
  2. 如果直接看这篇文章也是可以的,但这篇文章只能使您停留在会使用C++语言编写自己的Android binder服务的层面上。

一、 基于C语言编写Android Binder跨进程通信Demo总结及改进

深入内核讲明白Android Binder【一】我们讲解了如何使用C语言编写自己的binder服务,但所有代码都写在一个c文件中。职责不够分明,代码不易重用,也不利于代码阅读和维护。
在这里插入图片描述

我们可以把上面的结构优化下面的结构,即定义一个头文件IHelloService.h包含服务端和客户端共用的函数接口,BnHelloService和BpHelloService充当代理,分别实现客户端和服务端的功能,分别供binder服务test_server和客户端test_client.c使用。而这也是C++语言编写binder服务的整体框架。
在这里插入图片描述

二、C++语言编写自己的Binder服务Demo

1. binder服务demo功能介绍

我们继续采用深入内核讲明白Android Binder【一】中C语言实现的binder服务功能。C++实现的binder服务也提供sayhello和sayhello_to两个函数供客户端调用。

2. binder服务demo代码结构图

  • IHelloService.h:定义服务端和客户端共用的接口类。
  • BnHelloService.cpp:服务端的代理类。BnHelloService类的具体实现(binder服务的本地实现)
  • BpHelloService.cpp:客户端的代理类。文件中定义BpHelloService类,继承IHelloService(客户端调用binder服务的实现)
  • test_server.cpp:binder服务提供者(服务端)
  • test_client.cpp:binder服务使用者(客户端)
    在这里插入图片描述

3. binder服务demo代码实现

3.1 IHelloService.h代码实现

定义接口类IHelloService,类中有sayhello,sayhello_to两个纯虚函数。BnHelloService类和BpHelloService类会继承IHelloService实现这两个虚函数。

/* 参考: frameworks\av\include\media\IMediaPlayerService.h */

#ifndef ANDROID_IHELLOERVICE_H
#define ANDROID_IHELLOERVICE_H

#include <utils/Errors.h>  // for status_t
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>

#define HELLO_SVR_CMD_SAYHELLO     1
#define HELLO_SVR_CMD_SAYHELLO_TO  2
#define HELLO_SVR_CMD_GET_FD       3


namespace android {
   
   

class IHelloService: public IInterface
{
   
   
public:
    //声明接口
    DECLARE_META_INTERFACE(HelloService);
        virtual void sayhello(void) = 0;
        virtual int sayhello_to(const char *name) = 0;
};
//继承自IHelloService和BBinder
class BnHelloService: public BnInterface<IHelloService>
{
   
   
public:
        virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);

        virtual void sayhello(void);
        virtual int sayhello_to(const char *name);

        BnHelloService();
};
}


//https://github.com/CyanogenMod/android_frameworks_native/blob/cm-14.1/include/binder/IInterface.h
template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
   
   
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;
    typedef INTERFACE BaseInterface;

protected:
    virtual IBinder*            onAsBinder();
};

//通过预处理器运算符##(标记粘合符),声明接口
#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const android::String16 descriptor;                          \
    static android::sp<I##INTERFACE> asInterface(                       \
            const android::sp<android::IBinder>& obj);                  \
    virtual const android::String16& getInterfaceDescriptor() const;    \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();   

3.2 BnHelloService.cpp代码实现

BnHelloService作为服务端的代理类,是binder服务的本地实现

/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */

#define LOG_TAG "HelloService"

#include "IHelloService.h"


namespace android {
   
   

BnHelloService::BnHelloService()
{
   
   
}

// 根据code,确定调用服务的哪一个函数
status_t BnHelloService::onTransact( uint32_t code,
                                const Parcel& data,
                                Parcel* reply,
                                uint32_t flags)
{
   
   
        /* 解析数据,调用sayhello/sayhello_to */

    switch (code) {
   
   
        case HELLO_SVR_CMD_SAYHELLO: {
   
   
                        sayhello();
                        reply->writeInt32(0);  /* no exception */
            return NO_ERROR;
        } break;
                
        case HELLO_SVR_CMD_SAYHELLO_TO: {
   
   

                        /* 从data中取出参数 */
                        int32_t policy =  data.readInt32();
                        String16 name16_tmp = data.readString16(); /* IHelloService */
                        
                        String16 name16 = data.readString16();
                        String8 name8(name16);

                        int cnt = sayhello_to(name8.string());

                        /* 把返回值写入reply传回去 */
                        reply->writeInt32(0);  /* no exception */
                        reply->writeInt32(cnt);
                        
            return NO_ERROR;
        } break;       
        default:
            return BBinder::onTransact(code, data, reply, flags);
    }
}

void BnHelloService::sayhello(void)
{
   
   
        static int cnt = 0;
        ALOGI("say hello : %d\n", ++cnt);

}

int BnHelloService::sayhello_to(const char *name)
{
   
   
        static int cnt = 0;
        ALOGI("say hello to %s : %d\n", name, ++cnt);
        return cnt;
}
}

3.3 BpHelloService.cpp代码实现

BpHelloService作为客户端的代理类,是客户端调用binder服务的具体实现。
客户端调用服务端函数的步骤:1. 构造数据;2. 向服务端发送数据;3. 获取服务端返回的数据


/* 参考: frameworks\av\media\libmedia\IMediaPlayerService.cpp */

#include "IHelloService.h"

namespace android {
   
   
//继承自IHelloService和BpRefBase
class BpHelloService: public BpInterface<IHelloService>
{
   
   
public:
    BpHelloService(const sp<IBinder>& impl)
        : BpInterface<IHelloService>(impl)
    {
   
   
    }

        void sayhello(void)
        {
   
   
         /* 构造/发送数据 */

        Parcel data, reply;
        //为了与C实现的binder兼容,需要把传入的数据格式与C读取的数据格式一致
        data.writeInt32(0);
        data.writeString16(String16("IHelloService"));
        
        // 发送数据
        remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
        }
        
        int sayhello_to(const char *name)
        {
   
   
                /* 构造/发送数据 */
                Parcel data, reply;
                int exception;

                data.writeInt32(0);
                data.writeString16(String16("IHelloService"));

                data.writeString16(String16(name));
                
                // 发送数据
                remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
                
                // 获得服务返回的数据
                exception = reply.readInt32();
                if (exception)
                    return -1;
                else
                    return reply.readInt32();
        }
};

// 实现接口
IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService");

}

//https://github.com/CyanogenMod/android_frameworks_native/blob/cm-14.1/include/binder/IInterface.h
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
   
   
public:
    explicit                    BpInterface(const sp<IBinder>& remote);
    typedef INTERFACE BaseInterface;

protected:
    virtual IBinder*            onAsBinder();
};

//通过预处理器运算符##(标记粘合符),实现接口   
 #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const android::String16 I##INTERFACE::descriptor(NAME);             \
    const android::String16&                                            \
            I##INTERFACE::getInterfaceDescriptor() const {
     
                   \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
            const android::sp<android::IBinder>& obj)                   \
    {
     
                                                                        \
        android::sp<I##INTERFACE> intr;                                 \
        if (obj != NULL) {
     
                                                   \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {
     
                                              \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() {
     
      }                                    \
    I##INTERFACE::~I##INTERFACE() {
     
      }     

3.4 test_server.cpp代码实现

test_server是binder服务提供者(服务端),核心步骤:

  1. 打开驱动
  2. 获取servicemanager
  3. 向servicemanager中添加服务
  4. 死循环等待客户端发来数据,并进行处理和回复

/* 参考: frameworks\av\media\mediaserver\Main_mediaserver.cpp */

#define LOG_TAG "TestService"
//#define LOG_NDEBUG 0

#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>

#include "IHelloService.h"
#include "IGoodbyeService.h"

#define SOCKET_BUFFER_SIZE      (32768U)

using namespace android;

/* usage : test_server  */
int main(void)
{
   
   
        /* 打开驱动, mmap */
        sp<ProcessState> proc(ProcessState::self());

        /* 获得BpServiceManager (servicemanager的代理类)*/
        sp<IServiceManager> sm = defaultServiceManager();

        /* 添加服务 */
        sm->addService(String16("hello"), new BnHelloService(sockets[1]));

        /* 循环体 */
        ProcessState::self()->startThreadPool(); // 创建子线程,死循环等待客户端发送来的数据
        IPCThreadState::self()->joinThreadPool(); // 创建主线程,死循环等待客户端发送来的数据

        return 0;
}

3.5 test_client.cpp代码实现

test_client是binder服务使用者(客户端),实现核心步骤:

  1. 打开驱动
  2. 获得servicemanager
  3. 从servicemanager获得服务
  4. 调用服务的函数
#define LOG_TAG "TestService"
//#define LOG_NDEBUG 0

#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <unistd.h>

#include "IHelloService.h"
#include "IGoodbyeService.h"

using namespace android;

/* ./test_client <hello>
 * ./test_client <hello> <name>
 */
int main(int argc, char **argv)
{
   
   
        int cnt;
        
        if (argc < 2){
   
   
        ALOGI("Usage:\n");
        ALOGI("%s <readfile>\n", argv[0]);
        ALOGI("%s <hello|goodbye>\n", argv[0]);
        ALOGI("%s <hello|goodbye> <name>\n", argv[0]);
        return -1;
        }

        /* getService */
        /* 打开驱动, mmap */
        sp<ProcessState> proc(ProcessState::self());

        /* 获得BpServiceManager (servicemanager的代理类) */
        sp<IServiceManager> sm = defaultServiceManager();

        if (strcmp(argv[1], "hello") == 0)
        {
   
   

                sp<IBinder> binder =
                    sm->getService(String16("hello"));

                if (binder == 0)
                {
   
   
                    ALOGI("can't get hello service\n");
                        return -1;
                }

                /* service肯定是BpHelloServie指针 */
                sp<IHelloService> service =
                    interface_cast<IHelloService>(binder);


                /* 调用Service的函数 */
                if (argc < 3) {
   
   
                        service->sayhello();
                        ALOGI("client call sayhello");
                }
                else {
   
   
                        cnt = service->sayhello_to(argv[2]);
                        ALOGI("client call sayhello_to, cnt = %d", cnt);
                }
        }
        return 0;
}

3.6 编译binder服务的Android.mk文件

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
        BnHelloService.cpp \
        BpHelloService.cpp \
        BnGoodbyeService.cpp \
        BpGoodbyeService.cpp \
        test_server.cpp

LOCAL_SHARED_LIBRARIES := \
        libcutils \
        libutils \
        liblog \
        libbinder 


LOCAL_MODULE:= test_server
LOCAL_32_BIT_ONLY := true

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
        BpHelloService.cpp \
        BpGoodbyeService.cpp \
        test_client.cpp

LOCAL_SHARED_LIBRARIES := \
        libcutils \
        libutils \
        liblog \
        libbinder 


LOCAL_MODULE:= test_client
LOCAL_32_BIT_ONLY := true

include $(BUILD_EXECUTABLE

三、C++编写的Binder服务Demo源码解析

一图简单回顾下【深入内核讲明白Android Binder】系列的文章中讲解的Binder跨进程通信。
在这里插入图片描述

1. test_client.cpp源码解析

1.1 分析如何获得BpServiceManager对象

BpServiceManager是servicemanager服务的代理对象,通过BpServiceManager调用servicemanager提供的服务函数,BpServiceManager源码链接IServiceManager.cpp,BpServiceManager继承关系图如下
在这里插入图片描述
BpServiceManager继承自IServiceManager和BpRefBase,而BpRefBase中的mRemote成员指向BpBinder对象,BpBinder中mHandle成员代表了服务的句柄,通过mHandle可以获取相应的服务。

//继承自IServiceManager和BpRefBase
class BpServiceManager : public BpInterface<IServiceManager>
{
   
   
public:
    BpServiceManager(const sp<IBinder>& impl)
        : BpInterface<IServiceManager>(impl)
    {
   
   
    }

    virtual sp<IBinder> getService(const String16& name) const
    {
   
   
        unsigned n;
        for (n = 0; n < 5; n++){
   
   
            sp<IBinder> svc = checkService(name);
            if (svc != NULL) return svc;
            ALOGI("Waiting for service %s...\n", String8(name).string());
            sleep(1);
        }
        return NULL;
    }

    virtual sp<IBinder> checkService( const String16& name) const
    {
   
   
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        return reply.readStrongBinder();
    }

    virtual status_t addService(const String16& name, const sp<IBinder>& service,
            bool allowIsolated)
    {
   
   
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        data.writeStrongBinder(service);
        data.writeInt32(allowIsolated ? 1 : 0);
        status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
        return err == NO_ERROR ? reply.readExceptionCode() : err;
    }

    virtual Vector<String16> listServices()
    {
   
   
        Vector<String16> res;
        int n = 0;

        for (;;) {
   
   
            Parcel data, reply;
            data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
            data.writeInt32(n++);
            status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
            if (err != NO_ERROR)
                break;
            res.add(reply.readString16());
        }
        return res;
    }
};

IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

}; // namespace android


class BpRefBase : public virtual RefBase
{
   
   
protected:
                            BpRefBase(const sp<IBinder>& o);
    virtual                 ~BpRefBase(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mekeater

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值