原文地址:http://blog.csdn.net/zhx6044/article/details/47342227

Native Service 其实就是一个 linux 守护进程,提供一些服务,不过由于 android 的进程间通讯使用了 Binder 机制,那么我们就需要按照 android 的规则来实现我们的 Native Service。

客户端在请求 service 的服务时使用了一个具有相同接口的 Proxy 类。native service 这具体实现这个接口,所以 android 提供了 IInterface 类,其是”base class for Binder interfaces”,所以我们的 IZxTask 类继承它:

class IZxTask : public IInterface {
public:
enum { TASK_GET_PID = IBinder::FIRST_CALL_TRANSACTION,
}; virtual int getPid() = 0; DECLARE_META_INTERFACE(ZxTask);
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
IMPLEMENT_META_INTERFACE(ZxTask, "android.hardware.IZxTask");
  • 1

必须以 I 开头,因为后面会用到一些宏,比如 DECLARE_META_INTERFACE,I 开头是写到宏里面的,所以我们只要传入了 ZxTask 就行了。我们的 Native Service 提供一个接口就是返回 Service 的进程号。 

下面我们就需要开始分化实现,一个是客户端,一个是 native service。 

先来看代理类

class BpZxTask : public BpInterface<IZxTask> {
public:
BpZxTask(const sp<IBinder>& binder)
: BpInterface<IZxTask>(binder)
{
} virtual int getPid()
{
Parcel data, reply;
data.writeInterfaceToken(IZxTask::getInterfaceDescriptor());
remote()->transact(TASK_GET_PID, data, &reply);
return reply.readInt32();
}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

BpInterface 模板类,其中的 p 就是代理的意思。其以我们前面定义的 Interface 为模板参数。 

BpInterface 声明如下:

template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
BpInterface(const sp<IBinder>& remote); protected:
virtual IBinder* onAsBinder();
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

我们的 BpZxTask 需要实现我们定义的接口类中的接口函数。在实现中,我们是客户端,我们需要向 native service 提申请,我们使用 remote 获得关联 service 的 IBinder 对象,然后通过 transact 提交,通过 reply 获得返回值。

下面来看 BnInterface 的实现。

class BnZxTask : public BnInterface<IZxTask> {
public:
virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
};
  • 1
  • 2
  • 3
  • 4
  • 5
status_t BnZxTask::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{ switch (code) {
case TASK_GET_PID: {
CHECK_INTERFACE(IZxTask, data, reply);
int32_t pid = getPid();
reply->writeInt32(pid);
return NO_ERROR; } break; default:
return BBinder::onTransact(code, data, reply, flags);
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

我们在 bpinterface 的 transact 调用会回调 bninterface 的 onTransact 来处理,我们根据 code 参数来进行请求的区分。

BnInterface 类模板其声明如下:

 template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
virtual sp<IInterface>
queryLocalInterface(const String16& _descriptor);
virtual const String16& getInterfaceDescriptor() const; protected:
virtual IBinder* onAsBinder();
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

其一个父类是继承自 IInterface 的接口类,一个是代表 Binder service 服务端的 BBinder 类。

下面来实现 native service。

class ZxTaskService : public BinderService<ZxTaskService>, public BnZxTask {
public:
virtual int getPid();
static char const* getServiceName() { return "ZxTask"; }
friend class BinderService<ZxTaskService>;
}; int ZxTaskService::getPid()
{
return getpid();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

我们在此实现服务提供的 getPid 接口就 ok,BinderService 模板为我们启动一个 Service 实现了逻辑封装。 

BinderService 实现如下:

template<typename SERVICE>
class BinderService
{
public:
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
} static void publishAndJoinThreadPool(bool allowIsolated = false) {
publish(allowIsolated);
joinThreadPool();
} static void instantiate() { publish(); } static status_t shutdown() { return NO_ERROR; } private:
static void joinThreadPool() {
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
}
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

其要求模板参数实现getServiceName方法,publishpublishAndJoinThreadPool函数实现了该
service 添加到 SM 的逻辑,publish 只是 add,而publishAndJoinThreadPool会启动该
service。

这里我们就完成了 native service 的开发,我们将其编成库。 

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
ZxTask.cpp \
ZxTaskService.cpp LOCAL_C_INCLUDES := \
system/core/include \
frameworks/native/include LOCAL_SHARED_LIBRARIES := \
libbinder \
libutils \ LOCAL_MODULE:= libzxtask include $(BUILD_SHARED_LIBRARY)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

我们写一个 service 的可执行程序。 

main.cpp

#include "service/ZxTaskService.h"

int main()
{
/* code */
android::ZxTaskService::publishAndJoinThreadPool();
return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
main.cpp \ LOCAL_C_INCLUDES := frameworks/base/zxTask LOCAL_MODULE:= zxtaskservice LOCAL_SHARED_LIBRARIES := libzxtask libutils libbinder include $(BUILD_EXECUTABLE)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

写一个测试客户端

main.cpp

#include "service/ZxTask.h"
#include <binder/IServiceManager.h>
#include <unistd.h>
#include <stdio.h> int main()
{
using namespace android;
sp<IServiceManager> sm =defaultServiceManager();
printf("%s\n", "get serviceManager");
sp<IBinder> binder =sm->getService(String16("ZxTask"));
sp<IZxTask> mTask =interface_cast<IZxTask>(binder);
printf("ZxTask Service pid %d, client pid:%d",mTask->getPid(), getpid()); return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Android.mk

LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES := \
main.cpp \ LOCAL_C_INCLUDES := frameworks/base/zxTask LOCAL_MODULE:= zxtaskclient LOCAL_SHARED_LIBRARIES := libzxtask libutils libbinder include $(BUILD_EXECUTABLE)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

其中用到了interface_cast

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
  • 1
  • 2
  • 3
  • 4
  • 5

其使用了 asInterface 函数,而这个函数就是我们在 IZxTask 里面使用DECLARE_META_INTERFACE声明的。

#define DECLARE_META_INTERFACE(INTERFACE)                           \
static const android::String16 descriptor; \
static android::sp<I##INTERFACE> asInterface( \
const android::sp<android::IBinder>& obj); \
virtual const android::String16& getInterfaceDescriptor() const;\
I##INTERFACE(); \
virtual ~I##INTERFACE();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

其声明了一个描述的类属性,我们使用的asInterface函数。 

看下IMPLEMENT_META_INTERFACE宏。

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)              \
const android::String16 I##INTERFACE::descriptor(NAME); \
const android::String16& \
I##INTERFACE::getInterfaceDescriptor() const { \
return I##INTERFACE::descriptor; \
} \
android::sp<I##INTERFACE> I##INTERFACE::asInterface( \
const android::sp<android::IBinder>& obj) \
{ \
android::sp<I##INTERFACE> intr; \
if (obj != NULL) { \
intr = static_cast<I##INTERFACE*>( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { } \
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

主要看asInterface的实现。其会调用 IBinder 的 queryLocalInterface
查询我们的接口对象,这里使用了基类指针,如果没有就 new 出来。我们的 BpZxTask 只有在这个函数中使用,这也是为什么我在实现时,指示全部把它放在了 cpp 文件中。

intr = new Bp##INTERFACE(obj); 
  • 1

这一句表明我们的 Proxy 类一定以 Bp 开头且 IBinder 对象作为构造的参数传入,实现了 proxy 和 IBinder 对象的绑定。

  sp<IBinder> binder =sm->getService(String16("ZxTask"));  
  • 1

根据 service 名获得这个 service 的 IBinder 对象,使用interface_cast实现了客户端的
Proxy 和 service 的 IBinder 的绑定,然后我们在 getPid 中就可以调用 IBinder 的 transact 函数,这样就和 remote 通讯上,回调到 native service 的 onTransact 的接口,然后处理了将结果返回,这样就实现了 client 和 service 的通讯。

运行如下图:

代码例子:https://git.oschina.net/zhouX/servicedemo.git


添加native service的更多相关文章

  1. 王家林的81门一站式云计算分布式大数据&移动互联网解决方案课程第14门课程:Android软硬整合设计与框架揭秘: HAL&Framework &Native Service &App&HTML5架构设计与实战开发

    掌握Android从底层开发到框架整合技术到上层App开发及HTML5的全部技术: 一次彻底的Android架构.思想和实战技术的洗礼: 彻底掌握Andorid HAL.Android Runtime ...

  2. 你会在C#的类库中添加web service引用吗?

    本文并不是什么高深的文章,只是VS2008应用中的一小部分,但小部分你不一定会,要不你试试: 本人对于分布式开发应用的并不多,这次正好有一个项目要应用web service,我的开发环境是vs2008 ...

  3. 11、四大组件之二-Service高级(二)Native Service

    一.Service的分类 1.1>Android Service 使用Java编写在JVM中运行的服务 1.2>Native Service 使用C/C++完成的服务,一般在系统开始时完成 ...

  4. Binder机制,从Java到C (7. Native Service)

    1.什么是NativeService Native Service,是通过C或C++代码写出來,提供给Java进行远程调用的RemoteService.向Android开机就启动的surfacefli ...

  5. C#:添加web service引用

    VS2012里是这样添加web service引用的:

  6. VS2010下创建WEBSERVICE,第二天 ----你会在C#的类库中添加web service引用吗?

    本文并不是什么高深的文章,只是VS2008应用中的一小部分,但小部分你不一定会,要不你试试: 本人对于分布式开发应用的并不多,这次正好有一个项目要应用web service,我的开发环境是vs2008 ...

  7. xxx.service is not a native service, redirecting to /sbin/chkconfig.

    centos7编译安装的程序无法用systemctl 启动 [root@nagios-server check_commands]# systemctl enable npcd.service npc ...

  8. 从零開始怎么写android native service?

    从零開始怎么写android native service Android service对于从事android开发的人都不是一个陌生的东西,非常多人可能会认为服务非常easy. 服务是简单,由于复杂 ...

  9. NRF52840 添加 led service

    记录NRF52840 添加LED service的流程,以及遇到的问题. 由于SDK中已经有了led service的.c和.h文件,因此只需要添加文件,并且调用相关函数即可. 注:编译调试环境为ke ...

随机推荐

  1. SharePoint 2013 网站搜索规则的使用示例

    前言 SharePoint 2013搜索中,有一个非常好用的细化搜索结果的功能,就是“查询规则”.可以通过对于某些特定查询时,起到细化显示结果的作用.下面,我们简单的介绍一下该功能的使用和效果. 1. ...

  2. iOS UIPageViewController

    UIPageViewController是App中常用的控制器.它提供了一种分页效果来显示其childController的View.用户可以通过手势像翻书一样切换页面.切换页面时看起来是连续的,但静 ...

  3. IOS开发基础知识--碎片45

    1:iOS SEL的简单总结 SEL就是对方法的一种包装.包装的SEL类型数据它对应相应的方法地址,找到方法地址就可以调用方法 a.方法的存储位置 在内存中每个类的方法都存储在类对象中 每个方法都有一 ...

  4. iOS百度地图简单使用

    本文介绍三种接口: 1.基础地图2.POI检索3.定位 首先是配置环境,有两种方法,方法在官方教程里都有,不再多说 1.使用CocoaPods自动配置[这个方法特别好,因为当你使用CocoaPods配 ...

  5. (二)Maven的安装与环境配置

    想要安装 Apache Maven在Windows 系统上, 需要下载 Maven 的 zip 文件,并将其解压到你想安装的目录,并配置 Windows 环境变量. 所需工具 : 1.JDK 2.Ma ...

  6. 报文格式:xml 、定长报文、变长报文

    目前接触到的报文格式有三种:xml .定长报文.变长报文 . 此处只做简单介绍,日后应该会深入学习到三者之间如何解析,再继续更新.——2016.9.23 XML XML 被设计用来传输和存储数据. H ...

  7. Crontab定时任务配置

    CRONTAB概念/介绍 crontab命令用于设置周期性被执行的指令.该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行. cron 系统调度进程. 可以使用它在 ...

  8. Linux服务器宕机案例一则

    案例环境 操作系统 :Oracle Linux Server release 5.7 64bit 虚拟机 硬件配置 : 物理机型号为DELL R720 资源配置 :RAM 8G Intel(R) Xe ...

  9. C# 中的var关键字

    var 是3.5新出的一个定义变量的类型 其实也就是弱化类型的定义 VAR可代替任何类型 编译器会根据上下文来判断你到底是想用什么类型的 至于什么情况下用到VAR 我想就是你无法确定自己将用的是什么类 ...

  10. 在cmd和terminal怎么粘贴?

    在osx, linux的terminal 以及windows的 cmd实现粘贴是coder经常要做的事,鼠标右键,下拉菜单中单击粘贴paste.但是这显得笨拙,及其不快捷.但是正常使用的command ...