05.Binder系统:第7课第1节_Binder系统_c++实现_编写程序

在前面是小节中,讲解了C程序的使用示例,又深入的分析了binder驱动程序。接下来我们讲解怎么使用C++去使用这个binder服务,使用C++的目的,就是为了能够去复用别人的代码,让我们的程序更加的简单。

在这个课时的第一个小节,我们将使用C++编写一个服务,并且使用这个服务。在这个之前,我们先回顾一下之前有C程序写的代码,下面是回顾知识的简单框图:

我们知道binderi系统涉及三个方面,service_manager,test_server.c以及test_client.c,其中:
1.test_server提供服务:sayhello(),sayhello_to()
2.test_client使用服务:sayhello(),sayhello_to()
3.service_manager管理服务:

test_server会通过addService向service_manager注册服务,test_client通过getService获取服务。在test_client中也存在与test_server提供服务的同名函数,如sayhello(),sayhello_to()。但是他们两者的实现几乎是完全不一样的:
test_client中sayhello()或sayhello_to():构造数据,发送数据。
test_server中sayhello()或sayhello_to():一个循环,接收数据,解析数据,调用sayhello()或sayhello_to()函数
在这里插入图片描述
这种程序结构的编写是非常的差的,因为都集中在一个.c文件之中,我们看看能做哪些改进。

程序结构改进

下面是一个改进之后的框图,我们将围绕着这个框图进行讲解:
在这里插入图片描述
我们发现server与client都会调用sayhello(),sayhello_to()。我们可以他sayhello(),sayhello_to()写在一个头文件之中IHelloService.h,其中声明sayhello(),sayhello_to()两个函数。在server与client端我们分别去实现这两个函数:
server端:在文件BnHelloService.c(B代表binder,n代表native本地实现)实现sayhello(),sayhello_to()函数,并且包含头文件"IHelloService.h"。server在接收到client的数据,假设调用onTransact进行解析,根据解析得到的信息调用对应的函数,那么我们还需要一个主循环,让这个循环不停的解析数据,这个主循环在test_sevice.c中编写,其中存在man函数,mian函数包括了一个while循环,这个循环主要接受数据,然后代用onTransaction。
client端:在文件BpHelloService.c(B代表binder,p代表proxy,表示代表的意思),其中也包含头文件IHelloService.h,其中也要实现sayhello(),sayhello_to()两个函数(构造,发送数据)。这边也包含了test_client.c,其中照样存在main函数,调用sayhello()或者sayhello_to()函数。

server端与client端的接收,和发送数据,共用bind.c这个文件.或者一个库。下面我们开始编写C++程序。

c++程序编写

参考文件:
frameworks\av\include\media\IMediaPlayerService.h     (IMediaPlayerService,BnMediaPlayerService)
frameworks\av\media\libmedia\IMediaPlayerService.cpp                      (BpMediaPlayerService)
frameworks\av\media\libmediaplayerservice\MediaPlayerService.h
frameworks\av\media\libmediaplayerservice\MediaPlayerService.cpp
frameworks\av\media\mediaserver\Main_mediaserver.cpp   (server, addService)

首先创建文件夹APP_004_Binder_CPP_App,在其中创建IHelloService.h,BpHelloService.cpp,BnHelloService.cpp,test_client.cpp,test_server.cpp。

IHelloService.h

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>
#include <system/audio.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.cpp


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

#include "IHelloService.h"

#define LOG_TAG "HelloService"


namespace android {

status_t BnHelloService::onTransact( uint32_t code,
                                const Parcel& data,
                                Parcel* reply,
                                uint32_t flags = 0)
{
	/* 解析数据,调用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;
}

}

BpHelloService.cpp


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

#include "IHelloService.h"

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

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>


using namespace android;

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

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>


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

梳理流程

编写以上文件后,我们来梳理一下binder服务c++实现的过程,下面是一个流程图,围绕着该流程图讲解
在这里插入图片描述
1.定义接头类IHelloService,在其中声明sayhello()与sayhello_to()函数。
2.server端实现一个BnHelloService,在其中实现接口中的函数,以及一个onTransact函数
3.client端实现BpHelloService,同样实现接口中的函数,函数内容为构建一些数据,然后通过binder发送。其目的是为了调用服务端的函数。
4.实现server:在main函数中,通过addservice()添加服务,然后添加一个while()循环,循环读取,解析数据,然后调用函数。
5.实现client:在main函数中,通过svr=getService()获取服务,然后调用其中svr.sayhello或者svr.sayhello_to函数。

该小节我们只是编写写了代码,但是没有调试,下小节我们去调试代码(实际以上代码,都为已经调试过得代码呢)。

猜你喜欢

转载自blog.csdn.net/weixin_43013761/article/details/89022383