AIDL basically uses 3 - in out of inout

Posted by mfouts on Sun, 30 Jun 2019 01:11:53 +0200

In AIDL, incoming parameters from client and server can be set to flow direction. Only parameters do not contain return values.
1. in: The client can pass in parameters to the service (default method)
2. out: The server modifying the client's incoming parameter object will affect the client's incoming instance
3. inout: The server can either accept client parameters or modify their impact on client instances

Where is the label?

Here we use AIDL Basic Demo 2 as an example: AIDL Basic Usage 2

IMyAidlInterface.aidl is used as the interface between client and server in two basic cases of AIDL usage.

// IMyAidlInterface.aidl
package com.ucoupon.myservice;
import com.ucoupon.myservice2.Book;

interface IMyAidlInterface {

    String bookIn(in Book mbook);
    String bookOut(out Book mbook);
    String bookInout(inout Book mbook);
}

As you can see from the above code, in out inout is used to modify the input parameters in the aidl interface.

Let's review what's in Book.java.

package com.ucoupon.myservice2;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by FMY on 2017/5/18.
 */

public class Book implements Parcelable {

    String name;

    int id;

    public Book(String name, int id) {
        this.name = name;
        this.id = id;
    }

    protected Book(Parcel in) {
        name = in.readString();
        id = in.readInt();
    }

    public static final Creator<Book> CREATOR = new Creator<Book>() {
        @Override
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        @Override
        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(name);
        dest.writeInt(id);
    }
}

A very common class has two fields

  • Let's compile and see
    Compilation error, error in automatic generation interface java file. new Book() can not be instantiated.
    Because there is no such construction method at all.

Why did we not report an error in AIDL Basic 2?
Continue to view the source code

If the modifier parameter is out, an empty constructor of the modifier parameter is automatically created.
In this example, the following methods are modified out:
String bookOut(out Book mbook);

Solution: Create an empty construction method

  • Continue compiling
    Compile and Error Reporting

You can see that Book instantiates the call to the readFromParcel method. But book does not have this method.

Solution:
Add this method to the Book class. This method is used for the client to use out or inout modified method to read the value of the modified object at the server and assign it to the client.

package com.ucoupon.myservice2;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by FMY on 2017/5/18.
 */

public class Book implements Parcelable {


....

    public void readFromParcel(Parcel reply) {
        name = reply.readString();
        id = reply.readInt();

    }
    .....
}

After modification, it is compiled and passed.

Then you skip the step of copying the file to the client for binding operations.

in test

Look at the service segment code

package com.ucoupon.myservice;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import android.util.Log;

import com.ucoupon.myservice2.Book;

public class MyService extends Service {
    public MyService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.d(TAG, "onCreate() called");
    }

    //Callback at binding time
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind() called with: intent = [" + intent + "]");
        return new MyAidlInterface();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand() called with: intent = [" + intent + "], flags = [" + flags + "], startId = [" + startId + "]");
        return super.onStartCommand(intent, flags, startId);
    }

    @Override
    public void unbindService(ServiceConnection conn) {
        Log.d(TAG, "unbindService() called with: conn = [" + conn + "]");
        super.unbindService(conn);
    }

    @Override
    public void onRebind(Intent intent) {
        Log.d(TAG, "onRebind() called with: intent = [" + intent + "]");
        super.onRebind(intent);
    }

    @Override
    public boolean onUnbind(Intent intent) {
        Log.d(TAG, "onUnbind() called with: intent = [" + intent + "]");
        return super.onUnbind(intent);
    }

    @Override
    public void unregisterReceiver(BroadcastReceiver receiver) {
        Log.d(TAG, "unregisterReceiver() called with: receiver = [" + receiver + "]");
        super.unregisterReceiver(receiver);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy() called");
    }

    @Override
    public void onStart(Intent intent, int startId) {
        Log.d(TAG, "onStart() called with: intent = [" + intent + "], startId = [" + startId + "]");
        super.onStart(intent, startId);
    }

    private static final String TAG = "MyService";

    class MyAidlInterface extends IMyAidlInterface.Stub{


        @Override
        public String bookIn(Book mbook) throws RemoteException {
            Log.d(TAG, "bookIn() called with: mbook = [" + mbook + "]");

            mbook.id = 233;

            return null;
        }

        @Override
        public String bookOut(Book mbook) throws RemoteException {
            Log.d(TAG, "bookout() called with: mbook = [" + mbook + "]");

            mbook.id = 233;
            return null;
        }

        @Override
        public String bookInout(Book mbook) throws RemoteException {
            Log.d(TAG, "bookInout() called with: mbook = [" + mbook + "]");

            mbook.id = 233;
            return null;
        }
    }
}

Client:

package com.ucoupon.aidlstudy;

import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;

import com.ucoupon.myservice.IMyAidlInterface;
import com.ucoupon.myservice2.Book;

public class MainActivity extends AppCompatActivity {

    private Myconnect myconnect;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //Connection Management
        myconnect = new Myconnect();


        //intention
        Intent intent = new Intent();

        intent.setClassName("com.ucoupon.myservice","com.ucoupon.myservice.MyService");

        startService(intent);

        //Start binding services
        bindService(intent,myconnect,BIND_AUTO_CREATE);




    }

    private static final String TAG = "MainActivity";

    class Myconnect implements ServiceConnection {

        //Callback when the connection is successful
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(TAG, "onServiceConnected() called with: name = [" + name + "], service = [" + service + "]");


            IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);


            Book mBook = new Book("Client", -1);

            try {
                Log.e("fmy","Client did not call bookin Pre-method mBook: name = "+mBook.name+","+" id"+mBook.id);
                iMyAidlInterface.bookIn(mBook);
                Log.e("fmy","After client calls bookin After method mBook: name = "+mBook.name+","+" id"+mBook.id);
            } catch (RemoteException e) {
                e.printStackTrace();
            }

            //Unbundling service
//            unbindService(myconnect);
        }

        //Callback when disconnected
        @Override
        public void onServiceDisconnected(ComponentName name) {

            Log.d(TAG, "onServiceDisconnected() called with: name = [" + name + "]");
        }
    }
}

Results Forecast:
According to the preface in, the client can pass in an object to the server. But it is not effective for the server to modify the client instance after the server gets the object.

Operation results:
Client:

E/fmy: Before the client calls the bookin method, mBook: name = client, id-1
 mBook: name = client, id-1

Server side:

 mbook = [Book{name='Client', id=-1}]

From the above log, we can see that there is no change in the book instance before and after the client call.
The server also correctly reads to the client to send the book instance information.
Look back at the bookIn method.

  @Override
        public String bookIn(Book mbook) throws RemoteException {
            Log.d(TAG, "bookIn() called with: mbook = [" + mbook + "]");

            mbook.id = 233;

            return null;
        }

In this method, bookIn modifies the id of the incoming Book object to 233. But does the client affect its own book object after calling it?

out test

The client code is similar to the in test above, just changing the call to the bookout method.
Client:

Book mBook = new Book("Client", -1);

 try {
     Log.e("fmy","Client did not call bookout Pre-method mBook: name = "+mBook.name+","+" id"+mBook.id);
     iMyAidlInterface.bookOut(mBook);
     Log.e("fmy","After client calls bookout After method mBook: name = "+mBook.name+","+" id"+mBook.id);
 } catch (RemoteException e) {
     e.printStackTrace();
 }

Expected results:
out Definition: The server can't read the parameters passed in from the client, but can change the incoming object, and then affect the instance object of the client.

The client did not call the bookout method before mBook: name = client, id-1
 mBook: name = null, id233 after the client calls the post-bookout method

Server side:

mbook = [Book{name='null', id=0}]

Correct judgment: Because out is the client can not pass parameters to the server, so the book parameters of the server are default values.
At this point, the server modifies the book's id to 233. Then the server's book is returned. So the client's name is empty and the id is 233.

AIDL basically uses 4 - link ToDeath and unlinkToDeath

Topics: Android Java