Android aidl--Process Communication mechanism detailed _android

Source: Internet
Author: User
Tags static class stub mremote

Android Aidl, Android process mechanism communication mechanism, here to organize the knowledge of aidl, to help you learn to understand this part of knowledge!

What is Aidl

Aidl Full name Android Interface Definition Language, an Android interface Description language. It sounds esoteric, but the essence of it is to generate an assistive tool for interprocess communication interfaces. Its existence form is a kind of. aidl file, what the developer needs to do is define the interface of interprocess communication in the file, and the IDE will generate a. java file for the project to use according to our. Aidl interface file, which is similar to the "syntactic candy" we are talking about.

Aidl's syntax is the Java syntax, which is a little bit different on the guide package. In Java, if two classes are in the same package, it is not necessary to carry out a package operation, but in aidl you must make a guide package declaration.

Aidl Detailed

Conceive of a scene: We have a library management system, this system through the CS mode to achieve. The specific management function is implemented by the server-side process, and the client only needs to invoke the appropriate interface.

Then first define the ADIL interface for this management system.

We created a new Aidl package in/RC, with three files Book.java, Book.aidl, ibookmanager.aidl three files in the package.

Package Com.example.aidl Book Public

class book implements parcelable {
 int bookid;
 String BookName;

 Public book (int bookid, String bookname) {
   this.bookid = BookID;
   This.bookname = BookName;
 }

 ...
}

Package com.example.aidl;

Parcelable Book;

Package com.example.aidl;

Import Com.example.aidl.Book;

Inteface Ibookmanager {
  list<book> getbooklist ();
  void Addbook (in book book);
}

These three files are described separately below:

Book.java is the entity class we define, which implements the Parcelable interface so that the book class can be transferred between processes.
Book.aidl is the declaration of this entity class in Aidl.
Ibookmanager is the interface between server and client communications. (Note that in the Aidl interface, in addition to the basic type, the parameters must be in the direction before the parameter, in represents the input parameter, out represents the output parameter, inout represents the input output type parameter)

After the compiler compiles, Android studio automatically generates a. java file for our project, which contains three classes, the three classes are Ibookmanager, stubs, and Proxy, and these three classes are all static types, and we can totally separate them, The three classes are defined as follows:

Ibookmanager



Public interface Ibookmanager extends Android.os.IInterface {public

  void Addbook (Net.bingyan.library.Book book) Throws Android.os.RemoteException;

  Public java.util.list<net.bingyan.library.book> getbooklist () throws android.os.RemoteException;
}

Stub



public static abstract class Stub extends Android.os.Binder implements Net.bingyan.library.IBookManager {private S

    Tatic Final Java.lang.String descriptor = "Net.bingyan.library.IBookManager";
    static final int transaction_addbook = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int transaction_getbooklist = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
     /** * Construct the stub at attach it to the interface.
    * * Public Stub () {this.attachinterface (this, descriptor); /** * Cast a IBinder object into a Net.bingyan.library.IBookManager interface, * Generating a proxy if Needed. http://www.manongjc.com/article/1501.html */public static Net.bingyan.library.IBookManager Asinterface (ANDROID.O
      S.ibinder obj) {if ((obj = = null)) {return null;
      } android.os.IInterface iin = Obj.querylocalinterface (descriptor); if ((iin!= null) && (iin instanceof net.bingyan.library.Ibookmanager))) {return ((Net.bingyan.library.IBookManager) iin);
    Return to New Net.bingyan.library.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) throw s android.os.RemoteException {switch (code) {case Interface_transaction: {reply.writestring (DES
          Criptor);
        return true;
          Case Transaction_addbook: {data.enforceinterface (descriptor);
          Net.bingyan.library.Book _arg0;
          if ((0!= Data.readint ())) {_arg0 = Net.bingyan.library.Book.CREATOR.createFromParcel (data);
          else {_arg0 = null;
          } this.addbook (_ARG0);
          Reply.writenoexception ();
        return true; Case Transaction_getbooklist: {data.enforceinterface (descriptOR);
          java.util.list<net.bingyan.library.book> _result = This.getbooklist ();
          Reply.writenoexception ();
          Reply.writetypedlist (_result);
        return true;
    } return Super.ontransact (code, data, reply, flags);

 }
}

Proxy



private static class Proxy implements Net.bingyan.library.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;  }/** * Demonstrates some basic types that, can use as parameters * and return values in Aidl. http://www.manongjc.com/article/1500.html * * @Override public void Addbook (Net.bingyan.library.Book Boo
        K) 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 (); @Override public java.util.list<net.bingyan.library.book> getbooklist () throws Android.os.Rem
        oteexception {Android.os.Parcel _data = Android.os.Parcel.obtain ();
        Android.os.Parcel _reply = Android.os.Parcel.obtain ();
        Java.util.list<net.bingyan.library.book> _result;
          try {_data.writeinterfacetoken (descriptor);
          Mremote.transact (Stub.transaction_getbooklist, _data, _reply, 0);
          _reply.readexception ();
        _result = _reply.createtypedarraylist (Net.bingyan.library.Book.CREATOR);
          finally {_reply.recycle ();
        _data.recycle ();
      return _result;

 }
    }

The descriptions of the three classes generated are as follows:

    1. Ibookmanager This class is the interface we define, and Android Studio adds a parent class to it that inherits from the Android.os.interface interface, which has only one method IBinder Asbinder (), so There are three implemented methods in Ibookmanager, which are the windows of the server-side process and the client process communication.
    2. Stub is an abstract class that inherits from the Android.os.Binder class and implements the Ibookmanager interface. In the Stub, the Asbinder () interface method has been implemented, and two of the Aidl interface methods we have defined are left to the subclass that inherits it. It is used on the server side, so the service side needs to implement both methods.
    3. As the name implies is a proxy class, it is the server on the client side of a proxy, it also implements the Ibookmanager interface, and implementation of Ibookmanager all the methods. It is used on the client side and is the proxy for the client at the server. Now we analyze each of these three classes individually:
    4. Ibookmanager This class has nothing to say, it is simply inherited asinterface this interface, the role is to convert Ibookmanager to IBinder.
    5. Proxy This class has already mentioned, it is the interprocess communication mechanism of a package class, his internal implementation mechanism is Binder, through the construction method we also easy to see. Its construction method accepts a ibinder type parameter named remote, which obviously represents the service side. Let's look at the methods in this class Addbook () and Getbooklist ():
@Override public void Addbook (Net.bingyan.library.Book book) throws Android.os.RemoteException {Android.os.Parcel _da
   Ta = 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 (); }} @Override/* http://www.manongjc.com/article/1547.html/Public java.util.list<net.bingyan.library.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<net.bingyan.library.book> _result;
       try {_data.writeinterfacetoken (descriptor); Mremote.transact (StuB.transaction_getbooklist, _data, _reply, 0);
       _reply.readexception ();
    _result = _reply.createtypedarraylist (Net.bingyan.library.Book.CREATOR);
      finally {_reply.recycle ();
    _data.recycle ();
return _result;
 }

They are automatically implemented by the compiler, and there are many similarities between the two methods, which can be disclosed here: These are the windows that the client process invokes the server-side process. At the beginning of these two methods, they all define two Parcel (Chinese translation: Parcel) objects. Parcel This class looks familiar to us, yes, the parameters of the Createfromparcel () in the Writetoparcel () and creator in the book class are Parcel types, as explained in the documentation for this class:

Container for a message (data and object references) that can is sent through an ibinder. A Parcel can contain both flattened data that would be unflattened on the other side of the IPC (using the various methods Here is the writing specific types, or the general {@link Parcelable} interface), and references to live {@link IBinder} obje CTS that would result in the other side receiving a proxy ibinder connected with the original IBinder in the Parcel.

A Proxy is a container that can be passed through IBinder for messaging. A Parcel can contain serializable data that is deserialized at the other end of the IPC, or it can contain references to IBinder objects, which causes the other end to receive a proxy object of the IBinder type, which is connected to the original Ibin in Parcel Der Object.

Here's an intuitive illustration of the following:

The aidl of the Android process communication mechanism

As shown in the figure, we can see very intuitively that the service side takes Parcel as the data parcel relies on Binder and the client to communicate. The data parcel is the object after serialization.

As mentioned above, both methods define two Parcel objects, respectively called _data and _reply, in the image, from the client's point of view, _data is the client sent to the server data package, _reply server sent to the client data package.

And then we start to communicate with the server by using these two objects, and we can observe that there are two methods that call Mremote.transact (), which has four parameters, and the meaning of the first parameter. We'll go back to the second argument _data Responsible for sending data packages to the server, such as interface method parameters, and the third parameter _reply is responsible for receiving data packages from the server, such as the return value of the interface method. This line of code is only a simple method call, but it is the most central part of aidl communication, it actually made a remote method call (the client through the local agent proxy exposed interface method invoke the same name method), so can think of it is a time-consuming operation.

In our example:

The 1.void addbook (book book) requires _data to send parameter Book:book to the server by sending the book through its implemented Writetoparcel (Parcel out) method to _data, as you can , _data is actually the parameter out, remember the book in the implementation of this method? We are packing the book's fields into Parcel.

2.list<book> getbooklist () needs to receive the return value List<book>:books from the server by _reply, in the method of passing the CREATOR this static field in book as a parameter to _ In reply's Createtypedarraylist () method, do you remember the CREATOR in the book? Were you curious about how this static field should be used? Now it's clear that we need this object (it's easy to understand that we can call it "deserialization") to deserialize the server-side data to regenerate serializable objects or arrays of objects. It is obvious that CREATOR generated list<book>:books with the help of _reply.

Of course, the two methods of _data and _reply not only passed the object, but also passed some verification information, which we can not delve into, but should be noted that Parcel packaging sequence and the order of the package to be strictly corresponding. For example, the first package is int:i, so the first solution should also be the integer value. It is also the first time that the package is called if it is parcel.writeint (int), the first call to unpack should be parcel.readint ().

Here, the client's Proxy is finished, let's look at the Stub on the service side.

The stub implements one of the methods of Ibookmanager, which is simply to return itself simply because the stub itself inherits from Binder, and Binder inherits from IBinder, so there is no problem. You ask: Are there two other methods that have not been implemented? These two methods are the interface methods we define, which are left to the server process to implement, that is, we need to define a Stub's implementation in the service-side process. The following two important methods in the Stub are analyzed:

Ibookmanager asinterface (IBinder obj)

public static Net.bingyan.library.IBookManager asinterface (Android.os.IBinder obj) {
      if ((obj = = null)) {
        return null;
      }
      Android.os.IInterface iin = obj.querylocalinterface (descriptor);
      if ((iin!= null) && (iin instanceof Net.bingyan.library.IBookManager)) {return
        ( Net.bingyan.library.IBookManager) iin);
      return new Net.bingyan.library.IBookManager.Stub.Proxy (obj);
    }

The effect of this method is to convert the stub class to the Ibookmanager interface, and there is a judgment in the method that if our server-side process and the client process are the same process, the stub class is transformed directly into Ibookmanager, if not the same process. Then the Stub is converted to Ibookmanager by proxy class proxy. Why, we know that if the server-side process and the client process are not the same process, their memory cannot be shared, they cannot communicate in a normal way, but if we do it ourselves, it costs too much for the average developer, So the compiler helped us create a tool that encapsulates interprocess communication, this is the Proxy, which encapsulates the underlying process communication mechanism and exposes only the interface methods, and the client only needs to call the two methods to implement interprocess communication (in fact, the remote invocation of the method) without needing to know the details.

With this method, we can use the client to convert a IBinder type variable into our defined interface Ibookmanager, and the usage scenario will be explained in a later instance.

ontransact (int code, PARCEL data, Parcel reply, int flags)

@Override public boolean ontransact (int code, ANDROID.OS.PARCEL data, android.os.Parcel reply, int flags) throws Android. Os.
          remoteexception {switch (code) {case Interface_transaction: {reply.writestring (descriptor);
        return true;
          Case Transaction_addbook: {data.enforceinterface (descriptor);
          Net.bingyan.library.Book _arg0;
          if ((0!= Data.readint ())) {_arg0 = Net.bingyan.library.Book.CREATOR.createFromParcel (data);
          else {_arg0 = null;
          } this.addbook (_ARG0);
          Reply.writenoexception (); return true; /* http://www.manongjc.com/article/1499.html/} case transaction_getbooklist: {Data.enforcein
          Terface (descriptor);
          java.util.list<net.bingyan.library.book> _result = This.getbooklist ();
          Reply.writenoexception ();
          Reply.writetypedlist (_result);
       return true; } return Super.ontransact (code, data, reply, flags);
 }

Are we familiar with this method? We also see a similar method in the Proxy transact (int, Parcel, Parcel, int), their parameters are the same, and they are all methods in the Binder, so what are their connections?

As mentioned earlier, Transact () executes a remote call, and if Transact () is the originator of a remote call, then Ontransact () is the response of the remote invocation. The real process is the client generator remote method call, the Android system through the underlying code to respond to the call and processing, and then callback service-side ontransact () method, from the data package to remove the method parameters, to the server implementation of the same name method call, and finally package the return value back to the client.

It is important to note that Ontransact () is in the Binder thread pool of the server process, which means that if we are to update the UI in the Ontransact () method, we must rely on Handler.

The first parameter of the two methods means the identification code of the Aidl interface method, in which two constants are defined as indicators of the two methods:

static final int transaction_addbook = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int transaction_getbooklist = (Android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

if code = = Transaction_addbook, then the client invokes Addbook (), and if code = = Transaction_getbooklist, then the client invokes Getbooklist (). And then referred to the appropriate service-side method to handle. Use a graph to represent the entire communication process:

The aidl of the Android process communication mechanism

Knowing the whole process of aidl, the next step is the application of Aidl in the Android program.

The use of Aidl

I believe that everyone should be aware of the use of the service, although the service is called "services" and run in the background, but they are still running in the default process of the main thread. Actually let the Service run in the default process, a bit overqualified. Many of Android's system services are running in separate processes for other applications, such as window management services. The advantage of this is that multiple applications can share the same service, save resources, and facilitate centralized management of each client, the problem is the thread safety problem.

Then we will use Aidl to implement a simple CS architecture of the library management system.

First we define the service side:

Bookmanagerservice



public class Bookmanagerservice extends Service {

  private final list<book> mlibrary = new arraylist<> (); C2/>private Ibookmanager Mbookmanager = new Ibookmanager.stub () {
    @Override public
    void Addbook (book book) Throws RemoteException {
      synchronized (mlibrary) {
        mlibrary.add (book);
        LOG.D ("Bookmanagerservice", "Now we library has" + mlibrary.size () + "books");
      }

    @Override public
    list<book> getbooklist () throws RemoteException {return
      mlibrary;
    }
  };
 
  @Override/* http://www.manongjc.com/article/1496.html
  /public IBinder onbind (Intent Intent) {return
    Mbookmanager.asbinder ();
  }




<service
   android:process= ": Remote"
   android:name= ". Bookmanagerservice "/>

Service side we define the Bookmanagerservice class, in which we create a Stub object on the server, and implement the two Aidl interface methods that we need to implement to define the library management strategy for the server. In the Onbind () method We return the Ibookmanager object as IBinder. We know that when we bind a service, the system calls the Onbinder () method to get the IBinder object from the server and converts it to the client's IBinder object, although the IBinder of the server and the client's ibinder are two IBinder objects, but they are the same object at the bottom. When we register the service in XML, we give it a process name, so that the service can run in a separate process.

Next look at the implementation of the client:

Client



public class Client extends Appcompatactivity {private TextView TextView;

  Private Ibookmanager Bookmanager;
    @Override protected void OnCreate (@Nullable Bundle savedinstancestate) {super.oncreate (savedinstancestate);

    Setcontentview (r.layout.library_book_manager_system_client);
    Intent i = new Intent (client.this, Bookmanagerservice.class);

    Bindservice (i, Conn, bind_auto_create);
    Button Addabook = (button) Findviewbyid (R.id.button);
      Addabook.setonclicklistener (v-> {if (Bookmanager = null) return;
        try {bookmanager.addbook (new book (0, "book")); Textview.settext (getString r.string.book_management_system_book_count, string.valueof (Bookmanager.getbooklist ()
      . Size ()));
      catch (RemoteException e) {e.printstacktrace ();

    }

    });
  TextView = (TextView) Findviewbyid (R.id.textview); Private Serviceconnection conn = new Serviceconnection () {@Override public void onserviceconnected (CoMponentname name, IBinder service) {log.d ("Client-->", service.tostring ());
    Bookmanager = IBookManager.Stub.asInterface (service);
    @Override public void onservicedisconnected (componentname name) {log.d ("Client", name.tostring ());

}
  };

 }
 <?xml version= "1.0" encoding= "Utf-8"?> <linearlayout "xmlns:android=" Schemas.android.com/apk/res/android "android:orientation=" vertical "android:layout_width=" Match_parent "Android: layout_height= "Match_parent" android:weightsum= "1" android:gravity= "center" > <button android:text= "http:/" /www.manongjc.com/article/1495.html "android:layout_width=" 111DP "android:layout_height=" Wrap_content "Android : id= "@+id/button"/> <textview android:layout_margintop= "10DP" android:text= "@string/book_management_syst
    Em_book_count "android:layout_width=" 231DP "android:gravity=" center "android:layout_height=" Wrap_content " Android:id= "@+id/textview"/> </LinearLayout> 

Our client is a activity,oncreate () in which the service is bound, and the Bindservice () method has a parameter serviceconnection:conn, because the binding service is asynchronous, The function of this parameter is the interface that binds the callback after the service succeeds, and it has two callback methods: One is the callback after the connection service succeeds, and the other is recalled after disconnecting from the server. Our main concern now is the onserviceconnected () method, where we do only one thing: Convert the server-side IBinder objects into aidl interfaces, and we define Ibookmanager:bookmanager field to keep a reference to it. In this way, we can use this bookmanager to make a remote call to the method. We register the Button for the client: each click adds a book to the server and displays the number of books available in the library.

Now let's look at how the program works:

Every time we click on a button, we successfully add a book to the server, stating that we have successfully communicated across processes through Aidl.

Thank you for reading, I hope to help you, thank you for your support for this site!

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.