Android AIDL instance Parsing

Source: Internet
Author: User
Tags server resume mremote

Android AIDL instance Parsing
AIDL is not very common in our development. Although we use Sina Weibo's SSO login, the principle is to use AIDL, however, I have never written a complete example of AIDL, so I wrote this simple article.
AIDL (AndRoid Interface Description Language) is an excuse Description Language. the compiler can generate a piece of code through the aidl file and use a pre-defined interface to implement internal communication between two processes. if you want to access an object in another Service in one Activity, you must first convert the object to a parameter that can be recognized by AIDL (possibly multiple parameters ), then, AIDL is used to pass these parameters. At the message receiver, these parameters are used to assemble them into desired objects.
To put it bluntly, AIDL defines an interface. The client (caller) connects to the remote server resume through bindService. When the connection is established, an IBinder object is returned, this object is the BinderProxy of the Service side. When a connection is established, the client uses the asInterface function to package the BinderProxy object to the local Proxy, assign the BinderProxy object of the remote server to the mRemote field of the Proxy class, that is, execute a remote method call through mRemote. To have a deeper understanding of the Binder mechanism, go to Lao Luo's series of texts, and analyze the source code of the Java interface of the Android system's inter-process communication Binder Mechanism at the application framework layer. Next we will look at an AIDL instance.


AIDL interface declaration
Create a com. example. advanceandroid. aidl package under the src directory, and then create an ILogin. aidl file under the package. Note that the file is created instead of a class or interface type. Declare the interface in ILogin. aidl. The instance is as follows:

Package com. example. advanceandroid. aidl;

Interface ILogin {
String login ();
}

Note that both the interface and method declaration do not need to be public. An error is prompted when the method is added to public. After compilation, if eclipse Enables automatic compilation, an ILogin. java class is generated under gen/com. example. advanceandroid. aidl. The content is roughly as follows:

Package com. example. advanceandroid. aidl; public interface ILogin extends android. OS. IInterface {/** Local-side IPC implementation stub class. */public static abstract class Stub extends android. OS. binder implements com. example. advanceandroid. aidl. ILogin {private static final java. lang. string DESCRIPTOR = "com. example. advanceandroid. aidl. ILogin ";/** Construct the stub at attach it to the interface. */Public Stub () {this. attachInterface (this, DESCRIPTOR);}/*** Cast an IBinder object into an com. example. advanceandroid. aidl. ILogin * interface, generating a proxy if needed. */public static com. example. advanceandroid. aidl. ILogin asInterface (android. OS. IBinder obj) {if (obj = null) {return null;} android. OS. IInterface iin = obj. queryLocalInterface (DESCRIPTOR); if (iin! = Null) & (iin instanceof com. example. advanceandroid. aidl. ILogin) {return (com. example. advanceandroid. aidl. ILogin) iin);} return new com. example. advanceandroid. aidl. ILogin. 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 INTERFACE_TRANSACTION: {reply. writeString (DESCRIPTOR); return true;} case TRANSACTION_login: {// 1. the login request is executed this. login (); data. enforceInterface (DESCRIPTOR); java. lang. string _ result = this. login (); reply. writeNoException (); reply. writeString (_ result); return true ;}} return super. onTransact (code, data, reply, flags);} private static class Proxy implements com. example. advanceandroid. aidl. ILogin {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. lang. string login () throws android. OS. remoteException // 2. login in the Proxy, using the Binder mechanism to implement IPC {android. OS. parcel _ data = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); java. lang. string _ result; try {_ data. writeInterfaceToken (DESCRIPTOR); mRemote. transact (Stub. TRANSACTION_login, _ data, _ reply, 0); _ reply. readException (); _ result = _ reply. readString ();} finally {_ reply. recycle (); _ data. recycle ();} return _ result;} static final int TRANSACTION_login = (android. OS. IBinder. FIRST_CALL_TRANSACTION + 0);} public java. lang. string login () throws android. OS. remoteException ;}

As you can see, this class automatically generates the ILogin interface, which contains another login () function. But the most important thing is that a Stub class is generated, which integrates the sub-Binder class and implements the ILogin interface. The most important thing in Stub is the asInterface () function. In this function, the obj parameter type is determined. If the obj is a local interface, it is considered not IPC, this obj will be converted to the ILogin type; otherwise, the obj will be wrapped by another internal class Proxy automatically generated and assigned to the mRemote attribute in the Proxy. The Proxy class also implements the ILogin interface. In the login () function, the Proxy transmits requests and data to the server through the Binder Mechanism, as shown in comment 2 in the above Code. This is the completion of the client.

Server AIDL Interface
The server also needs to create an aidl file with the same name under the same package. example. advanceandroid. ILogin in the aidl package. aidl can be copied to the server. If a custom type is used, the custom type also needs to be available on both the client and server. After aidl is copied, the corresponding ILogin. java file will also be generated in the server program in gen, with the same content as the client. Here we need to look at the onTransact function, that is, Note 1 in the above Code. We can see that this is executed in case TRANSACTION_login. the login () function is used to execute this when receiving the TRANSACTION_login request from the client. login () function, through client analysis, we know that when we call login (), we actually submit a TRANSACTION_login request to the server through mRemote, therefore, the two ends are connected through the Binder mechanism. We can simply understand it as the C/S mode.

The server is not complete. The most important step is to create a Service. The content is roughly as follows:

/*** AIDL server interface. LoginStubImpl implements the ILogin interface. ** @ author mrsimple */public class LoginService extends Service {/*****/IBinder mBinder = new LoginStubImpl (); /*** @ author mrsimple */class LoginStubImpl extends Stub {@ Override public String login () throws RemoteException {return "this is from" + this. getClass (). getName () + "returned string" ;}}/** return the Binder instance, that is, the Stub subclass that implements the ILogin interface. Here it is LoginStubImpl * [url = home. php? Mod = space & uid = 133757] @ see [/url] android. app. service # onBind (android. content. intent) * // @ Override public IBinder onBind (Intent intent) {return mBinder ;}}

This Service is named LoginService, inherited from Service, and an internal class named LoginServiceImpl is created. This class inherits from the automatically generated Stub and implements the login () method. Declare An IBinder field in LoginService:
IBinder mBinder = new LoginStubImpl ();
In addition, the mBinder object is returned in the onBind function of LoginService. That is, when the client establishes a connection with the server, the onBind method is called to return the mBinder object, the IBinder object obtained in the onServiceConnected function of the ServiceConnection class of the client is the mBinder object in the LoginService packaged by BinderProxy. Therefore, the this. login () function called in onTransact on the server is actually the login () function in the called LoginStubImpl.

Register LoginService in AndroidManifest. xml of the server program, as follows:

    
         
             
                              
          
 


Establish a connection with the client

Add the following code to the Activity:

ServiceConnection mLoginConnection = new ServiceConnection () {@ Override public void onServiceDisconnected (ComponentName name) {Log. d ("", "### aidl disconnected. ") ;}@ Override public void onServiceConnected (ComponentName, IBinder service) {Log. d ("", "### aidl onServiceConnected. service: "+ service. getClass (). getName (); ILogin login = Stub. asInterface (service); Log. d ("", "### after asInterface:" + login. getClass (). getName (); try {Log. d ("", "### login:" + login. login (); // Toast. makeText (MainActivity. this, "onServiceConnected:" + // login. login (), // Toast. LENGTH_SHORT ). show ();} catch (RemoteException e) {e. printStackTrace () ;}};@ Override protected void onResume () {super. onResume (); // the server's action Intent aidlIntent = new Intent ("com. example. advanceandroid. aidl. loginService "); bindService (aidlIntent, mLoginConnection, Context. BIND_AUTO_CREATE) ;}@ Override protected void onStop () {super. onStop (); // unbind unbindService (mLoginConnection );}

Run

Run the server program first, and then start the client program. The client output is as follows:

10:40:54 09-02. 662: D/(9589): ### aidl onServiceConnected. service: android. OS. binderProxy09-02 10:40:54. 662: D/(9589): ### after asInterface: com. example. advanceandroid. aidl. ILogin $ Stub $ Proxy09-02 10:40:54. 662: D/(9589): ### login: This is from com. example. advanceandroid. aidl. loginService $ string returned by LoginStubImpl

It can be seen that the service object in onServiceConnected (ComponentName, IBinder service) is of the BinderProxy type, which is encapsulated into the Proxy type after asInterface conversion. However, when calling, the login () function in the LoginStubImpl server is executed. Therefore, the LoginStubImpl instance mBinder is packaged by the server as the BinderProxy type, and then packaged by the client Proxy. The Binder mechanism is used for data transmission to implement IPC.

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.