Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass active objects between services through AIDL

I'm trying to have a common object shared for several services in different packages. Each service must call the same object.

For example, Service A (from APK A) instantiates a custom object and I want that Service B and C (from APK B and C) retrieves the reference of this object and call some method of it.

I found in the Android reference that it should be possible by using Parcel :

Active Objects

An unusual feature of Parcel is the ability to read and write active objects. For these objects the actual contents of the object is not written, rather a special token referencing the object is written. When reading the object back from the Parcel, you do not get a new instance of the object, but rather a handle that operates on the exact same object that was originally written. There are two forms of active objects available.

Binder objects are a core facility of Android's general cross-process communication system. The IBinder interface describes an abstract protocol with a Binder object. Any such interface can be written in to a Parcel, and upon reading you will receive either the original object implementing that interface or a special proxy implementation that communicates calls back to the original object. The methods to use are writeStrongBinder(IBinder), writeStrongInterface(IInterface), readStrongBinder(), writeBinderArray(IBinder[]), readBinderArray(IBinder[]), createBinderArray(), writeBinderList(List), readBinderList(List), createBinderArrayList().

I tried to do this by passing my object (who extends binder) through AIDL but nothing works, I always gets a ClassCastException when I'm trying to retrieve the reference from the method createFromParcel(Parcel in).

An example of my code :

public class CustomObject extends Binder implements Parcelable {

  public CustomObject() {
    super();
  }

  public static final Parcelable.Creator<CustomObject> CREATOR = new Parcelable.Creator<CustomObject>() {
  public CustomObject createFromParcel(Parcel in) {
    IBinder i = in.readStrongBinder();
      // HOW TO RETRIEVE THE REFERENCE ??
      return null;
    }

    @Override
    public CustomObject[] newArray(int size) {
      return null;
    }
  };

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

  @Override
  public void writeToParcel(Parcel dest, int flags) {
    dest.writeStrongBinder(this);
  }
}

Is anyone has already done that ?

Thanks in advance !

like image 780
nbe_42 Avatar asked Nov 03 '22 21:11

nbe_42


1 Answers

Here are two approaches.

Simple: use aidl for the object itself

  • It seems you have an existing AIDL interface through which you pass this 'custom object' as a parcel. Don't do that. Instead:
  • The object which you pass through should be itself described by AIDL. Say, for example, you call it ICustomObject.aidl.
  • In this case you do not need to make the object Parcelable. You probably don't even need to write the above code; just use one AIDL-described type in another. For example add a line like this to the main AIDL for service A:

    ICustomObject getCustomObject();
    
  • In service A, within the Stub class you've already got, you'll need to simply return something inheriting from ICustomObject.

  • In services B and C, you can simply call that method to get hold of an ICustomObject. Simple! No parcels, no readStrongBinder(), nothing.

Harder

If you do the above, the Android toolchain generates Java code which marshalls and unmarshalls the object. You could instead write the code yourself.

ICustomObject myObjectWhichActuallyLivesInAnotherProcess = ICustomObject.Stub.asInterface(parcel.readStrongBinder())

or even

ICustomObject myObjectWhichActuallyLivesInAnotherProcess = (ICustomObject)parcel.readStrongBinder().queryLocalInterface("com.your.custom.object");

However I think your life will be more sane if you make everything aidl.

A note on class sharing

You'll probably want to create an Android "library project" which has ICustomObject.aidl within it, such that you can share the resulting classes between the projects which build A, B and C.

like image 84
Adrian Taylor Avatar answered Nov 15 '22 11:11

Adrian Taylor