手动添加c++ binder服务

1.定义一个接口类IHelloService.h

功能:定义业务接口sayhello和sayhello_to

IHelloService.h

/* ²Î¿¼: 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     0
#define HELLO_SVR_CMD_SAYHELLO_TO  1


namespace android {

class IHelloService: public IInterface
{
public:
    DECLARE_META_INTERFACE(HelloService);
	virtual void sayhello(void) = 0;
	virtual int sayhello_to(const char *name) = 0;
};

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);
};
}

#endif

BnHelloService是继承public BnInterface,其中BnInterface是一个模板类,

template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;

protected:
    virtual IBinder*            onAsBinder();
};

所以BnHelloService是继承IHelloService和BBinder两个基类。

2.binder的native服务实现: BnHelloService.cpp

功能:实现业务接口sayhello和sayhello_to两个方法,以及onTransact方法。

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

#define LOG_TAG "HelloService"

#include "IHelloService.h"


namespace android {

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();
            return NO_ERROR;
        } break;
		
        case HELLO_SVR_CMD_SAYHELLO_TO: {

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

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

			/* 把返回值写入reply传回去 */
			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.binder的proxy实现:BpHelloService.cpp

功能:调用sayhello和sayhello_to两个方法

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

#include "IHelloService.h"

namespace android {

class BpHelloService: public BpInterface<IHelloService>
{
public:
    BpHelloService(const sp<IBinder>& impl)
        : BpInterface<IHelloService>(impl)
    {
    }

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

        Parcel data, reply;
        data.writeInt32(0);

        remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
	}
	
	int sayhello_to(const char *name)
	{
		/* 构造/发送数据 */
        Parcel data, reply;

        data.writeInt32(0);
        data.writeString16(String16(name));

        remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);

		return reply.readInt32();
	}

};

IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService");

}

BpHelloService:继承自public BpInterface,BpInterface的模板类如下:

template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
                                BpInterface(const sp<IBinder>& remote);

protected:
    virtual IBinder*            onAsBinder();
};

所以BpHelloService是继承IHelloService和BpRefBase两个基类。

test_server.cpp

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

#define LOG_TAG "HelloService"
//#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 "IHelloService.h"


using namespace android;

int main(void)
{
	/* addService */

	/* while(1){ read data, 解析数据, 调用服务函数 } */

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

	/* 获得BpServiceManager */
	sp<IServiceManager> sm = defaultServiceManager();

	sm->addService(String16("hello"), new BnHelloService());

	/* 循环体 */
	ProcessState::self()->startThreadPool();
	IPCThreadState::self()->joinThreadPool();

	return 0;
}

test_client.cpp

#define LOG_TAG "HelloService"
//#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 "IHelloService.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 <hello|goodbye>\n", argv[0]);
        ALOGI("%s <hello|goodbye> <name>\n", argv[0]);
        return -1;
	}

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

	/* 获得BpServiceManager */
	sp<IServiceManager> sm = defaultServiceManager();

    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;
}

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
	BnHelloService.cpp \
	BpHelloService.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 \
	test_client.cpp

LOCAL_SHARED_LIBRARIES := \
	libcutils \
	libutils \
	liblog \
	libbinder 


LOCAL_MODULE:= test_client
LOCAL_32_BIT_ONLY := true

include $(BUILD_EXECUTABLE)

总结

服务端:
让我们用图梳理一下 (箭头代表继承关系)
在这里插入图片描述
归纳一下,

  • BBinder 实现了大部分的IBinder 接口,除了onTransact() 和 queryLocalInterface(), getInterfaceDescriptor();
  • BnInterface 实现了IBinder的queryLocalInterface()和getInterfaceDescriptor(), 但是其必须借助实际的接口类。
  • BnMediaPlayer只是定义并实现了onTransact()。

客户端:
BpRefBase 里有IBinder 成员变量,看来在客户端,没有一个类同时继承IBinder 和 IInterface, 但是有一个类继承了其一,但包含了另外一个,这种在设计模式里成为组合(Composition).
客户端中的BpRefBase类中包含IBinder类:在这里插入图片描述
可以通过interface_cast 直接把IBinder 转换成了 IMediaPlayer

总结:
flat_binder_object结构体如下:

struct flat_binder_object {
    /* 8 bytes for large_flat_header. */
    unsigned long type;
    unsigned long flags;

    /* 8 bytes of data. */
    union {
        void *binder; /* local object */
        signed long handle; /* remote object */
    };

    /* extra data associated with local object */
    void *cookie;
};

addService时,

  • 1.会为每个服务构造一个flat_binder_object 结构体,每个服务的flat_binder_object 中的binder(binder = reinterpret_cast<uintptr_t>(local->getWeakRefs()))和cookie都不同。
  • 2.调用ioctl发送数据,数据中包含flat_binder_object 结构体,服务的名字(即media.player),发送的目的地(handle = 0,即servicemanager)。
  • 3.驱动程序对每一个flat_binder_object构造一个binder_node节点。
  • 4.驱动程序根据handle=0找到sm,把这些数据发送给sm驱动层,并且创建binder_ref结构体,其中的binder_node元素指向上述的binder_node节点。
  • 5.sm的进程还会创建一个svlist的链表,里面挂载svcinfo结构体,含有name和handle值,handle即为驱动程序中binder_ref的desc值。
    struct svcinfo
    {
    struct svcinfo *next;
    uint32_t handle;

    uint16_t name[0];
    };
struct binder_node {
    ...
    struct binder_work work;
    union {
        struct rb_node rb_node;
        struct hlist_node dead_node;
    };
    struct binder_proc *proc;
    struct hlist_head refs;
    int internal_strong_refs;
    int local_weak_refs;
    int local_strong_refs;
    binder_uintptr_t ptr;//来自flat_binder_object中的binder
    binder_uintptr_t cookie;//来自flat_binder_object中的cookie
    ...
};
struct binder_ref {
    /* Lookups needed: */
    /*   node + proc => ref (transaction) */
    /*   desc + proc => ref (transaction, inc/dec ref) */
    /*   node => refs + procs (proc exit) */
    int debug_id;
    struct rb_node rb_node_desc;
    struct rb_node rb_node_node;
    struct hlist_node node_entry;
    struct binder_proc *proc;
    struct binder_node *node;
    uint32_t desc;
    int strong;
    int weak;
    struct binder_ref_death *death;
};

getService时

  • 1.Client想去获得服务,并且传输数据,数据=名称+“目的(handle = 0)”.
  • 2.调用ioctl发送数据.
  • 3.驱动程序根据handle=0找到sm,把数据给sm.
  • 4.sm从svlist找到对应项,比如根据名称(media.player)找到handle=1。
  • 5.sm通过ioctl返回数据,数据也是flat_binder_object,其中的handle=1
  • 6.通过5,驱动发现数据中有flat_binder_object结构体,且type为引用,binder_ref里面找到对应项(传入的handle值等于binder_ref的desc),再找到binder_node,最后为client的内核空间也建立binder_ref链表。

client怎么使用服务

  • 1.构造数据,里面含有code(通过code值决定调用哪个函数)、参数、目的(handle=1)
  • 2.使用ioctl发数据。
  • 3.驱动根据handle=1,找到binder_ref,根据binder_ref找到binder_node,根据binder_node中的binder_proc找到server进程。最后把数据传给server,并且在数据中设置ptr和cookie等于binder_node的ptr和cookie。server根据ptr和cookie确定找到哪个服务,根据code调用相应的函数。

综上:client中最核心的数据是handle,server最核心的数据是ptr/cookie。

在这里插入图片描述

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值