[Android] From the shortest to the deep understanding of AIDL

Source: Internet
Author: User

[Android] From the shortest to the deep understanding of AIDL
I. Binder Overview 1.1 why to use binder for security, stability, and memory management considerations, Android applications and system services are running in a separate process, however, communication and data sharing are required between them to avoid the problem of traditional IPC overhead and Service Denial. android library does not support System V's IPCBinder. It adds the reference counter of object reference and eliminates the reminder mechanism. When a Binder service is referenced by no terminal, its owner can automatically remind it to process its own Binder and identify the sender and recipient through UID/PID (which is important for security)

However:

The Binder does not support RPC. Only the local client and the server are based on message communication and does not apply to stream non-compliant with POSIX standards.
1.2 binder communication process

Client Service

Processes cannot communicate directly, so the Binder driver

The client and the server do not need to understand the binder protocol, so the proxy and the stub are used.

The client does not want to know that the IPC is being used, nor does it care about the binder and proxy. Therefore, the management object must be abstracted.

However, to obtain the handle of the service that the client wants to communicate with, you only need to ask sevicemanager (Context Manager) whether the service has been registered.

Finally, let's look at the overall architecture.

Ii. AIDL example

 

Cross-process addition and subtraction using aidl

2.1 Server

Create an android project, create the package com. realize. calc. aidl, and create the file ICalcAIDL. aidl. The content is as follows:

 

package com.realize.calc.aidl;interface ICalcAIDL{int add(int x , int y);int min(int x , int y );}

Create the com. realize. lizijun. binder_server package and create the CalcService. java service. The content is as follows:

 

 

package com.realize.lizijun.binder_server; import com.realize.calc.aidl.ICalcAIDL; import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log; public class CalcService extends Service{private static final String TAG = "server"; public void onCreate(){Log.e(TAG, "onCreate");} public IBinder onBind(Intent t){Log.e(TAG, "onBind");return mBinder;} public void onDestroy(){Log.e(TAG, "onDestroy");super.onDestroy();} public boolean onUnbind(Intent intent){Log.e(TAG, "onUnbind");return super.onUnbind(intent);} public void onRebind(Intent intent){Log.e(TAG, "onRebind");super.onRebind(intent);} private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub(){ @Overridepublic int add(int x, int y) throws RemoteException{return x + y;} @Overridepublic int min(int x, int y) throws RemoteException{return x - y;} }; }

Register a service in AndroidManifest. xml
        <service android:name="com.realize.lizijun.binder_server.CalcService">            <intent-filter>                <action android:name="com.realize.calc.aidl">                 <category android:name="android.intent.category.DEFAULT">            </category></action></intent-filter>        </service>
2.2 Client

Create an android project, create the package com. realize. calc. aidl, and create the file ICalcAIDL. aidl (which is the same as that on the server). The content is as follows:

package com.realize.calc.aidl;interface ICalcAIDL{int add(int x , int y);int min(int x , int y );}

The main activity content is as follows:
Package com. realize. lizijun. binder_client; import android. app. activity; import android. content. componentName; import android. content. context; import android. content. intent; import android. content. serviceConnection; import android. OS. bundle; import android. OS. IBinder; import android. util. log; import android. view. view; import android. widget. toast; import com. realize. calc. aidl. ICalcAIDL; public class MainActiv Ity extends Activity {private static final String TAG = "client"; private ICalcAIDL mCalcAidl; private ServiceConnection mServiceConn = new ServiceConnection () {@ Overridepublic void onServiceDisconnected (ComponentName name) {Log. e (TAG, "onServiceDisconnected"); mCalcAidl = null ;}@ Overridepublic void onServiceConnected (ComponentName, IBinder service) {Log. e (TAG, "onServiceConnected"); mCalcAidl = IC AlcAIDL. stub. asInterface (service) ;}}; @ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main);}/*** call * @ param view */public void BindService (View view) {Intent intent = new Intent (); intent when you click bindService. setAction ("com. realize. calc. aidl "); bindService (intent, mServiceConn, Context. BIND_AUTO_CREATE);}/*** click unBindSer Call the * @ param view */public void unbindService (View view) {unbindService (mServiceConn );} /*** call * @ param view */public void addInvoked (View view) throws Exception {if (mCalcAidl! = Null) {int addRes = mCalcAidl. add (12, 12); Toast. makeText (this, addRes + "", Toast. LENGTH_SHORT ). show ();} else {Toast. makeText (this, "the server is killed by an exception. Please bind the server again", Toast. LENGTH_SHORT ). show () ;}}/*** call * @ param view */public void minInvoked (View view) throws Exception {if (mCalcAidl! = Null) {int addRes = mCalcAidl. min (50, 12); Toast. makeText (this, addRes + "", Toast. LENGTH_SHORT ). show ();} else {Toast. makeText (this, "the server is not bound or killed abnormally. Please bind the server again", Toast. LENGTH_SHORT ). show ();}}}

The interface is as follows:

 

2.3 result description

 

After you click BindService, the server executes the onCreate and onBind methods, the client executes the onServiceConnected method, and then click 12 + 12, 50-12 to successfully call the server code, return the correct results, and then click unBindService, the Service calls onUnbind and onDestory and then click 12 + 12, 50-12. The correct result is still displayed, indicating that the connection between the client and the server still exists through the background, force stop the service. You can see that the onServiceDisconnected method is called. Click 12 + 12, 50-12, and you will not be able to get the result. 3. Analyze the API code generated by AIDL.

After ICalcAIDL. aidl is created above, the ICalcAIDL. java file is generated in the gen Directory, which implements proxy and stub on the client and server)

3.1 Server

Call ICalcAIDL. Stub in the server code

 

private final ICalcAIDL.Stub mBinder = new ICalcAIDL.Stub(){ @Overridepublic int add(int x, int y) throws RemoteException{return x + y;} @Overridepublic int min(int x, int y) throws RemoteException{return x - y;} };

In CalcService. java, it is obvious that Stub is the subclass of the Binder.

 

 

public static abstract class Stub extends android.os.Binder implements com.realize.calc.aidl.ICalcAIDL

Next, let's take a look at the onTransact method under Stub. This method implements addition and subtraction internally.
@ 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_add: {data. enforceInterface (DESCRIPTOR); int _ arg0; _ arg0 = data. readInt (); int _ arg1; _ arg1 = data. readInt (); int _ result = this. add (_ arg0, _ arg1); reply. writeNoException (); reply. writeInt (_ result); return true;} case TRANSACTION_min: {data. enforceInterface (DESCRIPTOR); int _ arg0; _ arg0 = data. readInt (); int _ arg1; _ arg1 = data. readInt (); int _ result = this. min (_ arg0, _ arg1); reply. writeNoException (); reply. writeInt (_ result); return true ;}} return super. onTransact (code, data, reply, flags);} the server executes the onTransact Method Based on the message sent from the client. The code of this method has four parameters, which are the unique identifier of an integer, the value returned by the reply server parameter passed by the data Client to identify the method to be executed. flags indicates whether the returned value exists. 0 indicates yes (bidirectional), and 1 indicates no (unidirectional)

 

3.2 Client

In the client code, ICalcAIDL. Stub. asInterface is called.

 

private ServiceConnection mServiceConn = new ServiceConnection(){@Overridepublic void onServiceDisconnected(ComponentName name){Log.e(TAG, "onServiceDisconnected");mCalcAidl = null;} @Overridepublic void onServiceConnected(ComponentName name, IBinder service){Log.e(TAG, "onServiceConnected");mCalcAidl = ICalcAIDL.Stub.asInterface(service);}};

In the ICalcAIDL. java file, asInterface is called to the Proxy

 

 

public static com.realize.calc.aidl.ICalcAIDL asInterface(android.os.IBinder obj){if ((obj==null)) {return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin!=null)&&(iin instanceof com.realize.calc.aidl.ICalcAIDL))) {return ((com.realize.calc.aidl.ICalcAIDL)iin);}return new com.realize.calc.aidl.ICalcAIDL.Stub.Proxy(obj);}

So let's take a look at the add method of Proxy.
@ Override public int add (int x, int y) throws android. OS. remoteException {android. OS. parcel _ data = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); int _ result; try {_ data. writeInterfaceToken (DESCRIPTOR); _ data. writeInt (x); _ data. writeInt (y); mRemote. transact (Stub. TRANSACTION_add, _ data, _ reply, 0); _ reply. readException (); _ result = _ reply. readInt ();} finally {_ reply. recycle (); _ data. recycle ();} return _ result;} declares two android. OS. the Parcel object, _ data is used to transmit data, and _ replay is used to receive the returned data and finally call the transact method to communicate with the server.


 

4. Examples without relying on AIDL

 

How can we achieve cross-process communication without using the AIDL file? From the above analysis, we can know that cross-process communication is not implemented through the AIDL file. In fact, this is to implement the interface function in the automatically generated AIDL file. Next we implement the cross-process multiplication and division call.

4.1 Server

Create a project and implement CalcService. java. The Code is as follows:

Package com. realize. lizijun. noaidl_binder_server; import android. app. service; import android. content. intent; import android. OS. binder; import android. OS. IBinder; import android. OS. parcel; import android. OS. remoteException; import android. util. log; public class CalcService extends Service {private static final String DESCRIPTOR = "CalcService"; private static final String TAG = "server"; public void onCreate () {Log. e (TAG, "onCreate") ;}@ Overridepublic int onStartCommand (Intent intent, int flags, int startId) {Log. e (TAG, "onStartCommand"); return super. onStartCommand (intent, flags, startId);} public IBinder onBind (Intent t) {Log. e (TAG, "onBind"); return mBinder;} public void onDestroy () {Log. e (TAG, "onDestroy"); super. onDestroy ();} public boolean onUnbind (Intent intent) {Log. e (TAG, "onUnbind"); return super. onUnbind (intent);} public void onRebind (Intent intent) {Log. e (TAG, "onRebind"); super. onRebind (intent);} private MyBinder mBinder = new MyBinder (); private class MyBinder extends Binder {@ Overrideprotected boolean onTransact (int code, Parcel data, Parcel reply, int flags) throws RemoteException {switch (code) {case 0x110: {Log. e (TAG, "0x110"); data. enforceInterface (DESCRIPTOR); int _ arg0; _ arg0 = data. readInt (); int _ arg1; _ arg1 = data. readInt (); int _ result = _ arg0 * _ arg1; reply. writeNoException (); reply. writeInt (_ result); return true;} case 0x111: {Log. e (TAG, "0x111"); data. enforceInterface (DESCRIPTOR); int _ arg0; _ arg0 = data. readInt (); int _ arg1; _ arg1 = data. readInt (); int _ result = _ arg0/_ arg1; reply. writeNoException (); reply. writeInt (_ result); return true ;}} return super. onTransact (code, data, reply, flags) ;};} customizes a Binder subclass, And then rewrites its onTransact Method

Register a service in AndroidManifest. xml
        <service android:name="com.realize.lizijun.noaidl_binder_server.CalcService">            <intent-filter>                <action android:name="com.realize.noaidl.calc">                <category android:name="android.intent.category.DEFAULT">            </category></action></intent-filter>        </service>
4.2 Client

Create a project. Its main activity is as follows:

 

Package com. realize. lizijun. noaidl_binder_client; import android. app. activity; import android. content. componentName; import android. content. context; import android. content. intent; import android. content. serviceConnection; import android. OS. bundle; import android. OS. IBinder; import android. OS. remoteException; import android. util. log; import android. view. view; import android. widget. toast; public class MainActi Extends Activity {private static final String TAG = "client"; private IBinder mPlusBinder = null; private ServiceConnection mServiceConnPlus = new ServiceConnection () {// only when servie exits unexpectedly, the system will call onServiceDisconnected () @ Overridepublic void onServiceDisconnected (ComponentName name) {Log. e (TAG, "mServiceConnPlus onServiceDisconnected"); mPlusBinder = null ;}@ Overridepublic void onServiceConnected (Compone NtName name, IBinder service) {Log. e (TAG, "mServiceConnPlus onServiceConnected"); mPlusBinder = service ;};@ Overrideprotected void onCreate (Bundle savedInstanceState) {super. onCreate (savedInstanceState); setContentView (R. layout. activity_main);} public void bindService (View view) {Intent intentPlus = new Intent (); intentPlus. setAction ("com. realize. noaidl. calc "); boolean result = bindService (intentPlus, MServiceConnPlus, Context. BIND_AUTO_CREATE); Log. e (TAG, result + "");} public void unbindService (View view) {if (mServiceConnPlus! = Null) {Log. e (TAG, "unbindService"); unbindService (mServiceConnPlus); // mServiceConnPlus = null ;}} public void mulInvoked (View view) {if (mPlusBinder = null) {Toast. makeText (this, "the server is not connected or the server is killed abnormally", Toast. LENGTH_SHORT ). show ();} else {android. OS. parcel _ data = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); int _ result = 0; try {_ data. writeInterfaceToken ("CalcService"); _ data. writeInt (50); _ data. writeInt (12); mPlusBinder. transact (0x110, _ data, _ reply, 0); _ reply. readException (); _ result = _ reply. readInt (); Toast. makeText (this, _ result + "", Toast. LENGTH_SHORT ). show ();} catch (RemoteException e) {e. printStackTrace ();} finally {_ reply. recycle (); _ data. recycle () ;}} public void divInvoked (View view) {if (mPlusBinder = null) {Toast. makeText (this, "the server is not connected or the server is killed abnormally", Toast. LENGTH_SHORT ). show ();} else {android. OS. parcel _ data = android. OS. parcel. obtain (); android. OS. parcel _ reply = android. OS. parcel. obtain (); int _ result = 0; try {_ data. writeInterfaceToken ("CalcService"); _ data. writeInt (36); _ data. writeInt (12); mPlusBinder. transact (0x111, _ data, _ reply, 0); _ reply. readException (); _ result = _ reply. readInt (); Toast. makeText (this, _ result + "", Toast. LENGTH_SHORT ). show ();} catch (RemoteException e) {e. printStackTrace ();} finally {_ reply. recycle (); _ data. recycle ();}}}}

The interface is as follows:

 

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.