从零開始怎么写android native service

Android service对于从事android开发的人都不是一个陌生的东西,非常多人可能会认为服务非常easy。

服务是简单,由于复杂的别人做了,所以才会认为简单。我们先梳理一下服务的分类,首先有本地服务跟系统服务的区分。而在APP里写的服务大多就成为Java服务或者应用服务。

/****************************************************************************************************/
声明:本博内容均由http://blog.csdn.net/edsam49原创,转载请注明出处。谢谢!
/*****************************************************************************************************/

做APP的人写个应用服务相对来说是最简单的。由于extends了一个service后几个简单的接口就能够跑起来了。写完这样的服务可能也仅仅是对服务一知半解,由于值钱的service类Google的人已经帮你写好了,这是你的福气为你带来了便利,当然也可能会麻痹你:),可是做APP的人会有能解决这个问题是首要任务了,有时间还是对它了解更清楚点比較好,在此不再讨论这个。

做设备做系统的人,常常可能会去写系统服务,也就是framework以下的服务,systemserver里面注冊的服务。写这样的服务一般来说比較少。仅仅有做设备系统的才会这样干,才有机会有完毕的系统代码,能够在里面自由遨游。笔者三年前写过一个,能够看看【自己动手从零開始写一个完整的android Service】http://blog.csdn.net/edsam49/article/details/8163639

那剩下的一个是本地服务。也就是native service,这样的服务我们了解的系统里面多媒体、audio system都是写成了本地服务,这样写的优点就是运行的效率更高一点,由于C/C++先天性就比JAVA的运行效率要高一点。笔者就是由于长期主要从事的都是底层开发的。我们有时有这么一种需求,又要运行效率高。又要好移植。主要是考虑推广写东西给广大客户,那么我就写一个本地服务,这样是最独立的了。效率也最高了。那一个本地服务究竟怎么写呢?大多数的人写过的服务以java服务居多。真正写本地服务的不多,本地服务相对来说又是更复杂一点的。

因此决定从零開始自己动手写一个本地service。以下就大概描写叙述一下过程。

本地服务有四大块,服务接口(IService),服务代理(也就是BpService),服务stub(也就是BnService)。服务实体(Service)。以下笔者的实例就以demoNativeService来开启,力求简单。里面就写了两个接口;

首先定义好服务接口IdemoNativeService。IdemoNativeService服务接口的父类是IInterface,在里面主要是要声明一下接口。在DECLARE_META_INTERFACE(demoNativeService)。代码例如以下:

class IdemoNativeService : public IInterface
{
public:
enum {
CONNECT = IBinder::FIRST_CALL_TRANSACTION,
PRINTSTRING_CMD,
}; public:
DECLARE_META_INTERFACE(demoNativeService);
virtual status_t connect(int pid,int previewhw,int intf,int fmt,int chan) = 0;
virtual status_t printString(const char *str) = 0; };

当然定义好了IdemoNativeService的头文件,就须要去实操了。先来搞定BpdemoNativeService,它的父类是BpInterface<IdemoNativeService>,这里面主要是涉及数据的跨进程用到的parcel。读啊。写啊,按套路来,也不难,也有AIDL工具能够使用。帮你转出来,再略微改动一下就能够了,里面有一个非常重要的remote,这个和remote就是幕后功臣啊。它保存了服务实例的对象啊。它是来之BpRefBase的一个成员,生成服务的时候。会得到赋值,定义完了以后,非常重要的一个程序就是要IMPLEMENT_META_INTERFACE(demoNativeService,"android.hardware.IdemoNativeService");这个宏是非常重要的,跟前面那个DECLARE是相应的。前面声明,后面实现,当然我们带的參数跟的名字是必须一致的。这样才干正常沟通嘛!

class BpdemoNativeService: public BpInterface<IdemoNativeService>
{
public:
BpdemoNativeService(const sp<IBinder>& impl)
: BpInterface<IdemoNativeService>(impl)
{
} virtual status_t connect(int pid,int previewhw,int intf,int fmt,int chan)
{
Parcel data, reply;
data.writeInterfaceToken(IdemoNativeService::getInterfaceDescriptor());
data.writeInt32(pid);
data.writeInt32(previewhw);
data.writeInt32(intf);
data.writeInt32(fmt);
data.writeInt32(chan);
remote()->transact(IdemoNativeService::CONNECT, data, &reply);
return reply.readInt32();
} virtual status_t printString(const char *str)
{
Parcel data, reply;
data.writeInterfaceToken(IdemoNativeService::getInterfaceDescriptor());
data.writeCString(str);
remote()->transact(IdemoNativeService::PRINTSTRING_CMD, data, &reply);
return reply.readInt32();
}
}; IMPLEMENT_META_INTERFACE(demoNativeService, "android.hardware.IdemoNativeService");//android.hardware.IdemoNativeService ds.demonativeservice

接着须要写服务stub了,BndemoNativeService的父类是BnInterface<IdemoNativeService>。有没有发现BndemoNativeService跟BpdemoNativeService。都会基于接口类IdemoNativeService,这样沟通起来的接口就唯一了,就具备了对话的可能。

class BndemoNativeService: public BnInterface<IdemoNativeService>
{
public:
virtual status_t onTransact( uint32_t code,const Parcel& data,Parcel* reply,uint32_t flags = 0);
};
status_t BndemoNativeService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code)
{
/*case CONNECT: {
CHECK_INTERFACE(IdemoNativeService, data, reply);
int pid = data.readInt32();
int previewhw = data.readInt32();
int intf = data.readInt32();
int fmt = data.readInt32();
int chan = data.readInt32();
reply->writeInt32(connect(pid,previewhw,intf,fmt,chan));
return NO_ERROR;
}break;
case PRINTSTRING_CMD: {
CHECK_INTERFACE(IdemoNativeService, data, reply);
const char *str;
str = data.readCString();
reply->writeInt32(printString(str));
return NO_ERROR;
}break;*/ default:
return BBinder::onTransact(code, data, reply, flags);
}
}

到这就轮到了大块头service实体demoNativeService了。demoNativeService是基于BndemoNativeService,在demoNativeService里面定义了一个instantiate()接口用于加入service到servicemanager里面去,注意demoNativeService()跟析构函数~demoNativeService()须要写成private的,免得别人能够new出对象来。在里面重写了onTransact。一旦BpdemoNativeService有风吹草动,就会联动到BndemoNativeService,由于服务实体重写了onTransact。所以实际就会先运行到demoNativeService::onTransact这里来,在这里面处理不了,能够再转给BpdemoNativeService的onTransact或者直接到BBinder的onTransact;

void demoNativeService::instantiate() {
android::defaultServiceManager()->addService(
IdemoNativeService::descriptor, new demoNativeService());
} demoNativeService::demoNativeService()
{
ALOGE("demoNativeService created");
mOpened = 1;
} demoNativeService::~demoNativeService()
{
ALOGE("demoNativeService destroyed");
} status_t demoNativeService::connect(int pid,int previewhw,int intf,int fmt,int chan){ ALOGD("demoNativeService connect:%d, %d, %d, %d, %d", pid, previewhw, intf, fmt, chan);
return 88; } status_t demoNativeService::printString(const char *str){
ALOGD("demoNativeService printString:%s", str);
return 66;
} #if 1
status_t demoNativeService::onTransact(uint32_t code,
const android::Parcel &data,
android::Parcel *reply,
uint32_t flags)
{
ALOGD("OnTransact(%u,%u)", code, flags); switch(code) {
case CONNECT: {
CHECK_INTERFACE(IdemoNativeService, data, reply);
int pid = data.readInt32();
int previewhw = data.readInt32();
int intf = data.readInt32();
int fmt = data.readInt32();
int chan = data.readInt32(); ALOGD("CONNECT: %d, %d, %d, %d, %d\n", pid,previewhw,intf,fmt,chan);
reply->writeInt32(connect(pid,previewhw,intf,fmt,chan));
return NO_ERROR;
}break; case PRINTSTRING_CMD: {
CHECK_INTERFACE(IdemoNativeService, data, reply);
const char *str;
str = data.readCString();
ALOGD("PrintString: %s\n", str);
ALOGD("printString: %s\n", str);
reply->writeInt32(printString(str));
return NO_ERROR;
} break;
default:
return BndemoNativeService::onTransact(code, data, reply, flags);
} return NO_ERROR;
}
#endif

写完了服务,那我们就再写一个可运行文件来生成一下,里面startThreadPool生成线程池。然后再调用joinThreadPool来监听变化;

    sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
// ALOGI("ServiceManager: %p", sm.get());
demoNativeService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();

写到这,能够说服务已经能够跑起来了,那我们怎么验证呢,最快的办法还是写一个可运行文件去測一下它的接口,看通没通就知道了。

       	int ret= -1;
int pid = IPCThreadState::self()->getCallingPid(); ALOGI("demoNativeService client is now starting, pid=%d", pid); android::sp<android::IServiceManager> sm = android::defaultServiceManager();
android::sp<android::IBinder> binder;
android::sp<IdemoNativeService> shw; do {
binder = sm->getService(android::String16("ds.demonativeservice"));
if (binder != 0)
break;
ALOGW("IdemoNativeService not published, waiting...");
usleep(500000);
} while(true); ALOGI("IdemoNativeService client is now trying"); shw = android::interface_cast<IdemoNativeService>(binder);
ret = shw->printString("Good man desheng");
ALOGI("demoNativeService client printString, ret=%d", ret); ret = shw->connect(pid,1, 2, 3, 4);
ALOGI("demoNativeService client connect, ret=%d", ret);

以下就是笔者測试的打印。例如以下:

# dem
demoNativeServiceclient demoNativeServiceserver
# demoNativeServiceserver &
[2] 2332
# --------- beginning of /dev/log/main
02-19 17:10:57.890 E/HelloWorldService( 2332): demoNativeService created #
# dem
demoNativeServiceclient demoNativeServiceserver
# demoNativeServiceclient
02-19 17:11:02.520 I/demoNativeService/Service( 2334): demoNativeService client is now starting, pid=2334
02-19 17:11:02.520 I/demoNativeService/Service( 2334): IdemoNativeService client is now trying
02-19 17:11:02.520 D/HelloWorldService( 2332): OnTransact(2,16)
02-19 17:11:02.520 D/HelloWorldService( 2332): PrintString: Good man desheng
02-19 17:11:02.520 D/HelloWorldService( 2332): printString: Good man desheng
02-19 17:11:02.520 D/HelloWorldService( 2332): demoNativeService printString:Good man desheng
02-19 17:11:02.520 I/demoNativeService/Service( 2334): demoNativeService client printString, ret=66
02-19 17:11:02.520 D/HelloWorldService( 2332): OnTransact(1,16)
02-19 17:11:02.520 D/HelloWorldService( 2332): CONNECT: 2334, 1, 2, 3, 4
02-19 17:11:02.520 D/HelloWorldService( 2332): demoNativeService connect:2334, 1, 2, 3, 4
02-19 17:11:02.520 I/demoNativeService/Service( 2334): demoNativeService client connect, ret=88
02-19 17:11:02.520 I/demoNativeService/Service( 2334): Hello client is now exiting
#
# 02-19 17:11:07.540 D/InitAlarmsService( 2259): Clearing and rescheduling alarms. # service list
Found 78 services:
0 ds.demonativeservice: [android.hardware.IdemoNativeService]
1 phone: [com.android.internal.telephony.ITelephony]
2 iphonesubinfo: [com.android.internal.telephony.IPhoneSubInfo]
3 simphonebook: [com.android.internal.telephony.IIccPhoneBook]
4 isms: [com.android.internal.telephony.ISms]
5 jeavoxmiddleware: [android.jeavox.IMiddleWareService]

写到这,假设要给应用调用的话,还须要写Client,JNI,JNI及以上在此不再讨论了。我们就简易来看看client怎么处理吧。事实上有点相似上面那个可运行文件的写法,这里可能就是有一个对象的概念。能够保持。大概例如以下:

demoNativeServiceClient::demoNativeServiceClient()
{
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("ds.demonativeservice"));
mdemoNativeService = interface_cast<IdemoNativeService>(binder);
} demoNativeServiceClient::~demoNativeServiceClient()
{
mdemoNativeService = NULL;
} int32_t demoNativeServiceClient::connect(int previewhw,int intf,int fmt,int chan)
{
return mdemoNativeService->connect(getCallingPid(),previewhw,intf,fmt,chan);
} int32_t demoNativeServiceClient::printString(const char *str)
{
return mdemoNativeService->printString(str);
}

罗哩罗嗦写了这么多。请大家拍砖,轻拍一下:)

从零開始怎么写android native service?的更多相关文章

  1. Bmob移动后端云服务平台--Android从零開始--(二)android高速入门

    Bmob移动后端云服务平台--Android从零開始--(二)android高速入门 上一篇博文我们简介何为Bmob移动后端服务平台,以及其相关功能和优势. 本文将利用Bmob高速实现简单样例,进一步 ...

  2. Bmob移动后端云服务平台--Android从零開始--(一)何为Bmob

    Bmob移动后端云服务平台--Android从零開始--(一)何为Bmob 在正式的项目开发中,单client不能满足我们的需求,须要实现client与服务端的连接. 而在编写Android服务端代码 ...

  3. 从零開始学习OpenCL开发(一)架构

    多谢大家关注 转载本文请注明:http://blog.csdn.net/leonwei/article/details/8880012 本文将作为我<从零開始做OpenCL开发>系列文章的 ...

  4. # 从零開始搭建Hadoop2.7.1的分布式集群

    Hadoop 2.7.1 (2015-7-6更新),Hadoop的环境配置不是特别的复杂,可是确实有非常多细节须要注意.不然会造成很多配置错误的情况.尽量保证一次配置正确防止重复改动. 网上教程有非常 ...

  5. 从零開始学Swift之Hello World进化版

    上节课,也就是昨晚啦,我们学习到从零開始学Swift之Hello World.那一节仅仅有一句代码,大家会认为不够过瘾. 那么这节课,就给大家来多点瘾货吧! 先上图! //var 代表变量的类型, s ...

  6. 关东升的《从零開始学Swift》即将出版

    大家好: 苹果2015WWDC大会公布了Swift2.0,它较之前的版本号Swift1.x有非常大的变化.所以我即将出版<从零開始学Swift><从零開始学Swift>将在&l ...

  7. 《PHP 5.5从零開始学(视频教学版)》内容简单介绍、文件夹

    <PHP 5.5从零開始学(视频教学版)>当当网购买地址: http://product.dangdang.com/23586810.html <PHP 5.5从零開始学(视频教学版 ...

  8. 从零開始开发Android版2048 (一)初始化界面

    自学Android一个月多了,一直在工作之余零零散散地看一些东西.感觉经常使用的东西都有些了解了,可是一開始写代码总会出各种奇葩的问题.感觉还是代码写得太少.这样继续杂乱地学习下去进度也太慢了,并且学 ...

  9. 从零開始开发Android版2048 (四) 分数、重置、结束

    这一篇的内容主要是在上一篇的基础上,增加分数计算(包含当前分数和最高分数).游戏结束的推断以及游戏界面的重置这三个部分的功能. 一.分数的计算和保存          首先,2048这个游戏的分数包含 ...

随机推荐

  1. 《Unix环境高级编程》读书笔记 第7章-进程环境

    1. main函数 int main( int argc, char *argv[] ); argc是命令行参数的数目,包括程序名在内 argv是指向参数的各个指针所构成的数组,即指针数组 当内核执行 ...

  2. Python内置数据结构之字符串str

    1. 数据结构回顾 所有标准序列操作(索引.切片.乘法.成员资格检查.长度.最小值和最大值)都适用于字符串,但是字符串是不可变序列,因此所有的元素赋值和切片赋值都是非法的. >>> ...

  3. codevs 1288 埃及分数 (迭代加深搜索)

    题目大意:给你一个分数$a/b$,把它拆解成$\sum_{i=1}^{n}1/ai$的形式,必须保证$ai$互不相同的情况下,尽量保证n最小,其次保证分母最大的分数的分母最小 什么鬼玄学题!!! 因为 ...

  4. Google的10大座右铭

    1. 以用户为中心,其他一切纷至沓来. 创建伊始,Google 即以提供最佳的用户体验为其中心任务.虽然很多公司主张客户利益优先,但难以抗拒各种诱惑,往往会牺牲客户的少量利益来增加股东价值. Goog ...

  5. [LeetCode]Subsets II生成组合序列

    class Solution {//生成全部[不反复]的组合.生成组合仅仅要採用递归,由序列从前往后遍历就可以. 至于去重,依据分析相应的递归树可知.同一个父节点出来的两个分支不能一样(即不能与前一个 ...

  6. 蓝的成长记——追逐DBA(18):小机上WAS集群故障,由一次更换IP引起

    原创作品.出自 "深蓝的blog" 博客,欢迎转载,转载时请务必注明出处.否则追究版权法律责任. 深蓝的blog:http://blog.csdn.net/huangyanlong ...

  7. 【甘道夫】Sqoop1.99.3基础操作--导入Oracle的数据到HDFS

    第一步:进入clientShell fulong@FBI008:~$ sqoop.sh client Sqoop home directory: /home/fulong/Sqoop/sqoop-1. ...

  8. Vim 批量替换

    假设在非Win系统下. 想批量替换文本不再是Ctrl+F那么简单了, 一般用Vim来做批量替换, 略微复杂点: 比如将192.168.0.1替换为192.168.0.2 :%s/192.168.0.1 ...

  9. hdu5249 Tricks Device(网络流最大匹配)

    分析题意可知: 1.最少须要切断多少边使吴不能找到张(题意吴仅仅能走最短路径上面的边),对从起点到终点的最短路径又一次建图,每条边的权值为1.求最大流就可以 2.在吴能够找到张的前提下,最多能够切断边 ...

  10. PIC18F4520 + NRF24L01

    SI SO应该对调过来用.. TX /* ** Tx.c ** Transmit test program for PIC18F4520 and nRF24L01 or nRF24L01+ ** Us ...