How to Write android native service from scratch?

Source: Internet
Author: User

How to Write android native service from scratch?

Android service is not a stranger to people engaged in android development. Many people may think that the service is very simple. The service is simple because it is complicated for others to do so. First, let's sort out the service categories. First, there is a distinction between local services and system services. Most services written in apps become Java services or application services.

The APP developer writes an application service, which is relatively simple, because after extends has a service, several simple interfaces can be run, after writing this kind of service, you may only know about the service, because the valuable service-type Google users have already helped you write it. This is your blessing that brings convenience to you, and of course it may paralyze you :), however, the APP developer will be able to solve the problem, which is the first task. It is better to know it more clearly if you have time. I will not discuss this here.

The person who works as a device as a system may often write system services, that is, services under the framework, and services registered in the systemserver. Generally, there are few such services, only those who work on the device system can have the opportunity to complete the system code. They can freely swim in it. I wrote one three years ago. You can see 【Write a complete android Service from scratch.]

The remaining one is the local service, that is, the native service. The multimedia and audio systems in the system we know about are all written as local services, the advantage of writing is that the running efficiency is higher, because C/C ++ is more efficient than JAVA. This is because I have been mainly engaged in underlying development for a long time. Sometimes we have such a requirement, which requires high operation efficiency and better transplantation. I mainly want to promote and write things to our customers, then I write a local service, which is the most independent and the most efficient. How can I write a local service? Most of the services written by people are mostly java services. There are not many local services actually written, and local services are relatively more complex. Therefore, I decided to write a local service from scratch. The following describes the process.

There are four local services: IService, Service proxy (BpService), Service stub (BnService), and Service entity (Service ); the following example is started with demoNativeService, and strives to be simple. Two interfaces are written in it;

First, define the service interface IdemoNativeService. The parent class of the IdemoNativeService service interface is IInterface. Specifically, declare the interface in DECLARE_META_INTERFACE (demoNativeService). The Code is as follows:

 

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

 

Of course, if you have defined the header file of IdemoNativeService, You need to perform actual operations. First, you need to solve BpdemoNativeService. Its parent class is BpInterface. Here, we mainly use the parcel, read, write, and sort data in different processes. It is not difficult to use the AIDL tool to help you transfer the data, let's just change it a little bit. There is a very important remote in it. This and remote are the secrets behind the scenes. It saves the objects of the service instance, it is a member of BpRefBase. When a service is generated, a value is assigned. After definition, an important program is IMPLEMENT_META_INTERFACE (demoNativeService, "android. hardware. idemoNativeService "); this macro is very important. It corresponds to the previous DECLARE. It is declared earlier and implemented later. Of course, the parameters we bring must be consistent with the name, so that we can communicate normally!

 

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
   
  
 

 

Then you need to write the service stub. The parent class of BndemoNativeService is BnInterface. Have you found that both BndemoNativeService and BpdemoNativeService are based on the Interface Class IdemoNativeService, so that the interface to communicate is unique and the conversation is possible;

 

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

 

This turns out to be a large service entity token. demoNativeService is based on the token and defines an instantiate () interface in demoNativeService to add the service to servicemanager. Pay attention to demoNativeService () with destructor ~ DemoNativeService () must be written as private, so that no one else can generate a new object. OnTransact is rewritten in it. Once BpdemoNativeService is a breeze, it will be linked to BndemoNativeService. Because the service entity overwrites onTransact, it will first be executed to demoNativeService: onTransact here, it cannot be processed here. You can transfer it to onTransact of BpdemoNativeService or directly to onTransact of BBinder;

 

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

 

After writing the service, we will write another executable file to generate the thread pool generated by startThreadPool, and then call joinThreadPool to listen for changes;

 

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

 

Writing this, we can say that the service is ready to run. How can we verify it? The fastest way is to write an executable file to test its interface. You can see it when it doesn't work;

 

       int ret= -1;      int pid = IPCThreadState::self()->getCallingPid();      ALOGI("demoNativeService client is now starting, pid=%d", pid);        android::sp sm = android::defaultServiceManager();        android::sp binder;        android::sp
 
   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
  
   (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);
  
 

 

The following figure shows the output of the test:

 

# demdemoNativeServiceclient   demoNativeServiceserver   # demoNativeServiceserver &                                                    [2] 2332# --------- beginning of /dev/log/main02-19 17:10:57.890 E/HelloWorldService( 2332): demoNativeService created# # demdemoNativeServiceclient   demoNativeServiceserver   # demoNativeServiceclient                                                      02-19 17:11:02.520 I/demoNativeService/Service( 2334): demoNativeService client is now starting, pid=233402-19 17:11:02.520 I/demoNativeService/Service( 2334): IdemoNativeService client is now trying02-19 17:11:02.520 D/HelloWorldService( 2332): OnTransact(2,16)02-19 17:11:02.520 D/HelloWorldService( 2332): PrintString: Good man desheng02-19 17:11:02.520 D/HelloWorldService( 2332): printString: Good man desheng02-19 17:11:02.520 D/HelloWorldService( 2332): demoNativeService printString:Good man desheng02-19 17:11:02.520 I/demoNativeService/Service( 2334): demoNativeService client printString, ret=6602-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, 402-19 17:11:02.520 D/HelloWorldService( 2332): demoNativeService connect:2334, 1, 2, 3, 402-19 17:11:02.520 I/demoNativeService/Service( 2334): demoNativeService client connect, ret=8802-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 listFound 78 services:0ds.demonativeservice: [android.hardware.IdemoNativeService]1phone: [com.android.internal.telephony.ITelephony]2iphonesubinfo: [com.android.internal.telephony.IPhoneSubInfo]3simphonebook: [com.android.internal.telephony.IIccPhoneBook]4isms: [com.android.internal.telephony.ISms]5jeavoxmiddleware: [android.jeavox.IMiddleWareService]

 

Write this. If you want to call the application, you need to write the Client, JNI, JNI, and above. We will not discuss them here. Let's just take a look at how the client handles them, in fact, it is a bit similar to the method of the executable file above. Here there may be an object concept that can be maintained, probably as follows:

 

demoNativeServiceClient::demoNativeServiceClient(){sp
 
   sm = defaultServiceManager();sp
  
    binder = sm->getService(String16("ds.demonativeservice"));mdemoNativeService = interface_cast
   
    (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);}
   
  
 

 

Luo Liluo writes so much. Please pat the bricks and take a pat :)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.