Android binder Mechanic (2)-How to obtain reference of the servicemanager proxy object

Source: Internet
Author: User

In this article, we will thoroughly analyze servicemanager, the service administrator of the Android system.

 

Servicemanager is the manager of Android system services. All processes that need to communicate with each other through the Binder Mechanism must first obtain the proxy object of the Service Manager for binder communication. For example, the system contains the audioflingerservice for audio mixing, cameraservice for photography, and mediaplayerservice for media file playback. All these services are registered with servicemanager, so servicemanager maintains a list of all services in the system. To use these services, any application must first request servicemanager for reference of these services to establish a connection with these services.

 

In the first article in this series, exampleservice registers a service with the system using the following statement.

 

// File: exampleservice. cpp <br/> int r = defaservicservicemanager ()-> addservice (string16 ("Byn. Example"), new exampleservice ());

 

There are two problems:

1. What is done by defaservicservicemanager () and what is the result returned by defaservicservicemanager?

2. Why can I register a service with the system by calling the addservice method of the object returned in the previous step? What have been done in this registration process?

 

This article answers Question 1 first.

Servicemanager is also a service in the system. How can applications get in touch with it? The answer is through the defaservicservicemanager () function. Defaservicservicemanager () is a global function defined by the system in the android namespace. It is used to obtain reference to the servicemanager proxy object. Let's take a look at the source code of the function.

// File: Framework/base/libs/binder/iservicemanager. cpp <br/> sp <iservicemanager> defaultservicemanager () <br/>{< br/> If (gdefaservicservicemanager! = NULL) return gdefaservicservicemanager; // If the proxy object already exists, this object is directly returned </P> <p >{< br/> automutex _ L (gdefaservicservicemanagerlock ); <br/> If (gdefaservicservicemanager = NULL) {<br/> gdefaservicservicemanager = interface_cast <iservicemanager> (<br/> processstate: Self () -> getcontextobject (null); <br/>}</P> <p> return gdefaservicemanager; <br/>}

Gdefaservicservicemanager is defined in libutil, so any program or library that uses libutil will have this variable, which is unique in a process. The initial value of gdefaservicservicemanager is null. Therefore, call processstate: Self () to obtain a processstate instance. The Singleton design mode is used here, so that a process has only one processstate instance.// File: Frameworks/base/libs/binder/processstate. CPP <br/> sp <processstate> processstate: Self () <br/>{< br/> If (gprocess! = NULL) return gprocess; </P> <p> automutex _ L (gprocessmutex); <br/> If (gprocess = NULL) gprocess = new processstate; <br/> return gprocess; <br/>}

This processstate will open the/dev/binder device for ipcthreadstate. View its constructor.

// File: Frameworks/base/libs/binder/processstate. CPP <br/> processstate: processstate () <br/>: mdriverfd (open_driver () <br/>, mvmstart (map_failed) <br/>, mmanagescontexts (false) <br/>, mbindercontextcheckfunc (null) <br/>, mbindercontextuserdata (null) <br/>, mthreadpoolstarted (false) <br/>, mthreadpoolseq (1) <br/> {<br/> If (mdriverfd> = 0) {<br/> // XXX ideally, there shoshould be a specific Define for whether we <br/> // have MMAP (or whether we cocould possibly have the kernel module <br/> // availabla). <br/> # If! Defined (have_win32_ipc) <br/> // MMAP the binder, providing a chunk of virtual address space to receive transactions. <br/> mvmstart = MMAP (0, binder_vm_size, prot_read, map_private | map_noreserve, mdriverfd, 0); <br/> If (mvmstart = map_failed) {<br/> // * sigh * <br/> LogE ("using/dev/binder failed: Unable to MMAP transaction memory. /n "); <br/> close (mdriverfd); <br/> mdriverfd =-1; <br/>}< br/> # else <br/> mdriverfd =-1; <br/> # endif <br/>}< br/> If (mdriverfd <0) {<br/> // need to run without the driver, starting our own thread pool. <br/>}< br/>}

Let's take a look at the source code of the open_driver () method.

// File: Frameworks/base/libs/binder/processstate. CPP <br/> static int open_driver () <br/> {<br/> If (gsingleprocess) {<br/> return-1; <br/>}</P> <p> int FD = open ("/dev/binder", o_rdwr); <br/> If (FD> = 0) {<br/> fcntl (FD, f_setfd, fd_cloexec); <br/> int vers; <br/> # If defined (have_android_ OS) <br/> status_t result = IOCTL (FD, binder_version, & vers); <br/> # else <br/> status_t result =-1; <br/> Errno = eperm; <br/> # endif <br/> If (result =-1) {<br/> LogE ("binder IOCTL to obtain version failed: % s ", strerror (errno); <br/> close (FD); <br/> FD =-1; <br/>}< br/> If (result! = 0 | vers! = Binder_current_protocol_version) {<br/> LogE ("binder driver protocol does not match user space protocol! "); <Br/> close (FD); <br/> FD =-1; <br/>}< br/> # If defined (have_android_ OS) <br/> size_t maxthreads = 15; <br/> result = IOCTL (FD, binder_set_max_threads, & maxthreads); <br/> If (result =-1) {<br/> LogE ("binder IOCTL To Set max threads failed: % s", strerror (errno )); <br/>}< br/> # endif </P> <p>} else {<br/> logw ("Opening"/dev/binder 'failed: % s/n ", strerror (errno); <br/>}< br/> return FD; <br/>}

Open_driver () method to open the binder device (/dev/binder), obtain the binder version number, set the maximum number of threads, and return the file descriptor of the binder device. Allocate a 1 MB continuous space (binder_vm_size) to the process in the kernel space, and map it to the user space of the process using the MMAP function. This space is used for transaction interaction data.

Return to the defaservicservicemanager () method. We can see that defaultservicemanager () is the proxy object that calls the getcontextobject method of the processstate object to obtain servicemanager. Let's take a look at the source code of the getcontextobject function:

// File: Frameworks/base/libs/binder/processstate. CPP <br/> sp <ibinder> processstate: getcontextobject (const sp <ibinder> & caller) <br/>{< br/> If (supportsprocesses ()) {<br/> return getstrongproxyforhandle (0); <br/>}else {<br/> return getcontextobject (string16 ("default"), caller ); <br/>}< br/>}

Because the support for the binder Driver (supportsprocesses () function will judge whether the binder driver is enabled to check whether the binder is supported), The getstrongproxyforhandle () method is called with 0 as the parameter to obtain the servicemanager proxy object. Let's take a look at the source code of the getstrongproxyforhandle () method:

// File: Frameworks/base/libs/binder/processstate. CPP <br/> sp <ibinder> processstate: getstrongproxyforhandle (int32_t handle) <br/>{< br/> sp <ibinder> result; </P> <p> automutex _ L (mlock); </P> <p> handle_entry * E = lookuphandlelocked (handle ); </P> <p> If (E! = NULL) {<br/> // we need to create a new bpbinder if there isn't currently one, or we <br/> // are unable to acquire a weak reference on this current one. see comment <br/> // In getweakproxyforhandle () for more info about this. <br/> ibinder * B = e-> binder; <br/> If (B = NULL |! E-> refs-> attemptincweak (this) {<br/> B = new bpbinder (handle); <br/> E-> binder = B; <br/> If (B) E-> refs = B-> getweakrefs (); <br/> result = B; <br/>} else {<br/> // this little bit of nastyness is to allow us to add a primary <br/> // reference to the remote proxy when this team doesn' t have one <br/> // but another team is sending the handle to us. <br/> result. force_set (B); <br/> E-> refs-> decweak (this); <br/>}</P> <p> return result; <br/>}

Getstrongproxyforhandle () first calls the lookuphandlelocked () method to find the list of Service proxy objects maintained by the current process. Let's take a look at the source code of the lookuphandlelocked () method.

// File: processstate. CPP <br/> processstate: handle_entry * processstate: lookuphandlelocked (int32_t handle) <br/>{< br/> const size_t n = mhandletoobject. size (); <br/> If (n <= (size_t) handle) {<br/> handle_entry E; <br/> E. binder = NULL; <br/> E. refs = NULL; <br/> status_t err = mhandletoobject. insertat (E, N, handle + 1-N); <br/> If (ERR <no_error) return NULL; <br/>}< br/> return & mhandletoobject. edititemat (handle); <br/>}

Mhhandletoobject is a vector of elements of the handle_entry type. It maintains the list of proxy objects of the current process. Its Index is the value of each proxy object handle. For example, if the handle of servicemanager must be 0, it is the first item in the list. If the value of the handle to be queried is greater than or equal to the size of the current list, it means that the Service proxy object entry to be created has not been created in the current process, then a new item needs to be inserted. The current list size is N, the index from 0 to the N-1, if the index to be queried is handle, then the handle-(N-1) item is inserted. If the proxy object entry has been created, you can directly return its reference.

Note: Here, "CREATE" only creates the corresponding entry (E. Binder = NULL; E. refs = NULL;) in the list. The real proxy object will not be created later.

Now return to the getstrongproxyforhandle () method. If the proxy object has not been created (e-> binder = NULL), create one and update the corresponding records in the proxy Object List.

Let's take a look at what the bpbinder class constructor has done.

// File: Frameworks/base/libs/binder/bpbinder. CPP <br/> bpbinder: bpbinder (int32_t handle) <br/>: mhandle (handle) <br/>, malive (1) <br/>, mobitssent (0) <br/>, mobituaries (null) <br/> {<br/> logv ("creating bpbinder % P handle % d/N", this, mhandle ); </P> <p> extendobjectlifetime (object_lifetime_weak); <br/> ipcthreadstate: Self ()-> incweakhandle (handle); <br/>}

Here, the incweakhandle () method of the ipcthreadstate class is called to increase the reference count. Let's look at the source code of the incweakhandle () method.

// File: Frameworks/base/libs/binder/ipcthreadstate. CPP <br/> void ipcthreadstate: incweakhandle (int32_t handle) <br/>{< br/> log_remoterefs ("ipcthreadstate: incweakhandle (% d)/n ", handle); <br/> MOUT. writeint32 (bc_increfs); <br/> MOUT. writeint32 (handle); <br/>}

Here, incweakhandle () adds a bc_increfs command in the output buffer.

If the proxy object corresponding to the handle has been created, the reference count is increased. Result is a strong pointer to the ibinder type. The Android system defines two smart pointers: SP (strong pointer) and WP (weak pointer. Note that the operator "=" has been overloaded. Force_set is a refbase Class Optimization Method for The processstate class. Let's take a look at its source code.

// File: Frameworks/base/include/utils/refbase. h <br/> template <typename T> <br/> void sp <t>: force_set (T * Other) <br/>{< br/> Other-> forceincstrong (this); <br/> m_ptr = Other; <br/>}

After the reference count is set, the getstrongproxyforhandle () method returns the handle of the proxy object. Next, we will use interface_cast to convert it to the iservicemanager type. Let's see how this conversion is implemented.

Gdefaservicservicemanager = interface_cast <iservicemanager> (<br/> processstate: Self ()-> getcontextobject (null); <br/>

Interface_cast <iservicemanager> actually calls the iservicemanager. asinterface method:

// File: Frameworks/base/include/binder/iinterface. h <br/> template <typename interface> <br/> inline sp <interface> interface_cast (const sp <ibinder> & OBJ) <br/>{< br/> return interface: asinterface (OBJ); <br/>}

Check the source file of iservicemanager. It seems that the asinterface method is not defined. Don't worry. Let's take a look at the definition of iservicemanager:

// File: Frameworks/base/include/binder/iservicemanager. h <br/> class iservicemanager: Public iinterface <br/>{< br/> Public: <br/> declare_meta_interface (servicemanager ); </P> <p>/** <br/> * retrieve an existing service, blocking for a few seconds <br/> * if it doesn't yet exist. <br/> */<br/> virtual sp <ibinder> getservice (const string16 & name) const = 0; </P> <p>/** <br/> * retrieve an existing service, non-blocking. <br/> */<br/> virtual sp <ibinder> checkservice (const string16 & name) const = 0; </P> <p>/** <br/> * register a service. <br/> */<br/> virtual status_t addservice (const string16 & name, <br/> const sp <ibinder> & Service) = 0; </P> <p>/** <br/> * return list of all existing services. <br/> */<br/> virtual vector <string16> listservices () = 0; </P> <p> Enum {<br/> get_service_transaction = ibinder :: first_call_transaction, <br/> check_service_transaction, <br/> add_service_transaction, <br/> list_services_transaction, <br/>}; <br/> };

The macro declare_meta_interface is defined in the iinterface. h header file as follows:

// File: Frameworks/base/include/binder/iinterface. h <br/> # define declare_meta_interface (Interface)/<br/> static const string16 descriptor; /<br/> static sp <I # interface> asinterface (const sp <ibinder> & OBJ);/<br/> virtual const string16 & getinterfacedescriptor () const; /<br/> I # interface ();/<br/> virtual ~ I ## interface ();/

Here, we finally find the asinterface method declaration. This method is implemented through the implement_meta_interface macro in the iservicemanager. cpp file.

// File: Frameworks/base/include/binder/iservicemanager. cpp <br/> implement_meta_interface (servicemanager, "android. OS. iservicemanager ");

The implement_meta_interface macro is defined as follows:

// File: Frameworks/base/include/binder/iinterface. h <br/> # define implement_meta_interface (interface, name)/<br/> const string16 I # interface: Descriptor (name ); /<br/> const string16 & I # interface: getinterfacedescriptor () const {/<br/> return I # interface: descriptor; /<br/>}/ <br/> sp <I # interface> I # interface: asinterface (const sp <ibinder> & OBJ) /<br/>{/ <br/> sp <I # interface> intr; /<Br/> If (OBJ! = NULL) {/<br/> intr = static_cast <I # interface *> (/<br/> obj-> querylocalinterface (/<br/> I # interface:: descriptor ). get ();/<br/> If (intr = NULL) {/<br/> intr = new BP # interface (OBJ ); /<br/>}/ <br/> return intr;/<br/>}/ <br/> I # interface :: I # interface () {}/ <br/> I # interface ::~ I ## interface (){}/

The final result after the above macros are displayed is,

Sp <iservicemanager> iservicemanager: asinterface (const sp <ibinder> & OBJ) <br/>{< br/> sp <iservicemanager> intr; <br/> If (OBJ! = NULL) {<br/> intr = static_cast <iservicemanager *> (obj-> querylocalinterface (<br/> iservicemanager: descriptor ). get (); <br/> If (intr = NULL) {<br/> intr = new bpservicemanager (OBJ ); <br/>}< br/> return intr; <br/>}

It can be seen that the iservicemanager: asinterface () function will eventually use an ibinder object to create a bpservicemanager object and return it.

Now, let's summarize the whole process of getting the servicemanager proxy object:

Defaservicservicemanager (); // gets the servicemanager proxy object

{

Interface_cast <iservicemanager> (processstate: Self ()-> getcontextobject (null); // converts the returned bpbinder-type proxy object to servicemanager-type proxy object

{

Getstrongproxyforhandle (0); // The proxy object of servicemanager can be obtained with the parameter 0.

{

Lookuphandlelocked (0 );

B = new bpbinder (0); // create a proxy object

Returns the proxy object generated by handle.

}

Returns the proxy object generated by handle.

}

Returns the proxy object converted to servicemanager.

}

 

Finally, we can answer Question 1:

Q: What are the tasks completed by defaservicservicemanager () and what are the results returned by defaservicservicemanager?

A: If the current process has generated a servicemanager proxy object, this function returns a reference to it. If the current process has not yet generated a servicemanager proxy object, create it, and return a reference to it.

 

In the next article, we will thoroughly analyze why the reference to the getservice method can be called to obtain the reference of the proxy object of exampleservice.

Related Article

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.