An explanation of the binder of the Android IPC mechanism

Source: Internet
Author: User
Tags mremote

IPC (inter-process communication, cross-process communication) refers to the process of data exchange between two processes, so we first have to understand what a process is and what a thread is.

Process: A process is an instance of a running program, which emphasizes the concept of dynamics more than a program, a process is a container for threads, and a process can contain multiple threads but at least one thread. Process is the basic unit of task scheduling and the allocation unit of system resources.

Thread: A thread is an execution path in a process that can only be subordinate to a process, in a multithreaded operating system or programming language (such as Java), where a thread is a unit of task scheduling, but it is not a unit of system resource allocation, and the thread fully inherits the resources that the parent process occupies, but when it executes, Also have their own operating site, such as the value of the PC register, stack space and so on.

For information on process and thread memory resources, see my blog: http://blog.csdn.net/htq__/article/details/50822582.

IPC mechanism is not unique to Android, any operating system requires an IPC mechanism, such as Linux can be named pipes, shared main memory, semaphores, sockets, Message Queuing and other ways to implement the IPC mechanism, Android is based on the Linux kernel, But wirelessly's IPC mechanism is not exactly the same as Linux, such as the binder mechanism is a feature of the IPC in Android, this IPC mechanism does not exist in Linux. This blog will explain in detail the binder mechanism of wirelessly.

In Android development binder is used primarily in the service, including Aidl and Messenger, and the bottom of Messenger is still aidl, for these content, readers can see my blog: Click to open the link. So this blog will take Aidl as an example to explain in detail the IPC principle of binder.


Start by creating a Aidl Java package that creates three files in the package Book.java,book.aidl and Ibookmanager.aidl code as follows:

public class Book implements parcelable {//book.java public int bookId;    Public String BookName;        Public book () {} public book (int bookId, String bookname) {this.bookid = BookId;    This.bookname = BookName;    } public int describecontents () {return 0;        } public void Writetoparcel (Parcel out, int flags) {out.writeint (bookId);    Out.writestring (BookName); public static final parcelable.creator<book> Creator = new parcelable.creator<book> () {public Boo        K Createfromparcel (Parcel in) {return new book (in);        } public book[] NewArray (int size) {return new book[size];    }    };        Private book (Parcel in) {bookId = In.readint ();    BookName = In.readstring ();    } @Override Public String toString () {return String.Format ("[Bookid:%s, bookname:%s]", BookId, BookName);  }}parcelable book;//book.aidlinterface Ibookmanager {//ibookmanager.aidl   List<book> getbooklist (); void Addbook (in book book);}

Where Book.java is a Java class that represents library information, it implements the Parcelable interface, Book.aidl is the book class declaration in Aidl, Ibookmanager.aidl is an interface we define, note that although the books class and the Ibookmanager class bit In the same package, but you still need to import the book class in the Ibookmanager.aidl file, which is the difference between the Aidl file and the normal Java class file.

After we have defined the above file, eclipse will automatically generate a Java class Ibookmanager.java for us in the project's Gen directory, which corresponds to the Ibookmanager.aidl file, let's take a look at its source code:

Public interface Ibookmanager extends android.os.iinterface{/** local-side IPC implementation stub class. */public Static Abstract class Stub extends Android.os.Binder implements com.test.aidl.ibookmanager{private static final Java.lang.String descriptor = "Com.test.aidl.IBookManager";/** Construct the stub at attach it to the interface. */public Stub () {this.attachinterface (this, descriptor);} /** * Cast an IBinder object to an Com.test.aidl.IBookManager interface, * Generating a proxy if needed.    */public static Com.test.aidl.IBookManager asinterface (Android.os.IBinder obj) {if ((Obj==null)) {return null;  }android.os.iinterface iin = obj.querylocalinterface (descriptor);        if (((iin!=null) && (iin instanceof Com.test.aidl.IBookManager)) {return ((Com.test.aidl.IBookManager) iin);} return new Com.test.aidl.IBookManager.Stub.Proxy (obj);     } @Override Public Android.os.IBinder Asbinder () {return this; } @Override public boolean ontransact (int code,Android.os.Parcel data, android.os.Parcel reply, int flags) throws Android.os.remoteexception{switch (code) {Case INTER          Face_transaction: {reply.writestring (descriptor);      return true; } case transaction_getbooklist: {data.enforceinterface (descriptor);java.util.list<com.test.aidl.book> _re      Sult = This.getbooklist (); Reply.writenoexception (); reply.writetypedlist (_result); return true; } case Transaction_addbook: {data.enforceinterface (descriptor); Com.test.aidl.Book _arg0;if ((0!=data.readint ())) {_arg0 = com.test.aidl.Book.CREATOR.createFromParcel (data);} else {_arg0 = null;}      This.addbook (_arg0); reply.writenoexception (); return true;} }return super.ontransact (Code, data, reply, flags);}       private static class Proxy implements com.test.aidl.ibookmanager{private Android.os.IBinder mremote;       Proxy (Android.os.IBinder remote) {mremote = remote; } @Override Public Android.os.IBinder Asbinder () {RetuRN Mremote; } public java.lang.String Getinterfacedescriptor () {return descriptor;} @Override public java.util.list<com.test.aidl.book> getbooklist () throws Android.os.RemoteException {Android. Os. Parcel _data = Android.os.Parcel.obtain (); Android.os.Parcel _reply = Android.os.Parcel.obtain ();java.util.list< Com.test.aidl.book> _result;try {_data.writeinterfacetoken (descriptor); Mremote.transact (Stub.TRANSACTION_ Getbooklist, _data, _reply, 0); _reply.readexception (); _result = _reply.createtypedarraylist ( Com.test.aidl.Book.CREATOR);} finally {_reply.recycle (); _data.recycle ();}     return _result; } @Override public void Addbook (Com.test.aidl.Book book) throws android.os.remoteexception{Android.os.Parcel _data = and   Roid.os.Parcel.obtain ();  Android.os.Parcel _reply = Android.os.Parcel.obtain ();   try {_data.writeinterfacetoken (descriptor);      if ((Book!=null)) {_data.writeint (1);      Book.writetoparcel (_data, 0);   } else {_data.writeint (0); } mReMote.transact (Stub.transaction_addbook, _data, _reply, 0);  _reply.readexception ();     } finally {_reply.recycle ();     _data.recycle (); }}}static Final int transaction_getbooklist = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACT Ion_addbook = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 1);p ublic java.util.list<com.test.aidl.book> Getbooklist () throws Android.os.remoteexception;public void Addbook (Com.test.aidl.Book book) throws Android.os.RemoteException;}
You can see that the Ibookmanager file that the system automatically created for us is still an interface that inherits from Android.os.IInterface. An abstract static class stub is created inside it, and it inherits from the Binder class implementing the Ibookmanager interface at the same time (but not the method in the interface, because the method in the interface is implemented when we create a binder class inside it when we create a service. So the stub still belongs to an abstract class).


Let's first comb the contents of the Ibookmanager interface, and we can see that the first two methods of declaration getbooklist and Addbook are included, Obviously these two methods are the two methods we declared in the Ibookmanager.aidl file, and it also defines two integer IDs to identify the two methods, which are used to determine which method the client is requesting in the Transact process of the method of its internal proxy class proxy. An internal class stub is also included, which is a binder class that defines an internal class proxy in this stub class.


Here are some important methods in the above code:

public static Com.test.aidl.IBookManager asinterface (Android.os.IBinder obj) {   if ((Obj==null)) {    return null;    }android.os.iinterface iin = obj.querylocalinterface (descriptor);  if ((iin!=null) && (iin instanceof Com.test.aidl.IBookManager)) {//This means that the client is in the same process as the server and returns the IInterface object directly  return ((Com.test.aidl.IBookManager) iin);}        return new Com.test.aidl.IBookManager.Stub.Proxy (obj); <span style= "font-family:arial, Helvetica, Sans-serif;" >//This indicates that the client is not in the same process as the server, and returns the proxy class proxy object </span>}
Asinterface is exactly one of the first methods we use when using serviceconnection in a bindservide component, and we can see that in the method first through Obj.querylocalinterface (descriptor) Gets the IInterface object based on the parameters passed in, and then determines whether the object is a Ibookmanager class, or if the object is returned directly, indicating that the client and the server are in the same process, that is, the local service is bound. That's what we call Binder objects in Serviceconnection's onserviceconnected.

public void onserviceconnected (componentname name, IBinder service) {                Mybinder = (myservice.mybinder) service;   The binding is local Service             mybinder.dosomething ();            }  


Otherwise, the internal proxy object IBookManager.Stub.Proxy (obj) of the Ibookmanager class is returned, which means that the client and the server are in different processes, and the method that the client invokes will be the method defined in the proxy class. Instead of directly invoking the method in the Ibookmanager.aidl file that is implemented in the service. That is, the binding is the remote service, that is, in Serviceconnection's onserviceconnected we are so called Binder object

public void onserviceconnected (componentname name, IBinder service) {                Mybinder = MyAIDL.Stub.asInterface (Service) c6/>//is bound to the remote service            mybinder.dosomething ();            }   

The above analysis shows that when a remote service is bound, when the client calls Addbook the Addbook method in the proxy class is called, so let's take a look at the Proxy#addbook

@Override public void Addbook (Com.test.aidl.Book book) throws android.os.remoteexception{   Android.os.Parcel _data = Android.os.Parcel.obtain ();   Android.os.Parcel _reply = Android.os.Parcel.obtain ();  try {   _data.writeinterfacetoken (descriptor);   if ((Book!=null)) {     _data.writeint (1);      Book.writetoparcel (_data, 0);      }   else {     _data.writeint (0);   }     Mremote.transact (Stub.transaction_addbook, _data, _reply, 0);     _reply.readexception ();  }     finally {    _reply.recycle ();     _data.recycle ();     } }
You can see that in this method you first create an input parameter parce object _data with the output type Parcel object _reply, then write some data to the input parameter parce object _data, and then call Mremote.transact ( Stub.transaction_addbook, _data, _reply, 0); The statement, when executing the statement, represents the client initiating an RPC (remote procedure Call) request, at which time the current thread is suspended until the RPC process returns and the current thread continues execution. Note that the Mremote object is the binder object that was passed in when the proxy object was created, that is, Mremote is a binder object, and we look at the Transact function in the binder, the code is as follows:

/**     * Default implementation rewinds the parcels and calls Ontransact.  On     * The remote side, Transact-calls into the binder-to-do the IPC.     */Public    Final Boolean transact (int code, PARCEL data, Parcel reply,            int flags) throws RemoteException {        if ( False) LOG.V ("Binder", "Transact:" + code + "to" + this);        if (data! = null) {            data.setdataposition (0);        }        Boolean r = Ontransact (code, data, reply, flags);        if (reply! = null) {            reply.setdataposition (0);        }        return r;    }

You can see that the Transact function is final decorated, that is, the function is not allowed to be overridden by inheritance, one of the most important statements in the function: boolean r = Ontransact (code, data, reply, flags); That is, the Ontransact function is called in the Transact function, and the ontransact function is generally required to be rewritten, and the overriding process is done automatically by our own defined Aidl file IDE, As shown above, the Ibookmanager.java file is automatically generated from the Ibookmanager.aidl file, and the Ontransact function is overridden in this Ibookmanager.java file.

This ontransact function is the key to the binder mechanism's operation, which runs on the server's binder thread pool, and when the client initiates a cross-process request, called the Transact function, the remote requested data is executed through the system's underlying function. The full signature of the function is: public boolean ontransact (int code, ANDROID.OS.PARCEL data, android.os.Parcel reply, int flags), The server uses code to determine which method the client is invoking, then takes the parameters of the target method from data (if the target method has parameters), then executes the target method, and when the target method finishes executing, writes the return value to reply if the target method has a return value. It is important to note that if the function returns FALSE, the client's request will fail, and the attribute can be used to authenticate the permission because we do not want any process to be free to access our services.

Through the above analysis, I believe that the reader of the binder mechanism of the entire process is already very familiar with the system, the bottom of the binder is how to transfer the data of this is not important, and we do not need to understand, we only need to know the binder mechanism of the entire process of operation, The above procedure is shown in the following way. Note that the following illustration only represents the process of binding a remote service, because tying the ground service does not involve an IPC mechanism. As follows:


For the above illustration or a little explanation, first in the client serviceconnection onserviceconnected (componentname name, IBinder Service) method we are The Mybinder = MyAIDL.Stub.asInterface (service) statement converts the service to a binder object, which is called the Asinterface method instead of using (Myservice.mybinder) The type of service conversion means that we want to get the remote service instead of the local service, then the next Mybinder calls the Addbook (book), this method will call binder in its internal Transact method to initiate the RPC request, At this point the client is suspended, Binder's Transact method is a final method, not allowed to be modified, in which the Ontransact method is called, which runs on the server's binder thread pool, This method is the key to the entire binder mechanism, in which the IPC data is read and written, the method return value is written to the _reply parameter, then the RPC process ends, the data is returned to the client, and the client is awakened.

In addition, because the binder method of the server is running in the binder thread pool, the method in binder should be implemented synchronously regardless of time-consuming, because it is already running in a thread.







An explanation of the binder of the Android IPC mechanism

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.