Many of the important servers in the system are included in the MediaServer:
- Audioflinger: Core Services in the audio system
- Audiopolicyservice: An important service for audio strategies in audio systems
- Mediaplayerservice: An important service in the multimedia system
- Cameraservice: Important services related to photography and photography
At the same time, analyzing mediaserver can help to understand the IPC mechanism in Android. Android system basically can be regarded as a binder based C/s architecture, the understanding of the binder mechanism is relatively complex, if you can use specific examples can be more easily understood.
Android's communication system architecture
Android's communication mechanism can basically be seen as the interaction between the client, server, and ServiceManager:
- The server first registers some service to ServiceManager, where the server is the ServiceManager client;
- If a client wants to use a service, it first obtains information about the service in ServiceManager, and all clients are servicemanager.
- The client receives the service information and then uses the service after establishing communication with the server process where the service is located, where clients are the servers.
During these interactions, the Android system uses binders to communicate.
MediaServer entry function
MS is an executable program, its entry function is the main function, where the file location: Frameworks\base\media\mediaserver\main_mediaserver.cpp
Code is as follows:
int main (int argc, Char** argv) {SP < Processstate> proc (Processstate::self ()); Sp< iservicemanager> SM = Defaultservicemanager (); Alogi ( "ServiceManager:%p" , Sm Get ()); Audioflinger::instantiate (); Mediaplayerservice::instantiate (); Cameraservice::instantiate (); Audiopolicyservice::instantiate (); Processstate::self () -> startthreadpool (); Ipcthreadstate::self () -> jointhreadpool ();}
As you can see, in the main function,
- We first get an example of a processstate, which we can guess from the self method using a singleton pattern;
- Next we call the Defaultservicemanager method to obtain the Iservicemanager instance;
- Then the initialization of several important services is carried out;
- Call the Startthreadpool method and the Jointhreadpool method.
Analysis of the Processstate class
File Location: Frameworks\base\libs\binder\processstate.cpp
Self method: In the main function, we call the self method to get a processstate instance, let's take a look at this method
sp<ProcessState> ProcessState::self(){ ifNULLreturn gProcess; //提供原子操作 AutoMutex _l(gProcessMutex); ifNULLnew ProcessState; return gProcess;}
As you can see, as expected, Processstate is using singleton mode.
Let's take a look at the Processstate constructor:
Processstate::P rocessstate (): Mdriverfd (Open_driver ()), Mvmstart (map_failed), mmanagescontexts (false), Mbindercontextcheckfunc (null), Mbindercontextuserdata (null), mthreadpoolstarted (false), Mthreadpoolseq (1){if(Mdriverfd >=0) {//XXX Ideally, there should is a specific define for whether we //Mmap (or whether we could possibly have the kernel module //Availabla).#if !defined (HAVE_WIN32_IPC) ///Mmap the binder, which provides a virtual into address memory space block to receive transactionsMvmstart = Mmap (0, Binder_vm_size, Prot_read, Map_private | Map_noreserve, MDRIVERFD,0);if(Mvmstart = = map_failed) {//*sigh*Aloge ("Using/dev/binder failed:unable to Mmap transaction memory.\n"); Close (MDRIVERFD); MDRIVERFD =-1; }#Else MDRIVERFD =-1;#endif } log_always_fatal_if (Mdriverfd <0,"Binder driver could not being opened. Terminating. ");}
As you can see, the Open_driver function is called first in the constructor and the return value is assigned to MDRIVERFD, so let's take a look at this function:
StaticintOpen_driver () {intFD =Open("/dev/binder", O_RDWR);if(FD >=0) {Fcntl(FD, F_SETFD, fd_cloexec);intVers status_t result = IOCTL (FD, binder_version, &vers);if(Result = =-1) {Aloge ("Binder ioctl to obtain version failed: %s", Strerror (errno));Close(FD); FD =-1; }if(Result! =0|| Vers! = binder_current_protocol_version) {Aloge ("Binder driver protocol does not match user space protocol!");Close(FD); FD =-1; } size_t MaxThreads = the; result = IOCTL (FD, Binder_set_max_threads, &maxthreads);if(Result = =-1) {Aloge ("Binder ioctl to set Max Threads failed: %s", Strerror (errno)); } }Else{ALOGW ("Opening '/dev/binder ' failed: %s\ n", Strerror (errno)); }returnFD;}
You can see that the Open_driver function primarily opens the/dev/binder device and returns the FD for this device.
Then I went back to the constructor, saved the FD for the device in MDRIVERFD, and then we initialized the other member variables and called the MMAP function to open up a piece of memory for the binder device because it received the data.
To summarize the tasks of our Processstate class:
- The binder device is opened and the FD of the device is saved;
- Using the saved FD to open a piece of memory for the binder device to receive data;
- Because Processstate uses singleton mode, each process can only open one binder device at a time.
Defaultservicemanager function Analysis
File Location: Frameworks\base\libs\binder\iservicemanager.cpp
sp< Iservicemanager> Defaultservicemanager () {if ( Gdefaultservicemanager != null ) return Gdefaultservicemanager; {Automutex _l (gdefaultservicemanagerlock); if (Gdefaultservicemanager == null ) {Gdefaultservicemanager = interface_cast< is Ervicemanager> (Processstate::self () -> getcontextobject (null )); }} return Gdefaultservicemanager;}
You can see that the Gdefaultservicemanager function mainly assigns values to the Gdefaultservicemanager, and first we look at the incoming parameters of this function: Processstate::self () Getcontextobject (NULL)
Sp<IBinder>Processstate:: Getcontextobject(Const SP<IBinder>&Caller) {returnGetstrongproxyforhandle (0);} Sp<IBinder>Processstate:: Getstrongproxyforhandle(int32_tHandle) {SP<IBinder>Result Automutex _l (MLock); Handle_entry*E=Lookuphandlelocked (Handle);if(E!= NULL) {//If it doesn't exist now or we can't get a reference to it, we need to create a new Bpbinder,IBinder*B=E -Binderif(b== NULL || !E -Refs -Attemptincweak (this)) {b= NewBpbinder (Handle); E -Binder=bif(b) E -Refs=B -Getweakrefs (); Result=b }Else{Result.Force_set (b); E -Refs -Decweak (this); } }returnResult;}
You can see that we actually returned a bpbinder (handle); handle has a value of 0.
Interface_cast looks like a coercion type conversion, which is actually a template function, let's look at its truth:
template<typename INTERFACE>inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj){ return INTERFACE::asInterface(obj);}
The template we passed in is Iservicemanager, which is actually called the Iservicemanager Asinterface method.
The Declaration and implementation of the Asinterface method is actually implemented through two macro definitions, located in the IInterface.h file:
#define DECLARE_META_INTERFACE (INTERFACE) \ Static ConstANDROID::STRING16 descriptor;StaticAndroid::sp<i# #INTERFACE > asinterface (\ Constandroid::sp<android::ibinder>& obj);Virtual Constandroid::string16& Getinterfacedescriptor ()Const; I# #INTERFACE (); \ Virtual~i# #INTERFACE (); \#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 () {} \
After replacing interface with Iservicemanager, you can get:
static constandroid:: String16Descriptor; Staticandroid::sp<iservicemanager>Asinterface (constandroid:: Sp<android:: IBinder>& obj); Virtual constandroid::string16&Getinterfacedescriptor () const;Iservicemanager(); Virtual ~Iservicemanager(); Constandroid:: String16 Iservicemanager::Descriptor (NAME); Constandroid::string16& Iservicemanager::Getinterfacedescriptor () const {return Iservicemanager::Descriptor; }android::sp<iservicemanager> Iservicemanager::Asinterface (constandroid:: Sp<android:: IBinder>& obj) {android::sp<iservicemanager>Intrif(obj! =NULL) {intr = static_cast<Iservicemanager*> (Obj->querylocalinterface (Iservicemanager::Descriptor). get ());if(Intr = =NULL) {intr = newBpservicemanager(obj); } }returnIntr }Iservicemanager::iservicemanager() { }Iservicemanager::~Iservicemanager() { }
You can see that the Asinterface method eventually actually returns a Bpservicemanager object.
Summarize the work of the Defaultservicemanager method:
- Created a Bpbinder object that is responsible for client binder communication (which is later) because we are clients for ServiceManager, so here we create binder clients;
- Created a Bpservicemanager object, primarily responsible for Iservicemanager's business functions, holding a Bpbinder object mremote inside his.
Class Relationship Summary
See here, has been a little dazzled, but also IBinder, but also Iservicemanager, is Bpbinder, but also Bpservicemanager, it is time to summarize the relationship of these classes, turn over these classes, Here is a non-standard UML diagram to illustrate:
It is important to note that:
- Refbase is the ancestor of all classes in Android, equivalent to object in Java;
- Bpbinder and Bbinder are both representative classes of binder communication in Android, where Bpbinder is the proxy class that the client uses to interact with the server, and P stands for proxy, while Bbinder is the destination of the interaction;
- Bpbinder and Bbinder correspond to each other, the binder system will be handle to identify the corresponding bbinder;
- Bnservicemanager in the n represents the native, and the bn corresponds to the Bpservicemanager, which represents the ServiceManager business proxy class.
Android Source code Analysis--mediaserver Source Analysis (a)