原文地址: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. IOS开发基础知识--碎片9

    1:两种方法删除NSUserDefaults所有记录 //方法一 NSString *appDomain = [[NSBundle mainBundle] bundleIdentifier]; [[N ...

  2. n个元素的入栈顺序有多少种出栈顺序?

    问题:w1.w2.w3.w4.w5,5个元素将会按顺序入栈,求出栈顺序有多少种情况. 先写一下结论方便记忆: 1个元素:1种 2个元素:2种 3个元素:5种 4个元素:14种 5个元素:42种 简单的 ...

  3. android studio 导入项目太慢(卡条)

    原因: 下载的项目和你当前已经下载的grandle 不一致, 导致导入的时候到网上下载相应的版本. 最简单的办法,修改你这个需要导入的项目. 需要修改的文件: 1. xxx-project/.idea ...

  4. 基于ntp的多服务器时间同步脚本

    server服务器每1个小时更新一次时间,server服务器旗下同步服务器每5秒钟同步一次时间,同步服务器与外网不做交互,由server服务器进行同步时间.所以保证每一台同步服务器时间一致. #vi ...

  5. php new self()和new static()

    class A { public static function get_self() { return new self(); } public static function get_static ...

  6. [css]我要用css画幅画(三)

    接着之前的[css]我要用css画幅画(二), 今天,我画了一个小人,他的名字暂时叫作小明. 以下只列出本次修改增加的内容 html如下: <div class="human left ...

  7. RedHat 4下无resize2fs命令

    在Red Hat Enterprise Linux AS release 4上进行LVM扩展分区时,发现RedHat 4下没有resize2fs,不过可以用ext2online替换resize2fs. ...

  8. Ant :DataType

    DataType patternset fileset selector filelist path regexp Ant datatype Ant中,除了Property可以做为Task执行时使用的 ...

  9. EF如何操作内存中的数据以及加载相关联表的数据:延迟加载、贪婪加载、显示加载

    之前的EF Code First系列讲了那么多如何配置实体和数据库表的关系,显然配置只是辅助,使用EF操作数据库才是每天开发中都需要用的,这个系列讲讲如何使用EF操作数据库.老版本的EF主要是通过Ob ...

  10. Kafka简介

    Kafka简介 转载请注明出处:http://www.cnblogs.com/BYRans/ Apache Kafka发源于LinkedIn,于2011年成为Apache的孵化项目,随后于2012年成 ...