Analysis of Android aidl Binder framework, aidlbinder

Source: Internet
Author: User
Tags mremote

Analysis of Android aidl Binder framework, aidlbinder
Reprinted please indicate the source: http://blog.csdn.net/lmj623565791/article/details/38461079, this article from [Zhang Hongyang's blog]
1. Overview

What can Binder do? Binder provides global services that can be accessed by any program in the system. Of course, this function should be provided by any system. Let's take a brief look at the Binder framework of Android.

The Android Binder framework consists of server interfaces, Binder drivers, and client interfaces. If you want to provide a global service, the global service end is the server interface, and any program is the client interface, they are accessed through a Binder driver.

Server Interface: it is actually an object of the Binder class. Once this object is created, a hidden thread is started internally to receive messages sent by the Binder driver. After receiving the message, the onTransact () function in the Binder object is executed, and different server-side code is executed according to the parameter of the function.

Binder DRIVER: This object is also an instance of the Binder class. The client accesses the remote service through this object.

Client Interface: Get the Binder driver and call its transact () to send messages to the server.

If you do not know the above, it doesn't matter. We will use examples below to better illustrate that practice is the only criterion for testing truth.

2. Use of AIDL

If you are familiar with Android, you must have used AIDL. If you do not know about it, it does not matter. The following example shows how to use AIDL.

We use AIDL to implement a cross-process addition and subtraction call.

1. Server

Create a project, create a package name: com. zhy. calc. aidl, and create an ICalcAIDL file in the package:

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

Note: The file name is ICalcAIDL. aidl.

Then, an ICalcAIDL. java file will be generated under the project's gen directory. The code of this file will not be pasted for the time being, which will be described in detail later.

Then we create a new Service in the project. The Code is as follows:

package com.example.zhy_binder;import com.zhy.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;}};}
In this Service, the generated ICalcAIDL is used to create an mBinder object and the onBind method of the Service returns

Remember to register in AndroidManifest

 <service android:name="com.example.zhy_binder.CalcService" >            <intent-filter>                <action android:name="com.zhy.aidl.calc" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>        </service>

Here we specify a name, because we will use Intent in other applications to find this Service later. This does not require Activity, so I did not write Activity, after the installation is complete, you cannot see the installation icon, Which is quietly running in the background.

At this point, the server has completed writing. Write the client

2. Client

The client code is relatively simple. Create a layout that contains four buttons: bind the service, unbind, call addition, and call subtraction.

Layout file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:onClick="bindService"        android:text="BindService" />    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:onClick="unbindService"        android:text="UnbindService" />    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:onClick="addInvoked"        android:text="12+12" />    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:onClick="minInvoked"        android:text="50-12" /></LinearLayout>

Main Activity

Package com. example. zhy_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. zhy. calc. aidl. ICalcAIDL; public class MainActivity extends Activity {private ICalcAIDL mCalcAidl; private ServiceConnection mServiceConn = new ServiceConnection () {@ Overridepublic void onServiceDisconnected (ComponentName name) {Log. e ("client", "onServiceDisconnected"); mCalcAidl = null ;}@ Overridepublic void onServiceConnected (ComponentName, IBinder service) {Log. e ("client", "onServiceConnected"); mCalcAidl = ICalcAIDL. stub. asInterface (service) ;}}; @ Override Protected 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. zhy. aidl. calc "); bindService (intent, mServiceConn, Context. BIND_AUTO_CREATE);}/*** call * @ param view */public void unBindService (V Iew view) {unbindService (mServiceConn);}/*** call * @ param view */public void addInvoked (View view) When you click the 12 + 12 button) 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 (58, 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 ();}}}

Very standard service binding code.

View the running result directly:

Click BindService to view the log

08-09 22:56:38.959: E/server(29692): onCreate08-09 22:56:38.959: E/server(29692): onBind08-09 22:56:38.959: E/client(29477): onServiceConnected
As you can see, after clicking BindService, the server executes the onCreate and onBind methods, and the client executes the onServiceConnected method, indicating that the server and client are connected

Then, click 12 + 12 and 50-12 to successfully call the server code and return the correct result.

Next, click unBindService.

08-09 22:59:25.567: E/server(29692): onUnbind08-09 22:59:25.567: E/server(29692): onDestroy
Because only one client is bound to this Service, the Service calls onUnbind and onDestory

Then, click 12 + 12, 50-12. We can see that the operation can still be correctly executed. That is to say, even if the onUnbind is called, the connection will not be disconnected. When will the port be opened?

That is, when the server is terminated abnormally, for example, we can find the service in the program being executed on the mobile phone:

Click Stop to view the log

08-09 23:04:21.433: E/client(30146): onServiceDisconnected
You can see that the onServiceDisconnected method is called, and the connection is disconnected. Now, click the buttons 12 + 12, 50-12, and the Toast server disconnection prompt is displayed.

Having said so much, it seems that it has nothing to do with the Binder framework. Let's take a look at what AIDL has done.

3. Analyze the code generated by AIDL
1. Server

Check the server code first. We can see that the service provided by our server is composed

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;}};

ICalcAILD. Stub is executed. Let's take a look at the Declaration of the Stub class:

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

We can clearly see that this class is a sub-class of the Binder. Is it true that the server we mentioned in the article is actually an instance of the Binder class?

Next, let's look at its onTransact () method:

@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);}

At the beginning of this article, we also mentioned that the server-side Binder instance will execute the onTransact Method Based on the messages sent from the client using the Binder driver, and then the server-side code will be executed according to its parameters.

We can see that onTransact has four parameters.

Code, data, replay, flags

Code is the unique identifier of an integer. It is used to identify the method to be executed. The client will pass this parameter to tell the server which method to execute.

Parameters passed by the data Client

Value returned by the replay Server

Flags indicates whether a return value exists. 0 indicates yes (bidirectional), and 1 indicates no (unidirectional)

Let's take a closer look at the Code in case TRANSACTION_min.

Data. enforceInterface (DESCRIPTOR); used with the writeInterfaceToken of the client to identify the remote service name

Int _ arg0;
_ Arg0 = data. readInt ();
Int _ arg1;
_ Arg1 = data. readInt ();

Next, read the two parameters passed in by the client.

Int _ result = this. min (_ arg0, _ arg1 );
Reply. writeNoException ();
Reply. writeInt (_ result );

Then execute this. min, that is, the min method we implemented; The returned result is written back by reply.

Similarly, you can see that the server generates Stub classes through AIDL and encapsulates the code that the server originally needs to write.

2. Client

The client connects to the server through ServiceConnected.

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

If you are sharp, you should guess the IBinder instance in onServiceConnected, which is actually the Binder driver we mentioned in the article and a Binder instance.

The following code is finally called in ICalcAIDL. Stub. asInterface:

return new com.zhy.calc.aidl.ICalcAIDL.Stub.Proxy(obj);

This Proxy instance passes in our Binder driver and encapsulates the code for calling the server. The client will call the server code through the transact () method of the Binder driver.

Directly look at the add method in 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;}

First, declare two Parcel objects, one for passing data, and the other for receiving the returned data.

_ Data. writeInterfaceToken (DESCRIPTOR); corresponds to enforceInterfac on the server.

_ Data. writeInt (x );
_ Data. writeInt (y); write the parameter to be passed

MRemote. transact (Stub. TRANSACTION_add, _ data, _ reply, 0 );

Finally, we can see our transact method. The first one corresponds to the server code, _ data, _ repay, respectively, corresponding to the server data, reply, and 0, indicating that it is bidirectional.

_ Reply. readException ();
_ Result = _ reply. readInt ();

Finally, read the data returned by our server and return. It can be seen that the onTransact of the server basically corresponds to one row.

At this point, we have explained the working principle of the Android Binder framework through the code generated by AIDL. The role of the Service is to create a Binder driver for us, that is, the bridge between the server and the client.

AIDL actually uses the aidl file we wrote to help us generate an interface, a Stub class for the server, and a Proxy class for the client to call. Can we achieve remote communication without writing AIDL? This section describes how to implement communication between the client and the server without relying on AIDL.

4. Implement inter-program communication without relying on AIDL
1. server code

We create a CalcPlusService. java to implement multiplication and division of two numbers.

package com.example.zhy_binder;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 CalcPlusService extends Service{private static final String DESCRIPTOR = "CalcPlusService";private static final String TAG = "CalcPlusService";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:{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:{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);}};}

We implement the server by ourselves, so we have customized a Binder subclass, and then re-write its onTransact method. We specify the service ID as CalcPlusService, then 0x110 as multiplication, and 0x111 as Division;

Remember to register in AndroidMenifest

 <service android:name="com.example.zhy_binder.CalcPlusService" >            <intent-filter>                <action android:name="com.zhy.aidl.calcplus" />                <category android:name="android.intent.category.DEFAULT" />            </intent-filter>        </service>

The server code ends.

2. client code

A project is created separately. The code is similar to the previous example.

First, layout the file:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:onClick="bindService"        android:text="BindService" />    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:onClick="unbindService"        android:text="UnbindService" />    <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:onClick="mulInvoked"        android:text="50*12" />        <Button        android:layout_width="fill_parent"        android:layout_height="wrap_content"        android:onClick="divInvoked"        android:text="36/12" /></LinearLayout>

We can see that multiplication and division are added.

Then the Activity code

Package com. example. zhy_binder_client03; 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 MainActivity extends Activity {private IBinder mPlusBinder; private ServiceConnection mServiceConnPlus = new ServiceConnection () {@ Overridepublic void onServiceDisconnected (ComponentName name) {Log. e ("client", "mServiceConnPlus onServiceDisconnected") ;}@ Overridepublic void onServiceConnected (ComponentName, IBinder service) {Log. e ("client", "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. zhy. aidl. calcplus "); boolean plus = bindService (intentPlus, mServiceConnPlus, Context. BIND_AUTO_CREATE); Log. e ("plus", plus + "");} public void unbindService (View view) {unbindService (mServiceConnPlus);} 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; try {_ data. writeInterfaceToken ("CalcPlusService"); _ 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; try {_ data. writeInterfaceToken ("CalcPlusService"); _ 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 ();}}}}

For clarity, I directly wrote code in mulInvoked, and neither the server nor the server abstracts an interface. When binding a service, use onServiceConnected to obtain the Binder driver, that is, mPlusBinder;

Then prepare the data and call the transact method. The code specifies the method on the server to be executed. The code is consistent with the above analysis.

The running result is as follows:


Is it good to implement the communication between our two applications without using the aidl file? We also analyzed from the aspect that our above analysis is correct.


Now, I believe that after reading this blog, you will have a deeper understanding of aidl and Binder.













Why does android not directly use the linux shared memory mechanism for inter-process communication, but use AIDL to publish service interfaces?

Android seems to be using the Binder driver at the underlying layer for sharing. This driver can avoid many problems with shared memory in Linux. I have not analyzed the details.

For adding a service in the Android framework

Refer to the examples in framework/base/services/java/com/android/server. Generally, a server is composed of xxxxService. java xxxxManager. java IxxxxManager. aidl. Manager and aidl are in frameworks/base/core/java/android /. If you want to run the system at startup, you need to add the code to start your Service in SystemServer. java.

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.