zoukankan      html  css  js  c++  java
  • 从零開始怎么写android native service?

    从零開始怎么写android native service

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

    服务是简单,由于复杂的别人做了,所以才会认为简单。我们先梳理一下服务的分类,首先有本地服务跟系统服务的区分。而在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
    ", 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
    ", str);
                    ALOGD("printString: %s
    ", 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);
    }

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

  • 相关阅读:
    nginx的rewrite指令
    springmvc上传图片《2》
    cors解决跨域
    java8的Streams
    vue基础篇---路由的实现《2》
    vue基础篇---vue组件《2》
    vue基础篇---watch监听
    ES6新特性
    ubuntu tftp 配置
    驱动程序分层分离概念--总线驱动设备模型
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/7183892.html
Copyright © 2011-2022 走看看