热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Androidnative层服务例子Bp和Bn

转入android阵地,被各种权限所阻挠,app写个jni各种没有权限,只能开个native服务,本来android的服务&

转入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 #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
{public://一定要实现这个类型的构造函数 理由看下面注释BpTestService(const sp& impl): BpInterface(impl){}//但是你会发现,最终调用,Bn 实例化了对象,而这个Bp没有主动实例化对象????怎么用?//其实Bp的实例化对象 也在之前的宏定义 IMPLEMENT_META_INTERFACE 中定义的函数//asInterface()中实现实例化对象了 , 所以第一次调用 asInterface() 的时候即 new 了本Bp对象,并且指定调用的// 上面的BpTestService(const sp& 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 中的纯虚函数,继承过来纯虚函数,所以自身还是虚类,不能用来创建对象
//所以后续,还有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 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
#include
#include 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 int main(int argc, const char*argv[])
{//首先,获取服务. 通过名称确定sp binder = defaultServiceManager()->getService(String16(TEST_SERVER));//这里就搞事情了, 这个 interface_cast 函数就是 之前在 ITestService.cpp 中用 宏IMPLEMENT_META_INTERFACE//定义的一个模板函数,其内部会调用 一次 new Bp##INTERFACE(obj); (只会创建一个,后续直接获取)//这个 构造函数就是 BpTestService 中要求实现的那个构造函数。 sp Bp_client = interface_cast(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)


推荐阅读
  • 本文概述了JNI的原理以及常用方法。JNI提供了一种Java字节码调用C/C++的解决方案,但引用类型不能直接在Native层使用,需要进行类型转化。多维数组(包括二维数组)都是引用类型,需要使用jobjectArray类型来存取其值。此外,由于Java支持函数重载,根据函数名无法找到对应的JNI函数,因此介绍了JNI函数签名信息的解决方案。 ... [详细]
  • 本文讨论了编写可保护的代码的重要性,包括提高代码的可读性、可调试性和直观性。同时介绍了优化代码的方法,如代码格式化、解释函数和提炼函数等。还提到了一些常见的坏代码味道,如不规范的命名、重复代码、过长的函数和参数列表等。最后,介绍了如何处理数据泥团和进行函数重构,以提高代码质量和可维护性。 ... [详细]
  • 近来有一个需求,是需要在androidjava基础库中插入一些log信息,完成这个工作需要的前置条件有编译好的android源码具体android源码如何编译,这 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文讨论了在VMWARE5.1的虚拟服务器Windows Server 2008R2上安装oracle 10g客户端时出现的问题,并提供了解决方法。错误日志显示了异常访问违例,通过分析日志中的问题帧,找到了解决问题的线索。文章详细介绍了解决方法,帮助读者顺利安装oracle 10g客户端。 ... [详细]
  • 本文详细介绍了Android中的坐标系以及与View相关的方法。首先介绍了Android坐标系和视图坐标系的概念,并通过图示进行了解释。接着提到了View的大小可以超过手机屏幕,并且只有在手机屏幕内才能看到。最后,作者表示将在后续文章中继续探讨与View相关的内容。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • Question该提问来源于开源项目:react-native-device-info/react-native-device-info ... [详细]
  • mysqldinitializeconsole失败_mysql03误删除了所有用户解决办法
    误删除了所有用户解决办法第一种方法(企业常用)1.将数据库down掉[rootdb03mysql]#etcinit.dmysqldstopShuttingdownMySQL..SU ... [详细]
  • 嗨,我想用多处理来加速我的代码。但是,apply_async对我不起作用。我试着做一个简单的例子,比如:frommultip ... [详细]
author-avatar
v88v的秋天
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有