Android native层服务例子Bp和Bn

转入android阵地,被各种权限所阻挠,app写个jni各种没有权限,只能开个native服务,本来android的服务,就是基于Binder机制所建立的,如果写个简单的服务 只需继承自Bindler, 实现onsTransact(). 参考现成的工程都是 很复杂的 Bp + Bn 好繁杂的样子,所以这里写了个 Bp+Bn 的最简单demo以观其骨架。  工整,perfect!
功能: 一个服务程序,一个测试服务的程序,测试服务程序调用服务中的 say_hello() ,服务端say_hello

环境: android源码,纯native c++ 程序 (不得不BB一下csdn,用Markdownd编辑一贴代码就炸,用文本编辑贴个图就如下,这个鸟样)

代码主题结构:

201908.24 补充:

==========================补充分割线==============================================================

上图补充说明,  BpTestService代理  fun1(),fun2 调用 remote()->  , 这里是关键,在里面实际上 remote()调用已经进入内核调用了,即本进程调用驱动,自己在这里阻塞,Binder驱动从 parcle中解出参数, (parcle实际上是一个共享内存的实现,所以通过parcle传递的”数据“可以跨进程)。 同时,注册的服务端有一个BInder驱动在不停地轮询查看是否有 人请求,这个时候就会获得参数,然后服务侧的进程 开始启动,调用对应函数,完事把结果 打包到parcle传递给驱动,驱动返回到Bp侧,Bp侧进程拿到结果继续执行。

图解:

至于Binder传递数据的过程,有很多博客介绍,比传统ipc通信少一次拷贝,这里不做讨论。

====================补充分割线====================================================================

文件总览:

代码:

/*
* ITestService.h 
*/
#ifndef ITESTSERVICE_HEAD_H_
#define ITESTSERVICE_HEAD_H_
#define FORBID_CONSTRUCTORS(name) \
    name(const name &); \
    name &operator=(const name &)


#include <binder/IInterface.h>
#include <binder/Parcel.h>


#define TEST_SERVER "TestService_na_tuo_nao_hai" 

using namespace android;

enum {
	TEST_SER_OPENDOOR,
	TEST_SER_SAYHELLO,
};

class ITestService: public IInterface
{
public :
	//申明为 interface 这是一个android源码 /frameworks/native/binder IInterface.h中的一个宏定义
	//注意这里有个坑,用这个宏定义之后一定还要配合另一个宏:
	//IMPLEMENT_META_INTERFACE 在.cpp同时使用,不然编译报错不看宏定义原意真是一脸懵逼
	DECLARE_META_INTERFACE(TestService);

	//以下是服务可以提供的方法调用,全部申明为纯虚函数
	virtual void open_the_door() = 0;
	virtual void say_hello() = 0;
private:
	//这是一个虚类,禁止构造
    FORBID_CONSTRUCTORS(ITestService);
	
};
#endif
/*
* ITestService.cpp
*/
#include "ITestService.h"

#include "BpTestService.h" //??? 为何要这个头文件?  下面这个宏,展开后会实现一个 asInterface()
//该函数内部 new Bp##INTERFACE(obj);  所以一般看到 Bp类的声明定义都放在 I*.cpp 中
//这里如果缺少这个头文件,报错 error: unknown type name 'BpTestService';

IMPLEMENT_META_INTERFACE(TestService, "TestService_na_tuo_nao_hai");

/*
* BpTestService.h
*/
#ifndef BPTESTSERVICE_HEAD__
#define BPTESTSERVICE_HEAD__
#include "ITestService.h"

using namespace android;
//注意, 类名, I* Bn* Pn*  三个前缀不同,后面保持一致,不然宏定义又会各种未定义未实现的错误
class BpTestService : public BpInterface<ITestService>
{

public:
	//一定要实现这个类型的构造函数 理由看下面注释
	BpTestService(const sp<IBinder>& impl)
		   : BpInterface<ITestService>(impl)
	   {
	   }
		   

	//但是你会发现,最终调用,Bn 实例化了对象,而这个Bp没有主动实例化对象????怎么用?
	//其实Bp的实例化对象 也在之前的宏定义 IMPLEMENT_META_INTERFACE 中定义的函数
	//asInterface()中实现实例化对象了 , 所以第一次调用  asInterface() 的时候即 new 了本Bp对象,并且指定调用的
	// 上面的BpTestService(const sp<IBinder>& impl) 带参数的构造函数

	//实现全部的 ITestService提供的方法调用
	//所以到这里,该类已经不是纯虚函数了,可以创建对象了。 Bp 完成
	virtual void open_the_door() ;
	virtual void say_hello() ;
};
#endif
/*
* BpTestService.cpp
*/

#include "BpTestService.h"

void BpTestService::open_the_door() 
{
//远程调用 Bn的OnTranscat()
	Parcel data, reply;
        data.writeInterfaceToken(ITestService::getInterfaceDescriptor());//Bn端配合检查,避免服务调用错误
        remote()->transact(TEST_SER_OPENDOOR, data, &reply);
}

void BpTestService::say_hello()
{//同理
	Parcel data, reply;
        data.writeInterfaceToken(ITestService::getInterfaceDescriptor());//Bn端配合检查,避免服务调用错误
        remote()->transact(TEST_SER_SAYHELLO, data, &reply);
}
/*
* BnTestService.h
*/
#ifndef BNTESTSERVICE_HEAD__
#define BNTESTSERVICE_HEAD__
#include "ITestService.h"

using namespace android;

//注意, 类名, I* Bn* Pn*  三个前缀不同,后面保持一致,不然宏定义又会各种未定义未实现的错误
class BnTestService : public BnInterface<ITestService>
{//该类没有完全 实现 ITestService 中的纯虚函数,继承过来纯虚函数,所以自身还是虚类,不能用来创建对象
//所以后续,还有Real_TestService_Bn来实现

//但是这里有一个 onTransact 被实现了,这个很重要,ITestService 提供的服务调用全部在它里面转调
//所以这类是一个 转换层。

public:
    virtual int onTransact( uint32_t code,
                            const Parcel& data,
                            Parcel* reply,
                            uint32_t flags = 0);
};
#endif
/*
* BnTestService.cpp
*/
#include "BnTestService.h"

int BnTestService::onTransact( uint32_t code,
                            const Parcel& data,
                            Parcel* reply,
                            uint32_t flags )
{//Bn  全部通过改函数转调 到ITestService 公共接口对应的虚函数

	switch(code)
		{
			case TEST_SER_OPENDOOR:
				{
					//这是 基类ITestService 中的纯虚函数,实现在 派生类Real_TestService_Bn中
					//所以这个调用会实际调用到 Real_TestService_Bn::open_the_door();
					
					CHECK_INTERFACE(ITestService, data, reply);//只是个检查,需要Bp端配合
					// data.writeInterfaceToken(ITestService::getInterfaceDescriptor()) 使用
					open_the_door();
					reply->writeInt32(0);
            		                return NO_ERROR;
				}
				break;
			case TEST_SER_SAYHELLO:
				{
					//同理open_the_door 
					CHECK_INTERFACE(ITestService, data, reply);
					say_hello();
					reply->writeInt32(0);
            		                return NO_ERROR;
				}
				break;
			default:
				return BBinder::onTransact(code, data, reply, flags);
		}
	return NO_ERROR;	
}
/*
* Real_TestService_Bn.h
*/
#ifndef REAL_TEST_SERVICE_BN_HEAD__
#define REAL_TEST_SERVICE_BN_HEAD__
#include "BnTestService.h"

//#define TEST_SERVER "TestService_na_tuo_nao_hai" 
class Real_TestService_Bn : public BnTestService
{
public :
	//必备,服务发布
	static void publishService();
	
	//因为基类     ITestService 的宏定义 DECLARE_META_INTERFACE 中把其析构函数申明成虚函数了。
	//避免把本 类的对象指针 向上转型成 基类指针,然后析构的时候,只调用到基类的析构。所以这里派生类
	//的析构函数也申明成 虚函数
	virtual ~Real_TestService_Bn();

	//这里就要全部实现父类的纯虚函数
	virtual void open_the_door() ;
	virtual void say_hello() ;

private:
	//static  ,一个服务就行
	static Real_TestService_Bn* sTestService;
};
#endif
/*
* Real_TestService_Bn.cpp
*/
#include "Real_TestService_Bn.h"

#include <binder/IServiceManager.h>

Real_TestService_Bn* Real_TestService_Bn::sTestService = NULL;
void Real_TestService_Bn::publishService()
{
	if(sTestService == NULL)
	{
		sTestService = new Real_TestService_Bn();
		//注册服务
		defaultServiceManager()->addService(String16(TEST_SERVER),
                        sTestService);
	}
}

Real_TestService_Bn:: ~Real_TestService_Bn()
{

}

void Real_TestService_Bn::open_the_door()
{//服务提供的功能
	printf("open_the_door!! welcom ![%d%s]\n",__LINE__,__FUNCTION__);
}

void Real_TestService_Bn::say_hello()
{//服务提供的功能
	printf("say_hello !! hello!  [%d%s]\n",__LINE__,__FUNCTION__);
}
	

/*
* Main_TestService.cpp
*/
#include "Real_TestService_Bn.h"

#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>

int main(int argc , const char* argv[])
{
	Real_TestService_Bn::publishService();
    ProcessState::self()->startThreadPool();
    IPCThreadState::self()->joinThreadPool(); 
}
/*
* Main_Client.cpp
*/
#include "BpTestService.h"//客户端,只需要Bp代理

#include <binder/IServiceManager.h>

int main(int argc, const char*argv[])
{
	//首先,获取服务. 通过名称确定

	sp<IBinder> binder = defaultServiceManager()->
            getService(String16(TEST_SERVER));

	//这里就搞事情了, 这个 interface_cast 函数就是 之前在   ITestService.cpp 中用 宏IMPLEMENT_META_INTERFACE
	//定义的一个模板函数,其内部会调用                 一次 new Bp##INTERFACE(obj);  (只会创建一个,后续直接获取)
	//这个 构造函数就是 BpTestService 中要求实现的那个构造函数。 
	
	sp<ITestService> Bp_client =  interface_cast<ITestService>(binder);	

	//现在,Bn 和Bp 对象都有了。 本程序拥有 Bp对象,服务程序用于Bn对象。
	//不过 interface_cast 模板函数返回的是 Bn Bp的统一基类 ITestService*

	
	//下面这个调用过程,虚函数的一个经典释义: 以基类之指针指向派生类之对象,调用的是派生类的方法
	// 所以 先调用到Bp中的 对应实现 open_the_door();->
	//然后Bp中用remote() 进行了一波远程调用操作,全部调用到 Bn的 onTransact ->
	//还是虚函数的作用,Bn的onTranscat调用全部到了 BnTestService中实现的 onTranscat()->
	//而这个 BnTestService中的onTranscat(),其实又没做正经事,有把所有case 都一一对应到其派生类 Real_TestService_Bn 中的各个函数

	//这样就从Bp的 open_the_door() -> Bn::onTranscat -> Bn::open_the_door()
	Bp_client->open_the_door();
	Bp_client->say_hello();
	
}
#Android.mk
ROOT_DIR := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PATH := $(ROOT_DIR)

#头文件目录
LOCAL_C_INCLUDES := $(TOP)/frameworks/native/include/gui
LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/input
LOCAL_C_INCLUDES += $(TOP)/frameworks/base/include/

#需要连接的库
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SHARED_LIBRARIES += libutils
LOCAL_SHARED_LIBRARIES += libcutils
LOCAL_SHARED_LIBRARIES += libc
LOCAL_SHARED_LIBRARIES += libbinder

#编译的源文件
LOCAL_SRC_FILES := ITestService.cpp \
 BpTestService.cpp \
 BnTestService.cpp \
 Real_TestService_Bn.cpp \
 Main_TestService.cpp 
 
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -DPLATFORM_ANDROID
#编译输出的模块名称
LOCAL_MODULE:= wang_test_server

#编译为可执行程序
include $(BUILD_EXECUTABLE)
#include $(BUILD_SHARED_LIBRARY)

#==================================================================================
#分割线---------------------------------------------------------------------
#测试服务
#==================================================================================
#ROOT_DIR := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PATH := $(ROOT_DIR)

#头文件目录
LOCAL_C_INCLUDES := $(TOP)/frameworks/native/include/gui
LOCAL_C_INCLUDES += $(TOP)/frameworks/native/include/input
LOCAL_C_INCLUDES += $(TOP)/frameworks/base/include/

#需要连接的库
LOCAL_SHARED_LIBRARIES += liblog
LOCAL_SHARED_LIBRARIES += libutils
LOCAL_SHARED_LIBRARIES += libcutils
LOCAL_SHARED_LIBRARIES += libc
LOCAL_SHARED_LIBRARIES += libbinder

#编译的源文件
#这两处 ITestService.cpp 和BpTestService.cpp 同服务端编译有些重叠
#因为 ITestService.cpp 是 Bp和Bn共用的,都需要,而ITestService.cpp 其中又需要 依赖 BpTestService.cpp
#所以一般 BpTestService.cpp 和 ITestService.cpp 写在一起编译成一个库 ,这里全部单独分开,为了方便看其本质
LOCAL_SRC_FILES := ITestService.cpp \
 BpTestService.cpp \
 Main_Client.cpp 
 
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS += -DPLATFORM_ANDROID
#编译输出的模块名称
LOCAL_MODULE:= wang_test_server_client

#编译为可执行程序
include $(BUILD_EXECUTABLE)
#include $(BUILD_SHARED_LIBRARY)
发布了96 篇原创文章 · 获赞 27 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/u012459903/article/details/99943382
今日推荐