从零开始怎么写android native service?

简介: 从零开始怎么写android native service        Android service对于从事android开发的人都不是一个陌生的东西,很多人可能会觉得服务很简单。

从零开始怎么写android native service

        Android service对于从事android开发的人都不是一个陌生的东西,很多人可能会觉得服务很简单。服务是简单,因为复杂的别人做了,所以才会觉得简单。我们先梳理一下服务的分类,首先有本地服务跟系统服务的区分,而在APP里写的服务大多就成为Java服务或者应用服务。

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

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

做设备做系统的人,经常可能会去写系统服务,也就是framework下面的服务,systemserver里面注册的服务,写这种服务一般来说比较少,只有做设备系统的才会这样干,才有机会有完成的系统代码,可以在里面自由遨游,笔者三年前写过一个,可以看看【自己动手从零开始写一个完整的android Servicehttp://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);
}

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

目录
相关文章
|
7月前
|
Android开发
Android 11 添加Service服务SELinux问题
Android 11 添加Service服务SELinux问题
400 1
|
7月前
|
Android开发
Android基础知识:请解释Service是什么,它与IntentService的区别是什么?
Android基础知识:请解释Service是什么,它与IntentService的区别是什么?
117 0
|
编解码 Android开发
Android native层实现MediaCodec编码H264/HEVC
Android平台在上层实现mediacodec的编码,资料泛滥,已经不再是难事,今天给大家介绍下,如何在Android native层实现MediaCodec编码H264/HEVC,网上千篇一律的接口说明,这里不再赘述,本文主要介绍下,一些需要注意的点,权当抛砖引玉,相关设计界面如下:
256 0
|
7月前
|
XML Java Android开发
Android Studio App开发之服务Service的讲解及实战(包括启动和停止,绑定与解绑,推送服务到前台实现音乐播放器,附源码)
Android Studio App开发之服务Service的讲解及实战(包括启动和停止,绑定与解绑,推送服务到前台实现音乐播放器,附源码)
1013 0
|
6月前
|
调度 Android开发
43. 【Android教程】服务:Service
43. 【Android教程】服务:Service
64 2
|
7月前
|
Android开发
Android Service Call /dev/xxx SELinux
Android Service Call /dev/xxx SELinux
135 1
|
4月前
|
编解码 网络协议 Android开发
Android平台GB28181设备接入模块实现后台service按需回传摄像头数据到国标平台侧
我们在做Android平台GB28181设备对接模块的时候,遇到这样的技术需求,开发者希望能以后台服务的形式运行程序,国标平台侧没有视频回传请求的时候,仅保持信令链接,有发起视频回传请求或语音广播时,打开摄像头,并实时回传音视频数据或接收处理国标平台侧发过来的语音广播数据。
|
6月前
|
JavaScript 前端开发 Android开发
kotlin安卓在Jetpack Compose 框架下使用webview , 网页中的JavaScript代码如何与native交互
在Jetpack Compose中使用Kotlin创建Webview组件,设置JavaScript交互:`@Composable`函数`ComposableWebView`加载网页并启用JavaScript。通过`addJavascriptInterface`添加`WebAppInterface`类,允许JavaScript调用Android方法如播放音频。当页面加载完成时,执行`onWebViewReady`回调。
|
5月前
|
Dart Android开发 Windows
Flutter和Native 通信 android端
Flutter和Native 通信 android端
|
7月前
|
存储 监控 Java
Android Service之设备存储空间监控 DeviceStorageMonitorService
Android Service之设备存储空间监控 DeviceStorageMonitorService
153 2