The pure Native Service indicates that the code is on the Native layer. The previous article mentioned that the two service processes communicate through onTransacton in the binder. This article mainly describes how to use the C/S structure, use IInterface for mutual access.
Take the specific code as an example:
Test. cpp:
Using namespace android;
Int main (int argc, char ** argv)
{
Sp <ProcessState> proc (ProcessState: self ());
Sp <IServiceManager> sm = defaultServiceManager ();
LOGI ("ServiceManager: % p", sm. get ());
Sm-> addService ("test. service", new Test); // Add it to serviceManager.
ProcessState: self ()-> startThreadPool ();
IPCThreadState: self ()-> joinThreadPool ();
// In Version 2.3, you can define to replace the above Code with one sentence:
TestService: publishAndJoinThreadPool ();
Return 0;
}
BinderService is defined as follows:
Static void publishAndJoinThreadPool (){
Sp <ProcessState> proc (ProcessState: self ());
Sp <IServiceManager> sm (defaultServiceManager ());
Sm-> addService (String16 (SERVICE: getServiceName (), new SERVICE ());
ProcessState: self ()-> startThreadPool ();
IPCThreadState: self ()-> joinThreadPool ();
}
The cross-Process C/S structure is defined here. Therefore, it can be divided into local server BnTest and client BpTest. The definitions and implementations of hidden Bp and Bn are included in BnTest. cpp.
BnXX stands for the server and Bp code Client
The header file ITest. h is defined as follows:
# Define ANDROID_ITEST_H
# Ifndef ANDROID_ITEST_H
Class ITest: public IInterface
{
Protected:
Enum
{
TEST_GETTEST = 0,
TEST_SETTEST,
};
Public:
DECLARE_META_INTERFACE (Test); // declare an important macro definition
// Define pure virtual functions
Virtual void getTest () = 0;
Virtual void setTest () = 0;
};
// BnTest statement
Class BnTest: public BnInterface <ITest>
{
Public:
Virtual status_t onTransact (uint32_t code,
Const Parcel & data,
Parcel * reply,
Uint32_t flags = 0 );
};
//----------------------------------------------------------------------------
}; // Namespace android
# Endif // ANDROID_ITEST_H
Interface implementation ITest. cpp
Namespace android {
// BpTest implementation
Class BpTest: public BpInterface <ITest>
{
Public:
BpTest (const sp <IBinder> & impl)
: BpInterface <ITest> (impl)
{
}
Virtual void getTest ()
{
Parcel data, reply;
Data. writeInterfaceToken (ITest: getInterfaceDescriptor ());
// TODO... use a similar writeXXX Function
Remote ()-> transact (TEST_GETTEST, data, & reply );
Int ret = reply. readXXX ();
Return;
}
Virtual void setTest ()
{
Parcel data, reply;
Data. writeInterfaceToken (ITest: getInterfaceDescriptor ());
// TODO... use the dead-class writeXXX Function
Remote ()-> transact (TEST_SETTEST, data, & reply );
Int ret = reply. readXXX ();
Return;
}
};
// BnTest implementation
// An important definition implementation
IMPLEMENT_META_INTERFACE (Test, "android. test. ITest ");
Status_t BnTest: onTransact (
Uint32_t code, const Parcel & data, Parcel * reply, uint32_t flags)
{
Switch (code ){
Case TEST_GETTEST :{
CHECK_INTERFACE (ITest, data, reply );
// TODO... setTest ()
} Break;
Case TEST_GETTEST :{
CHECK_INTERFACE (ITest, data, reply );
// TODO... getTest ()
} Break;
Default:
Break;
}
}
//----------------------------------------------------------------------
}
As mentioned above, many codes are basically the same, but they are only added with different processing codes. What is important is to use the Parcel object for serialization.
The following describes how to implement and call the client and server:
How to call the client:
Static sp <ITest> getTestSerivce ()
{
Sp <IBinder> binder;
Static sp <ITest> sTestManager = NULL;
If (sTestManager! = NULL)
Return sTestManager;
Sp <IServiceManager> sm = defaultServiceManager ();
Do {
Binder = sm-> getService (String16 ("test. service "));
If (binder = 0 ){
LOGW ("TestService not published, waiting ...");
Usleep (500000); // 0.5 s
}
} While (binder = 0 );
If (sTestManager = NULL ){
STestManager = interface_cast <ITest> (binder );
}
Return sTestManager;
}
Use the getTestSerivce function to obtain the client manager handle, and then use sTestManager-> setTest/getTest to call
This is a common function implementation method for clients to access the service.
Server implementation:
Class TestService:
Public BinderService <TestService>, // 2.3 exists, while Version 2.2 implements the instantiate () function.
Public BnTest,
Protected Thread
{
Public:
Static void instantiate ();
Static char const * getServiceName () {return "test. service ";}
// Interface functions implemented by the server
Virtual void getTest ();
Virtual void setTest ();
};
Void TestService: instantiate (){
DefaultServiceManager ()-> addService (
String16 ("test. service"), new TestService ());
}
Version 2.3 does this in the BinderService class:
Class BinderService
{
Public:
Static status_t publish (){
Sp <IServiceManager> sm (defaultServiceManager ());
Return sm-> addService (String16 (SERVICE: getServiceName (), new SERVICE ());
}
Static void instantiate () {publish ();}
...
};
OK. This is the cross-Process C/S structure code framework.
// TestService can be defined in Version 2.3 ::
From andyhuabing's column