Transfer active objects between services through AIDL

I am trying to use a shared object for several services in different packages. Each service must call the same object.

For example, service A (from APK A) creates an instance of a custom object, and I want services B and C (from APK B and C) to extract a reference to this object and call some method of it.

I found in the Android reference that this should be possible with Parcel :

Active objects

An unusual feature of Parcel is the ability to read and write objects. For these objects, the actual contents of the object is not written, but rather a special token that refers to the object. When you read an object back from the Parcel, you are not getting a new instance of the object, but rather a descriptor that works with the exact same object that was originally written. There are two forms of active objects available.

Binder objects are the primary means of the overall cross-process Android communication system. The IBinder interface describes an abstract protocol with a Binder object. Any such interface can be written to the Package, and after reading you will receive either the source object of the implementation of this interface or a special proxy implementation that provides feedback to the source object. Ways to use writeStrongBinder (IBinder), writeStrongInterface (IInterface), readStrongBinder (), writeBinderArray (IBinder []), readBinderArray (IBinder []), createBinderArray (), writeBinderList (List), readBinderList (List), createBinderArrayList ().

I tried to do this by passing my object (which extends the middleware) through AIDL, but nothing works, I always get a ClassCastException when I try to get a link from the createFromParcel (Parcel in) method.

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

Has anyone already done this?

Thanks in advance!

+4
source share
3 answers

Here are two approaches.

Simple: use helpl for the object itself

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

     ICustomObject getCustomObject(); 
  • In service A, in the Stub class that you already have, you just need to return something inheriting from ICustomObject .

  • In services B and C, you can simply call this method to get ICustomObject . Just! No parcels, no readStrongBinder() , nothing.

Harder

If you do this above, binding to the Android tool generates Java code that sorts and undoes the object. Instead, you can 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 that your life will become more reasonable if you do everything possible.

Class Sharing Note

You might want to create an Android library project that has ICustomObject.aidl inside it so that you can share the resulting classes between projects that build A, B, and C.

+2
source

Have you looked at the content providers ?

0
source

Having studied this in some detail, I don’t think that it really can be done. The ClassCastException you get is the result of casting BinderProxy (which is a private class that extends IBinder) to your actual class ( CustomObject ). A BinderProxy always passed when it calls Binders through other processes, and this is the object they refer to when they point to "either the source object that implements this interface, or a special implementation of the proxy." BinderProxy allows you to call the onTransact() method of IBinder , but nothing more.

I honestly believe that the documentation is incorrect when they state that the "source object" is passed through processes, as there are several other copies of the documentation for this class: both clearly copied and incorrect .

0
source

Source: https://habr.com/ru/post/1482900/


All Articles