转入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
#include
};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
{public://一定要实现这个类型的构造函数 理由看下面注释BpTestService(const sp
};
#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 中的纯虚函数,继承过来纯虚函数,所以自身还是虚类,不能用来创建对象
//所以后续,还有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
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
#include
#include
{Real_TestService_Bn::publishService();ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();
}
/*
* Main_Client.cpp
*/
#include "BpTestService.h"//客户端,只需要Bp代理#include
{//首先,获取服务. 通过名称确定sp
#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)