Research on Binder Mechanism of Android

Source: Internet
Author: User
Tags uppercase letter mremote

(1) Overview
Android's binder Mechanism provides a method for inter-process communication, so that a process can call the functions provided by another process in a way similar to a remote process call. The binder mechanism is provided in both the Java environment and the C/C ++ environment.
In the android code, the binder with C/C ++ includes some types and interface definitions and implementations. The relevant code is in the following files:

  1. Frameworks/base/include/binder/IInterface. h
  2. Frameworks/base/include/binder/Binder. h
  3. Frameworks/base/include/binder/BpBinder. h
  4. Frameworks/base/include/binder/IBinder
  5. Frameworks/base/include/binder/Parcel. h
  6. Frameworks/base/include/binder/IPCThreadState. h
  7. Frameworks/base/include/binder/ProcessState. h
  8. Frameworks/base/libs/binder/Binder. cpp
  9. Frameworks/base/libs/binder/BpBinder. cpp
  10. Frameworks/base/libs/binder/IInterface. cpp
  11. Frameworks/base/libs/binder/IPCThreadState. cpp
  12. Frameworks/base/libs/binder/Parcel. cpp
  13. Frameworks/base/libs/binder/ProcessState. cpp

Copy code

To understand the relationships between these classes and interfaces and the implementation mechanism of the binder, it is best to use an example for research. The example I selected is the implementation of the media player that comes with android. The Media Player Code is in the following directories:

  1. Frameworks/base/include/media
  2. Frameworks/base/media

Copy code

Use the reverse engineering function of startUML to analyze the above Code and sort out the code to obtain the following class diagram (click to view the original size image ).

Upload

Download Attachment(230.18 KB)

Android's media playback function is divided into two parts: one is the media playback application and the other is the MediaServer, Which is started by init when the system is started. For details, see init. rc file ). These two parts run in different processes respectively. Media Playback applications include Java programs and some C ++ code. The media playback service is a C ++ code, and an external module opencore must be called to implement real media playback. Media Playback applications and media playback services must use the binder Mechanism to call each other. These calls include:
(1) The media playback application sends control commands to the media playback service.
(2) The media playback Service sends an event notification (Y) to the media playback application)
The media playback Service provides multiple external interfaces. The preceding figure shows two interfaces: IMediaService and IMediaPlayer. IMediaplayer is used to create and manage playback instances, while the IMediaplayer interface is the playback interface, it is used to control the playback and playback of specified media files.
In the figure above, there is also an interface provided by the media playback application to the media playback service: IMediaPlayerClient, which is used to receive notify.
Because these interfaces need to be called across processes, the binder mechanism is required. Each interface consists of two parts: one is the real implementation of interface functions (BnInterface), which runs in the interface providing process; the other is the interface's proxy (BpInterface ), this part runs in the process that calls the interface. Binder is used to establish a connection between the two parts. Is an overview of the entire player.

Upload

Download Attachment(39.27 KB)

The Media Player is more complex and implements three interfaces in total. However, to understand the binder Mechanism, you only need to study one of the interfaces. Select the IMediaPlayerService interface.
The IMediaPlayerService interface includes six function functions: create (url), create (fd), decode (url), decode (fd), createMediaRecord (), and createMetadataRetriever (). Here we will not introduce what these functions do. We only focus on how to provide these function interfaces through the binder.
(2) Interface Definition
(1) define interface classes

First, define the IMediaPlayerService class, which is an interface class (C ++ should be called pure virtual class ). This interface class is defined in the file frameworks/base/include/media/IMediaPlayerService. h. The Code is as follows:

  1. Class IMediaPlayerService: public IInterface
  2. {
  3. Public:
  4. DECLARE_META_INTERFACE (MediaPlayerService );
  5. Virtual sp <IMediaRecorder> createMediaRecorder (pid_t pid) = 0;
  6. Virtual sp <imediametadataretriever> createmetadataretriever (pid_t PID) = 0;
  7. Virtual sp <imediaplayer> Create (pid_t PID, const sp <imediaplayerclient> & client, const char * URL) = 0;
  8. Virtual sp <imediaplayer> Create (pid_t PID, const sp <imediaplayerclient> & client, int FD, int64_t offset, int64_t length) = 0;
  9. Virtual sp <imemory> decode (const char * URL, uint32_t * psamplerate, int * pnumchannels, int * pformat) = 0;
  10. Virtual sp <imemory> decode (int fd, int64_t offset, int64_t length, uint32_t * psamplerate, int * pnumchannels, int * pformat) = 0;
  11. };

Copy code

As you can see, this interface class defines the six function interfaces that IMediaPlayerService needs to provide. Because it is an interface class, it is defined as a pure virtual function. Note that the name of this interface class must start with an uppercase letter I.

Focus on a macro definition prior to these functions: DECLARE_META_INTERFACE (MediaPlayerService ). This macro definition must be available, which encapsulates some class member variables and member functions required to implement the binder. These member functions can create a proxy for a binder implementation. This macro is defined in frameworks/base/include/utils/IInterface. h and will be discussed later. The macro-defined parameter must be the name of the interface class to remove the remainder of the letter I.
In addition, we can see that the returned values of the functions defined in the interface class are in the form of sp <xxxx>, which looks a little weird. Sp is a template class defined in android. It is used to implement the smart pointer function. Sp <IMediaPlayer> is the intelligent pointer of IMediaPlayer. You can simply regard it as the pointer definition in Standard C ++, that is, IMediaPlayer.

(2) define and implement the binder class

The binder class includes two types: interface implementation class and interface proxy class. The interface proxy class inherits from BpInterface, and the interface implementation class inherits from BnInterface. Both base classes are template classes that encapsulate the inter-process communication mechanism of the binder, so that users do not need to pay attention to the underlying communication implementation details.
For the IMediaPlayerService interface, the binder interface implementation class is BnMediaPlayerService, and the interface proxy class is BpMediaPlayerService. Note that the names of these two classes are strictly required. They must start with Bn and Bp, and the latter part must be the names of the previously defined interface classes to remove the letter 'I '. For example, if the interface class defined above is IMediaPlayerService and the letter I is removed, it is MediaPlayerService. Therefore, the names of the two binder classes are BnMediaPlayerService and BpMediaPlayerService. Why is there such a requirement? The reason is in the macro definition DECLARE_META_INTERFACE () and another macro definition IMPLEMENT_META_INTERFACE. If you are interested, let's take a look at these two macro definitions in the file frameworks/base/include/utils/IInterface. h.
BpMediaPlayerService is a final implementation class. Define and implement it in the file frameworks/base/media/libmidia/IMediaPlayerService. cpp. Before reading the BpMediaPlayerService code, let's take a look at an enumeration definition at the beginning of the IMediaPlayerService. cpp file:

  1. Enum {
  2. Create_url = ibinder: first_call_transaction,
  3. Create_fd,
  4. DECODE_URL,
  5. DECODE_FD,
  6. CREATE_MEDIA_RECORDER,
  7. CREATE_METADATA_RETRIEVER,
  8. };

Copy code

These six enumeration definitions correspond to the six functional functions provided by the IMediaPlayerService interface, which can be called the functional code of these functional functions. RPC is used between processes to identify the function to be called. If you do not want to define these enumerated values, you can directly write 1, 2, 3, 4, 5, and 6 where you need them later ...... What does a suitable programmer do?
Next, let's take a look at the bpmediaplayerservice code.
(3) bpmediaplayerservice code analysis

  1. Class BpMediaPlayerService: public BpInterface <IMediaPlayerService>
  2. {
  3. Public:
  4. BpMediaPlayerService (const sp <IBinder> & impl): BpInterface <IMediaPlayerService> (impl)
  5. {
  6. }
  7. //...... Omitted
  8. Virtual sp <IMediaPlayer> create (pid_t pid, const sp <IMediaPlayerClient> & client, const char * url)
  9. {
  10. Parcel data, reply;
  11. Data. writeInterfaceToken (IMediaPlayerService: getInterfaceDescriptor ());
  12. Data. writeint32 (PID );
  13. Data. writestrongbinder (client-> asbinder ());
  14. Data. writecstring (URL );
  15. Remote ()-> transact (create_url, Data, & reply );
  16. Return interface_cast <imediaplayer> (reply. readstrongbinder ());
  17. }
  18. //...... Omitted
  19. };

Copy code

First, we can see that this class inherits from the template class bpinterface, and the specified type is the interface class imediaplayerservice. The bpinterface template class is defined in the file iinterface. h. After looking at the definition of bpinterface, we can see that after bpmediaplayerservice is defined like this, it actually indirectly inherits the imediaplayerservice, thus providing the interface functions defined by the imediaplayerservice interface. Bpmediaplayerservice needs to implement these interface functions. After a simple constructor, it is the implementation of these interface functions. We can see that the implementation methods of all interface functions are consistent, and the parameters are still given to the Implementation class of the binder through the mechanism provided by the binder, and the return value is obtained. This is why this class becomes a proxy class. The following describes the next interface function. The create (URL) function is selected here ).

  1. Virtual sp <imediaplayer> Create (pid_t PID, const sp <imediaplayerclient> & client, const char * URL)
  2. {
  3. Parcel data, reply;
  4. Data. writeinterfacetoken (imediaplayerservice: getinterfacedescriptor ());
  5. Data. writeint32 (PID );
  6. Data. writeStrongBinder (client-> asBinder ());
  7. Data. writeCString (url );
  8. Remote ()-> transact (CREATE_URL, data, & reply );
  9. Return interface_cast <IMediaPlayer> (reply. readStrongBinder ());
  10. }

Copy code

The parameter of this interface function specifies a URL. The function creates a player instance for this URL to play the URL.
The function first defines two local variables data and reply. The types of the variables are parcel. Parcel is a class defined for data transmission through binder communication. It encapsulates multiple types of data and provides multiple Data Reading and Writing functions, it is used for writing and reading data of various types. supported data types include both simple data types and objects. The variable data defined here is used to encapsulate the input parameters required for the CREATE () function call, while reply is used to encapsulate the returned data of the Call (including the output parameter values and function return values ).
The function first writes various types of data to data. The first write is a description string of the interface. The binder implementation class uses this string to verify the interface to prevent call errors. This string can also be left empty. If this string is left empty, do not verify it in the binder implementation class. The input parameters required by the interface function are written after the description string. It should be noted that Pacel provides a data storage method that stores data first-in-first-out, that is, the data write sequence and read sequence must be strictly consistent; otherwise, errors may occur.
After data writing is completed, the function calls remote ()-> transact () to complete binder communication. The first parameter of the transact () function is the Function Code mentioned above. The function of transact () is to pass data in data to the binder implementation class. After the function is called, reply will contain the returned data. First, let's look at the remote () member functions. As mentioned above, BpMediaPlayerService indirectly inherits the IMediaPlayerService interface class by inheriting the BpInterface template class. In fact, the BpInterface class is a multi-inheritance subclass with two parent classes, another parent class is BpRefbase (frameworks/base/include/utils/Binder. h ). Remote () is a member function inherited from the BpRefBase class, which returns a private property mRemote defined in the BpRefBase class. MRemote is a reference to an object of the subclass BpBinder of the IBinder Interface Class (refer to the class relationship diagram above ). The transact () function is defined in the IBinder Interface Class (frameworks/base/include/utils/Binder. h), and implement (frameworks/base/include/utils/BpBinder. h. frameworks/base/libs/utils/BpBinder. cpp ). In the transact () function, the transact () function of the IPCThreadState class is called, and inter-process communication is realized through the android shared memory driver in the Lniux kernel. However, we will not talk about these details here. Here, BpBinder class objects are a key and one of the core implementations of the Binder proxy. The BpBinder class can be considered as a communication handle (similar to a socket in Network Programming), used to implement inter-process communication. Next, we need to study where the BpBinder Class Object (that is, the value of the mRemote member variable) comes from.
Let's look back at the BpMediaPlayerService Constructor (see the previous Code ). The constructor parameter is a reference to an IBinder object. The mRemote value is the object passed in here. So how does this object come from? To clarify this point, you need to find the code for creating an BpMediaPlayerService instance. This Code follows the definition code of this class. Continue to check the IMediaPlayerService. cpp file. After the BpMediaPlayerService class definition, the following code is displayed:

  1. IMPLEMENT_META_INTERFACE (MediaPlayerService, "android. hardware. IMediaPlayerService ");

Copy code

This line of code calls a macro definition IMPLEMENT_META_INTERFACE (). This macro definition echoes the previously mentioned DECLARE_META_INTERFACE. You can see the name. The IMPLEMENT_META_INTERFACE () macro is the specific implementation of the member function defined by DECLARE_META_INTERFACE. The first parameter of this macro must be exactly the same as the DECLARE_META_INTERFACE () parameter. The second parameter is the description string of the interface (this string has been mentioned earlier ). It is not important to describe the string. What is important is a static member function asInterface () defined in the macro (). The class instance of BpMediaPlayerService is created in the static member function asInterface () of IMediaPlayerService. an inline function interface_cast () is defined in IInterface. h, which encapsulates this member function. It is easy to see through the code that the parameters of the BpMediaPlayerService constructor are passed in through the interface_cast () parameter.
Well, let's see where interface_cast () is called and what its parameters are. Find the frameworks/base/media/libmedia/IMediaDeathNotifier. cpp file, and the IMediaDeathNotifier: getMediaPlayerService () implementation code:

  1. IMediaDeathNotifier: getMediaPlayerService ()
  2. {
  3. LOGV ("getMediaPlayerService ");
  4. Mutex: Autolock _ l (sServiceLock );
  5. If (sMediaPlayerService. get () = 0 ){
  6. Sp <IServiceManager> sm = defaultServiceManager ();
  7. Sp <IBinder> binder;
  8. Do {
  9. Binder = sm-> getService (String16 ("media. player "));
  10. If (binder! = 0 ){
  11. Break;
  12. }
  13. LOGW ("Media player service not published, waiting ...");
  14. Usleep (500000); // 0.5 s
  15. } While (true );
  16. If (sDeathNotifier = NULL ){
  17. SDeathNotifier = new DeathNotifier ();
  18. }
  19. Binder-> linkToDeath (sDeathNotifier );
  20. SMediaPlayerService = interface_cast <IMediaPlayerService> (binder );
  21. }
  22. LOGE_IF (sMediaPlayerService = 0, "no media player service !? ");
  23. Return sMediaPlayerService;
  24. }

Copy code

Let's take a look at the red font section in the above Code. Based on the previous analysis, we can see that the object instance of the BpBinder class is obtained from the getService () function of the android service manager. Further, we will find the following code:

  1. {
  2. Parcel data, reply;
  3. Data. writeInterfaceToken (IServiceManager: getInterfaceDescriptor ());
  4. Data. writeString16 (name );
  5. Remote ()-> transact (CHECK_SERVICE_TRANSACTION, data, & reply );
  6. Return reply. readStrongBinder ();
  7. }

Copy code

The Android service manager is a separate process and provides external interfaces. The meaning of this Code is to call the checkService () interface function of the Service Manager through the interface proxy of the Android Service Manager to find the specified service (the above is to find media. player Service), returns an object instance of the BpBinder class after the search is successful, which is used by the IMediaPlayerService proxy. This object BpBinder is created in the Parcel: readStrongBinder () function. So how was it created? There is no need to trace the ServiceManager implementation code here. After all, we just want to know how BpBinder objects are created. Let's take another example. Back to the implementation of the BpMediaPlayerService: create () function, is it very familiar. Yes. A BpBinder class object is also created in that function, which is used by the IMediaPlayer interface proxy. Although the interfaces are different, the creation principle is the same. Let's continue. Next we should go to another class of binder-implementation class code.

(3) BnMediaPlayerService code analysis
The BnMediaPlayerService class is defined in the file frameworks/base/include/media/IMediaPlayService. h. The implementation is the same as that of BpMediaPlayerService in the file frameworks/base/media/libmidia/IMediaPlayerService. cpp. The code for class definition is as follows:

  1. Class BnMediaPlayerService: public BnInterface <IMediaPlayerService>
  2. {
  3. Public:
  4. Virtual status_t ontransact (uint32_t code, const parcel & Data, parcel * reply, uint32_t flags = 0 );
  5. };

Copy code

This class is inherited from the BnInterface template class and the constraint type is IMediaPlayerService. Take a look at the definition of the BnInterface template class (IInterface. h) to know that BnMediaPlayerService indirectly inherits the IMediaPlayerService interface class. However, the BnInterface class does not implement the six interface functions defined by IMediaPlayerService. Therefore, the BnInterface is a pure virtual class. These interfaces must be implemented in the BnMediaPlayerService subclass. This subclass is MediaPlayerService (frameworks/base/media/libmidiaservice/MediaPlayerService. h, frameworks/base/media/libmidiaservice/MediaPlayerService. cpp ). In the onTransact () member function of BnMediaPlayerService, you need to call these six interface functions. BnMediaPlayerService mainly defines and implements the onTransact () function. When the transact () function is called on the proxy side, the onTransact () function on this side will be called. The implementation code of BnMediaPlayerService is as follows:

  1. # Define check_interface (interface, data, reply )/
  2. Do {If (! Data. enforceinterface (interface: getinterfacedescriptor ())){/
  3. Logw ("Call incorrectly routed to" # Interface );/
  4. Return permission_denied ;/
  5. } While (0)
  6. Status_t bnmediaplayerservice: ontransact (
  7. Uint32_t code, const parcel & Data, parcel * reply, uint32_t flags)
  8. {
  9. Switch (CODE ){
  10. Case create_url :{
  11. CHECK_INTERFACE (IMediaPlayerService, data, reply );
  12. Pid_t pid = data. readInt32 ();
  13. Sp <IMediaPlayerClient> client = interface_cast <IMediaPlayerClient> (data. readStrongBinder ());
  14. Const char * url = data. readCString ();
  15. Sp <IMediaPlayer> player = create (pid, client, url );
  16. Reply-> writeStrongBinder (player-> asBinder ());
  17. Return NO_ERROR;
  18. } Break;
  19. //...... Omitted
  20. Default:
  21. Return BBinder: onTransact (code, data, reply, flags );
  22. }
The first step of copying code is a macro definition CHECK_INTERFACE (). The macro definition is used to check the interface description string, which has been mentioned earlier and does not need to be detailed. Then the onTrasact () function is implemented. The structure of this function is also very simple, that is, different function calls are executed based on the value of the parameter code. The value of code is the interface function code mentioned above. In addition to code, the function parameters also include two Parcel objects, data and reply, which are used to transmit input parameters and returned data respectively. They correspond to the parameters of the transact () function. Another parameter flag is not used here. The example create (url) corresponding to the interface function we selected earlier takes a look at the corresponding implementation here:
  1. Case CREATE_URL :{
  2. CHECK_INTERFACE (IMediaPlayerService, data, reply );
  3. Pid_t pid = data. readInt32 ();
  4. Sp <IMediaPlayerClient> client = interface_cast <IMediaPlayerClient> (data. readStrongBinder ());
  5. Const char * url = data. readCString ();
  6. Sp <IMediaPlayer> player = create (pid, client, url );
  7. Reply-> writeStrongBinder (player-> asBinder ());
  8. Return NO_ERROR;
  9. }

Copy code

First, retrieve the input parameters from the data object in sequence, call the interface function create () (implemented in the subclass MediaPlayerService), and write the returned data to reply. After this function is returned, the proxy's transact () will also be returned.
So how is the onTransact () function called? You can view the definition of the BnInterface template class. This class is also a multi-inheritance class, and the other parent class is BBinder (frameworks/base/include/utils/Binder. h, frameworks/base/libs/utils/Binder. cpp ). The BBinder class inherits from IBinder and also implements the transact () function. In this function, the onTransact () function is called. The transact () function of the BBinder object is called in the executeCommand () member function of the IPCThreadState class. This involves lower-layer implementation, which is not mentioned here.
The above Code also has something to do with the BpBinder object created previously mentioned. Looking at the red font, the create () function call will create a subclass object of the IMediaPlayer interface class. This object is actually MediaPlayerService :: client class (let's take a look at the definition of MediaPlayerService), while MediaPlayerService: the Client class inherits from the BnMediaPlayer class, similar to the BnMediaPlayerService class, bnMediaPlayer is actually a binder implementation class (a subclass of BBinder and then a subclass of IBinder ). In the above Code, this object is written to reply through the writeStrongBinder () function of Parcel, and on the proxy side, the object of BpBinder can be obtained by reading through the readStrongBinder () function of Parcel. The specific creation process of the class has been encapsulated in the definition of the Parcel class.

(4) real implementation of interface functions
Now the two binder classes have been defined. The following is the real implementation of the imediaplayerservice interface function. As mentioned above, these functions are implemented in the mediaplayerservice class. This class inherits from bnmediaplayerservice and indirectly inherits the six function functions defined by the imediaplayerservice interface class. You only need to implement these six function functions in the normal way, of course, a lot of other things are required to implement these six functions. However, these specific implementation methods have nothing to do with the Binder Mechanism.
A static function instantiate () is defined in the mediaplayerservice class. In this function, an object instance of mediaplayerservice is created and registered to the Service Manager. In this way, you can obtain the imediaplayerservice proxy object from the Service Manager. This instantiate () is called in the main () function of the mediaserver program.

  1. Void MediaPlayerService: instantiate (){
  2. DefaultServiceManager ()-> addService (
  3. String16 ("media. player"), new MediaPlayerService ());
  4. }

Copy code

(3) Summary
To sum up. It is a hierarchical model of the binder mechanism.
Upload

Download Attachment(10.16 KB)

If a service needs to provide cross-process interfaces through the Binder Mechanism, do the following.
(1) The first step is to define an interface class that inherits from the iinterface for this interface, which is called imyservice.
(2) Step 2: define two binder classes, one of which is the proxy class bpmyservice and must inherit from the bpinterface. The other is the implementation class bnmyservice, which must inherit from the bninterface.
(3) Step 3: Define the subclass of bnmyservice. This subclass can be any name, for example, myservice, and all functions provided by the actually implemented interface in it.
(4) Step 4: Create a MyService instance and register it with the Service Manager (such as IMediaPlayerService). You can also create it in functions of other interfaces (such as IMediaPlayer ).
From: http://ytydyd.blog.sohu.com/139026338.html for android2.3 some modifications, has been registered as this color.

Research on the binder Mechanism of android 1 (C ++)
Http://www.eoeandroid.com/forum-viewthread-tid-53565-fromuid-93074.html
Research on the binder Mechanism of android 2 (C ++ part)
Http://www.eoeandroid.com/forum-viewthread-tid-53579-fromuid-93074.html

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.