I want to implement in aidl (aosp) android a callback function which shall transfer multiple values than just one. How to solve that? Using a Pair object? Or is there any other better way?
-
1Do you mean a callback that returns multiple values? Or a callback that takes multiple values as input? The latter case seems straightforward, so I assume you mean the former. You could return multiple values by adding parameters marked as `out` to the function. That seems easier to me than adding a new pair object. Of course if the values you return are in some way tightly coupled, then from a design perspective it would make sense to use a kind of pair object. – f9c69e9781fa194211448473495534 Jan 14 '21 at 03:56
-
Yes a callback that returns multiple value. Yes, they are indeed coupled. Like: "Title" and "Content" of a book. – tailor Jan 14 '21 at 10:55
-
Ok, in that case you could create a new parcelable type. What language are you targeting (i.e. Java or C++)? For C++ you can see how to create a custom parcelable [here](https://stackoverflow.com/questions/65284392/aidl-interface-between-java-and-c/65348028#65348028), for Java e.g. [here](https://stackoverflow.com/questions/7181526/how-can-i-make-my-custom-objects-parcelable). – f9c69e9781fa194211448473495534 Jan 14 '21 at 11:46
-
thx, I'm using java. – tailor Jan 14 '21 at 13:14
-
@f9c69e9781fa194211448473495534 do you maybe also know a good plain example implementing a simple callback into aidl. – tailor Jan 15 '21 at 11:10
1 Answers
Here is an example for implementing an AIDL callback that returns a custom object, in Java.
Interface specification
SomeResult.aidl
You would define an AIDL for the custom class that you want to transfer over binder.
package com.example; parcelable SomeResult;
ISomeCallback.aidl
You would have an AIDL for your callback. Note this imports the previous AIDL for the parcelable.
package com.example; import com.example.SomeResult; interface ISomeCallback { SomeResult getResult(); }
ISomeService.aidl
You would have an AIDL for your service. Your service could have some method which takes the callback as an input. Of course, it would also be possible to have a method which returns a callback, depending on what you want to do.
package com.example; import com.example.ISomeCallback; interface ISomeService { void someAction(ISomeCallback callback); }
Implementation
You can then write Java classes which implement these interfaces.
SomeResult.java
The parcelable type has to implement the
Parcelable
interface. You have to provide implementations for how to write/read your custom class to/from aParcel
. Usually this is done by writing each member of the class to the parcel and then reading them back out again in the same order.package com.example; import android.os.Parcel; import android.os.Parcelable; public class SomeResult implements Parcelable { private String someData1; private String someData2; public SomeResult(String someData1, String someData2) { this.someData1 = someData1; this.someData2 = someData2; } @Override public int describeContents() { return 0; // No special data, such as file descriptors } @Override public void writeToParcel(Parcel out, int flags) { out.writeString(someData1); out.writeString(someData2); } public static final Parcelable.Creator<SomeResult> CREATOR = new Parcelable.Creator() { public SomeResult createFromParcel(Parcel in) { return new SomeResult(in.readString(), in.readString()); } public SomeResult[] newArray(int size) { return new SomeResult[size]; } }; }
SomeCallback.java
In your callback you would then construct a new instance of your custom class and return it.
package com.example; import com.example.ISomeCallback; import com.example.SomeResult; public class SomeCallback extends ISomeCallback.Stub { @Override public SomeResult getResult() { return new SomeResult("Hello", "world!"); } }
SomeService.java You would implement the method of the service that takes the callback. In the method, you can then invoke the callback to obtain instances of your custom class.
package com.example; import android.os.RemoteException; import com.example.ISomeService; public class SomeService extends ISomeService.Stub { @Override public void someAction(ISomeCallback callback) throws RemoteException { SomeResult result = callback.getResult(); // ... } }
Usage
To use your service, you would for example obtain a proxy object from the service manager (assuming your service runs as a system service, if your service is run by some other means, your way for obtaining the proxy object would differ). You would then construct an instance of your callback class and call the service method with your callback as parameter:
ISomeService someService = ISomeService.Stub.asInterface(
ServiceManager.getService("some_service"));
ISomeCallback someCallback = new SomeCallback();
try {
someService.someAction(someCallback);
} catch (RemoteException ex) {
// TODO Handle error
}

- 4,361
- 2
- 13
- 40
-
Thank you very much for your snippets. I appreciate. What I don't understand is (maybe we misunderstood each other): I want to have a listener which listens to callbacks from service, without my client needs to ask for it. Imagine following scenario: In system service is a server running, waiting for messages over tcp. Whenever a message arrives, it shall forward it to the client, which has started the service. – tailor Jan 16 '21 at 12:52
-
Maybe that's possible with your snippet above, but it looks like the client have to call a method and get a return value, actively. But what I wish is a java like listener pattern. – tailor Jan 16 '21 at 12:53
-
Ok, I don't know the details of how you are starting the service. How are you making the client known to the service? Is there a 1-to-1 relation between client and service or will one service manage multiple clients? Using the example code above, you wouldn't necessarily have the client ask for each callback invocation. You could also rename `someAction` to e.g. `registerClient` and have that method store the callback in some `List
` on the service side. When the service processes an event, it could then go through this list and trigger each callback from that list. – f9c69e9781fa194211448473495534 Jan 16 '21 at 20:05 -
Yes u did understand me right. But how will the client be informed about the triggered callback? Because I don't have any listener in client side listening to any event from service side. – tailor Jan 17 '21 at 02:00
-
The `ICallback` that arrives at the service is a proxy object that forwards all calls over binder to the original instance. So when the service calls `callback.getResult()`, the `getResult` function is run in the client process (and the result is transferred back over binder to the service). In particular, this means you can modify the client state from your implementation of `getResult`. – f9c69e9781fa194211448473495534 Jan 17 '21 at 02:32