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);
    }

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

  • 相关阅读:
    Android自定义之仿360Root大师水纹效果
    Android之TextView的Span样式源码剖析
    Android之TextView的样式类Span的使用详解
    随着ScrollView的滑动,渐渐的执行动画View
    仿微信主界面导航栏图标字体颜色的变化
    android自定义之 5.0 风格progressBar
    Android性能优化之内存篇
    Android性能优化之运算篇
    How to install Zabbix5.0 LTS version with Yum on the CentOS 7.8 system?
    How to install Zabbix4.0 LTS version with Yum on the Oracle Linux 7.3 system?
  • 原文地址:https://www.cnblogs.com/yjbjingcha/p/7183892.html
Copyright © 2011-2022 走看看