AIDL explanation - in-depth analysis

When I first came into contact aidlwith it, I felt that this was difficult. For me, an Android novice, it is not necessary to understand his principles.

In fact, it is quite simple to look at it step by step.

Use of aidl

The most common aidl use is Service cross-process communication, so let's write a Activity and Service cross-process communication.

First of all, we create a new aidlfile in AS (ps: now AS aidldoes not require the same name as the java package):

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
            String getInfor(String s);
}

The basicTypes method can be ignored. We define a getInfor() method here , which accepts a string parameter and returns a string. Well, it is quite simple.

Then we sync project app/generated/source/aidl/debug/aidlto find the java file generated by aidl, which is automatically generated by AS, first code

package com.example.haley.coolweather;
// Declare any non-default types here with import statements

public interface IMyAidlInterface extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.haley.coolweather.IMyAidlInterface
{
private static final java.lang.String DESCRIPTOR = "com.example.haley.coolweather.IMyAidlInterface";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.example.haley.coolweather.IMyAidlInterface interface,
 * generating a proxy if needed.
 */
public static com.example.haley.coolweather.IMyAidlInterface asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface (DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.haley.coolweather.IMyAidlInterface))) {
return ((com.example.haley.coolweather.IMyAidlInterface)iin);
}
return new com.example.haley.coolweather.IMyAidlInterface.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_basicTypes:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
long _arg1;
_arg1 = data.readLong();
boolean _arg2;
_arg2 = (0!=data.readInt());
float _arg3;
_arg3 = data.readFloat();
double _arg4;
_arg4 = data.readDouble();
java.lang.String _arg5;
_arg5 = data.readString();
this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
reply.writeNoException();
return true;
}
case TRANSACTION_getInfor:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
java.lang.String _result = this.getInfor(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.haley.coolweather.IMyAidlInterface
{
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 you can use as parameters
     * and return values in AIDL.
     */
@Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(anInt);
_data.writeLong(aLong);
_data.writeInt (((aBoolean)? (1) :( 0)));
_data.writeFloat(aFloat);
_data.writeDouble(aDouble);
_data.writeString(aString);
mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(s);
mRemote.transact(Stub.TRANSACTION_getInfor, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getInfor = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
/**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
public java.lang.String getInfor(java.lang.String s) throws android.os.RemoteException;
}

The code here is a long one, we don't have to look at him first, let's look at the service first

public class MyService extends Service {
   
public final static String TAG = "MyService";

private IBinder binder = new IMyInterface.Stub() {
        @Override       
        public String getInfor(String s) throws RemoteException {
            Log.i(TAG, s);
            return "I am the string returned by Service";
       }
    };
@Overrid
public void onCreate() {
    super.onCreate();
    Log.i(TAG, "onCreat");    
}       
@Override    
public IBinder onBind(Intent intent) {
    return binder;  
    }
}

Here, we first create a new ImyInterface.stub(), and convert it up to IBinder, return it in the inBInder() method, and rewrite the abstract method we defined above. As we can see above, ImyInterface.stub is An inner class of ImyInterface that inherits Binder and implements the interface we just defined. In the generated .java file, most of the code is this inner class.

Because it is cross-process communication, you also need to add a process attribute when declaring service in the AndroidManifest.xml file, as shown in the figure

<service
    android:name=".server.MyService"
    android:process="com.mathiasluo.remote" />

Let's look at Activity

public class MainActivity extends AppCompatActivity {
    public final static String TAG = "MainActivity";
    private IMyInterface myInterface;
    private ServiceConnection serviceConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            myInterface = IMyInterface.Stub.asInterface(service);
            Log.i(TAG, "Successful connection to Service");
            try {
                String s = myInterface.getInfor("I am the string from Activity");
                Log.i(TAG, "String obtained from Service: " + s);
            } catch (RemoteException e) {
                e.printStackTrace ();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.e(TAG, "Failed to connect to Service");
        }
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate (savedInstanceState);
        setContentView(R.layout.activity_main);
        startAndBindService ();
    }
    private void startAndBindService() {
        Intent service = new Intent(MainActivity.this, MyService.class);
        //startService(service);
        bindService(service, serviceConnection, Context.BIND_AUTO_CREATE);
    }
}

First of all, we should understand that what is returned is IBinderwhat we are in Servicethe onBind( )method return, IBinderand then we call Stubthe static method in asInterfaceand pass the returned one as a IBinderparameter.
In the asInterfacemethod, it is first judged whether it is passed in , and if it is, IBinderit returns one ; then it is judged whether the passed in is in the current process, if it is, it returns directly, if it is not, it returns . What I think I need to understand here is that what is returned directly implements the defined interface method . Because of what is achieved in. Of course, if it is in the same process, then the method we call is to call the method locally, and we can call it directly.nullnullnullIBinderIMyInterfaceIMyInterface.Stub.Proxy(obj)IMyInterfacegetInforIMyInterface.StubIMyInterface

If not in the same process, it will return IMyInterface.Stub.Proxy(obj):

Then in the static inner class of Proxy, here we call the IBindermethod transactto pass the data to the remote server. Then in our remote MyService, the inside Stubwill call back onTransact()(because you pass the data to a remote service, the remote service will call back when it receives the data)

Therefore, when we make a simple call IMyInterface, getInforwe first send Proxythe transactdata, then the server onTransactaccepts and processes the incoming data, and then writes the processed data into the return value and sends it to the client. After the client reads the value, it will The return value of the calling method is returned.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325659968&siteId=291194637