从零开始怎么写android native service?
Android service对于从事android开发的人都不是一个陌生的东西,很多人可能会觉得服务很简单。服务是简单,因为复杂的别人做了,所以才会觉得简单。我们先梳理一下服务的分类,首先有本地服务跟系统服务的区分,而在APP里写的服务大多就成为Java服务或者应用服务。
做APP的人写个应用服务相对来说是最简单的,因为extends了一个service后几个简单的接口就可以跑起来了,写完这种服务可能也只是对服务一知半解,因为值钱的service类Google的人已经帮你写好了,这是你的福气为你带来了便利,当然也可能会麻痹你:),但是做APP的人会有能解决问题是首要任务了,有时间还是对它了解更清楚点比较好,在此不再讨论这个。
做设备做系统的人,经常可能会去写系统服务,也就是framework下面的服务,systemserver里面注册的服务,写这种服务一般来说比较少,只有做设备系统的才会这样干,才有机会有完成的系统代码,可以在里面自由遨游,笔者三年前写过一个,可以看看【自己动手从零开始写一个完整的android Service】
那剩下的一个是本地服务,也就是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
class BpdemoNativeService: public BpInterface{ public: BpdemoNativeService(const sp & impl) : BpInterface (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
class BndemoNativeService: public BnInterface{ 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, repl