Native service is actually a Linux daemon, providing some services, but since the Android interprocess communication uses the binder mechanism, then we need to follow the Android rules to implement our Native service.
The client uses a proxy class with the same interface when requesting service services. Native service This specifically implements this interface, so Android provides the IInterface class, which is "base class for Binder interfaces", so our Izxtask class inherits it:
public IInterface {public: enum { TASK_GET_PID = IBinder::FIRST_CALL_TRANSACTION, }; virtualint0; DECLARE_META_INTERFACE(ZxTask);};
IMPLEMENT_META_INTERFACE"android.hardware.IZxTask");
Must start with I, because there will be some macros, such as Declare_meta_interface,i start is written to the inside of the macro, so we just passed the zxtask on the line. Our native service provides an interface that is the process number that returns the service.
Below we need to start the differentiation implementation, one is the client, one is the native service.
First look at the proxy class
class Bpzxtask: PublicBpinterface<Izxtask> {public:Bpzxtask(const sp<ibinder>& binder):Bpinterface<Izxtask>(binder){} virtual int getpid(){Parceldata, reply; Data.writeinterfacetoken(izxtask::getinterfacedescriptor()); Remote()->transact(task_get_pid, data, &reply); Return Reply.readint32(); }};
Bpinterface template class, where p is the meaning of the agent. It is the template parameter with the interface we defined earlier.
Bpinterface declares as follows:
publicpublic BpRefBase{public: BpInterface(const sp<IBinder>& remote);protected: virtual IBinder* onAsBinder();};
Our bpzxtask need to implement the interface functions in the interface classes we define. In the implementation, we are the client, we need to apply to the native service, we use remote to obtain the associated service IBinder object, and then through Transact commit, through reply to obtain the return value.
Let's look at the implementation of Bninterface.
public BnInterface<IZxTask> {public: virtualonTransactconst0);};
status_t Bnzxtask:: Ontransact (uint32_t code, constParcel& data, Parcel* reply, uint32_t flags){switch (code) { Case Task_get_pid: {Check_interface(Izxtask, Data, reply);int32_t pid = Getpid (); Reply->writeint32 (PID); ReturnNo_error; } break; default:ReturnBbinder:: Ontransact (Code, Data, reply, flags);}}
Our Transact call in Bpinterface will callback Bninterface's ontransact to handle, we make the request distinction according to the code parameter.
The Bninterface class template is declared as follows:
publicpublic BBinder{public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtualconst String16& const;protected: virtual IBinder* onAsBinder();};
One of its parent classes is an interface class that inherits from IInterface, and one that represents the Bbinder class on the binder service side.
Below to implement the native service.
publicpublic BnZxTask {public: virtualintgetPid(); staticcharconstreturn"ZxTask"; } friend class BinderService<ZxTaskService>;};int ZxTaskService::getPid(){ return getpid();}
Here we implement the Getpid interface provided by the service to implement a logical encapsulation of the Ok,binderservice template for us to start a service.
The Binderservice is implemented as follows:
Template<typename Service>class binderservice{ Public:Staticstatus_tPublish(BOOLallowisolated =false) {sp<iservicemanager> sm (Defaultservicemanager ());returnSm->addservice (String16 (Service::getservicename ()),NewSERVICE (), allowisolated); }Static voidPublishandjointhreadpool (BOOLallowisolated =false) {publish (allowisolated); Jointhreadpool (); }Static voidInstantiate () {Publish ();}Staticstatus_t shutdown () {returnNo_error; }Private:Static void Jointhreadpool() {sp<processstate> PS (processstate::self ()); Ps->startthreadpool (); Ps->givethreadpoolname (); Ipcthreadstate::self ()->jointhreadpool (); }};
It requires a template parameter implementation getServiceName
method, publish
and the publishAndJoinThreadPool
function implements the logic that the service adds to the SM, publish just add, and publishAndJoinThreadPool
the service is started.
Here we have completed the development of the native service, which we have compiled into a library.
Android.mk
Local_path:=$(Call My-dir)include $(Clear_vars)Local_src_files :=Zxtask. cppZxtaskservice. cppLocal_c_includes := System/core/includeframeworks/native/includelocal_shared_libraries := Libbinder LibutilsLocal_module:= Libzxtaskinclude $(build_shared_library)
We write a service executable program.
Main.cpp
#include"service/ZxTaskService.h"int main(){ /* code */ android::ZxTaskService::publishAndJoinThreadPool(); return0;}
Android.mk
LOCAL_PATH$(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := LOCAL_C_INCLUDES := frameworks/base/zxTaskLOCAL_MODULE:= zxtaskserviceLOCAL_SHARED_LIBRARIES := libzxtask libutils libbinderinclude $(BUILD_EXECUTABLE)
Write a test client
Main.cpp
#include "service/zxtask.h"#include <binder/IServiceManager.h>#include <unistd.h>#include <stdio.h>intMain () {using namespaceAndroid sp<iservicemanager> SM =defaultservicemanager ();printf("%s\n","Get ServiceManager"); Sp<ibinder> Binder =sm->getservice (String16 ("Zxtask")); Sp<izxtask> mtask =interface_cast<izxtask> (binder);printf("Zxtask Service pid%d, client pid:%d", Mtask->getpid (), Getpid ());return 0;}
Android.mk
LOCAL_PATH$(call my-dir)include $(CLEAR_VARS)LOCAL_SRC_FILES := LOCAL_C_INCLUDES := frameworks/base/zxTaskLOCAL_MODULE:= zxtaskclientLOCAL_SHARED_LIBRARIES := libzxtask libutils libbinderinclude $(BUILD_EXECUTABLE)
It was used interface_cast
.
template<typename INTERFACE>inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){ return INTERFACE::asInterface(obj);}
It uses the Asinterface function, and this function is what we use to declare in Izxtask DECLARE_META_INTERFACE
.
# Define declare_meta_interface (INTERFACE) \ static const android::string16 descriptor; static android::sp<i# #INTERFACE > Asinterface (\ const Android::sp<android::ibinder >& obj); virtual const android::string16& getinterfacedescriptor () const ; I# #INTERFACE (); \ virtual ~i# #INTERFACE ();
It declares a description of the class property that we use for the asInterface
function.
Look at the IMPLEMENT_META_INTERFACE
macro.
#define IMPLEMENT_META_INTERFACE (INTERFACE, NAME) \ ConstAndroid::string16 I# #INTERFACE::d escriptor (NAME); \ Constandroid::string16& I# #INTERFACE:: Getinterfacedescriptor () const {\ returnI# #INTERFACE::d escriptor; \} android::sp<i# #INTERFACE > i# #INTERFACE:: Asinterface (\ Constandroid::sp<android::ibinder>& obj) { Android::sp<i# #INTERFACE > intr; \ if(obj = NULL) {intr =static_cast<i# #INTERFACE *> (\Obj->querylocalinterface (I# #INTERFACE::d escriptor). get ()); \ if(Intr = = NULL) {intr =NewBp# #INTERFACE (obj); \} }returnIntr } I# #INTERFACE:: i# #INTERFACE () {} \I# #INTERFACE:: ~i# #INTERFACE () {} \
The main view asInterface
of the implementation. It calls IBinder's querylocalinterface to query our interface object, where the base class pointer is used, if not new. Our bpzxtask is only used in this function, which is why when I implement it, I'm instructed to put it all in the CPP file.
new Bp##INTERFACE(obj);
This sentence indicates that our proxy class must start with BP and IBinder object as the parameter of construction, and implement the binding of proxy and IBinder object.
sp<IBinder> binder =sm->getService(String16("ZxTask"));
The IBinder object for the service is obtained from the service name, using the interface_cast
binding that implements the client's proxy and the service's IBinder, and then we can invoke the Transact function of ibinder in Getpid. This and the remote communication, callback to the native service Ontransact interface, and then processed to return the results, so that the client and service to achieve the communication.
Run as:
code example: Https://git.oschina.net/zhouX/servicedemo.git
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
Android Add a native Service