热门标签 | 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)


推荐阅读
  • 开发笔记:实验7的文件读写操作
    本文介绍了使用C++的ofstream和ifstream类进行文件读写操作的方法,包括创建文件、写入文件和读取文件的过程。同时还介绍了如何判断文件是否成功打开和关闭文件的方法。通过本文的学习,读者可以了解如何在C++中进行文件读写操作。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 本文介绍了一个题目的解法,通过二分答案来解决问题,但困难在于如何进行检查。文章提供了一种逃逸方式,通过移动最慢的宿管来锁门时跑到更居中的位置,从而使所有合格的寝室都居中。文章还提到可以分开判断两边的情况,并使用前缀和的方式来求出在任意时刻能够到达宿管即将锁门的寝室的人数。最后,文章提到可以改成O(n)的直接枚举来解决问题。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 本文介绍了最长上升子序列问题的一个变种解法,通过记录拐点的位置,将问题拆分为左右两个LIS问题。详细讲解了算法的实现过程,并给出了相应的代码。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文讨论了一个数列求和问题,该数列按照一定规律生成。通过观察数列的规律,我们可以得出求解该问题的算法。具体算法为计算前n项i*f[i]的和,其中f[i]表示数列中有i个数字。根据参考的思路,我们可以将算法的时间复杂度控制在O(n),即计算到5e5即可满足1e9的要求。 ... [详细]
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社区 版权所有