原文地址: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. 隐藏tabbar的属性hidesBottomBarWhenPushed

    项目中有需求是A视图控制器push之后B视图控制器需要隐藏底部的tabbar,在pop之后A视图控制器仍然显示tabbar. 其实不需要在push操作时敲 self.hidesBottomBarWhe ...

  2. DropDownList默认选中

    一.DropDownList默认选中 开始的笨方法: foreach (ListItem item in DropDownList1.Items)                       {    ...

  3. java设计模式--策略模式

    策略模式属于对象的行为模式.其用意是针对一组算法,将每一个算法封装到具有共同接口的独立的类中,从而使得它们可以相互替换.策略模式使得算法可以在不影响到客户端的情况下发生变化. 本文地址:http:// ...

  4. AE影视后期之跳跃音符制作

    制作跳动音符 新建项目 a.打开AE b.新建项目打开一张图片 c.新建合成将图片拖动到左下角的合成面板 新建文本图层. a.找到图层选项里面的新建text b.在里面输入IIIIIIIIIIIIII ...

  5. lable计算行高

    _introduce.text=status.introduce; //设置行间距 NSMutableAttributedString *attributedString = [[NSMutableA ...

  6. 设置Hyper V

    1.打开服务器管理器 2.添加角色和功能 3.安装类型 -> 基于角色或基于功能的安装 4.服务器选择 -> 下一步 5.服务器角色 勾选"Hyper V"

  7. jqGrid 操作一些总结

    1. 手动往grid中添加数据 $("#orgGridId").jqGrid('addRowData',mydata[i].id,mydata[i]); mydata[i].id: ...

  8. ORACLE应用调优:请避免SQL做大量循环逻辑处理

    前阵子遇到一个案例:一个同事说以前一个运行很正常的包,突然间比以前慢了很多,执行时间非常长,晚上的作业调用这个包跑了几个小时也没有跑出数据.于是我在跟踪.优化过程中定位到包中一个存储过程的一段SQL, ...

  9. SQL SERVER Transactional Replication中添加新表如何不初始化整个快照

    在SQL SERVER的复制(Replication)中,有可能出现由于业务需求变更,需要新增一张表或一些表到已有的复制(发布订阅)当中,这种需求应该是很正常,也很常见的.但是在已有的复制(发布订阅) ...

  10. Linq专题之提高编码效率—— 第一篇 Aggregate方法

    我们知道linq是一个很古老的东西,大家也知道,自从用了linq,我们的foreach少了很多,但有一个现实就是我们在实际应用中使用到的却是屈指可数 的几个方法,这个系列我会带领大家看遍linq,好的 ...