Saturday, January 16, 2010

Oneway interfaces

In early betas, the Android IPC was strictly synchronous. This means that service invocations had to wait for the return value of the remote method to arrive back to the caller. This is generally an advantage because the caller can be sure that the called service received the invocation by the time the remote method returns. In some cases, however, this causes the caller to wait unnecessarily. If synchronicity is not required and the method has no return value, oneway AIDL interfaces may be used.

Oneway methods are specified by addind the oneway keyword to the AIDL interface definition.

oneway interface IncreaseCounter { void increaseCounter( int diff ); }

Only the entire interface can be oneway and these methods must all have void return value. The stub compiled from oneway AIDL interface does not have return path for remote methods on the service side and does not wait for the method to execute on the client side. The delivery is reliable (no invocations are lost) but the timing is not guaranteed, e.g. two sequential oneway invocations may arrive at the invoked service in different order. Oneway interfaces are therefore more complicated to use (they are also faster and don't block the caller) and are used extensively by the Android framework internally to deliver event notifications.

Click here to download the example program.

Our primitive example has an Activity and a Service. The service exposes two interfaces: one "normal" (Counter.aidl) and one oneway (increaseCounter.aidl). The interesting bit here is how one service can expose two interfaces. The onBind method checks the Intent used to bind the service and returns different binders based on the Intent. The important point here not to use the Intent extra Bundle to differentiate among interfaces. I did this and I can confirm that even though extras arrive at onBind (the API documentation states the contrary) but the framework gets completely confused and thinks that the service has already been bound with the same Intent (the framework seemingly cannot figure out that the Intent extras were different). In the example program I abused the category field therefore and this works nicely.


Anonymous said...

releaseService() isn't invoked in onDestory in the enclosed example... :-)

Gabor Paller said...

I am not aware of such a method in Android ...

michal said...

cool example thanks for sharing!

Elangovan Manickam said...

I know this thread is 7 years old now. But I just want to point few things about this blog.

First, the onBind() method on the service will receive the call only once in its lifetime. Even though multiple clients trying to bind to the same service, the android system just returns the cached IBinder object without calling the onBind method. So I couldn't understand how your 'If' condition in the onBind method will work. if you want them to work then you need to stop the service before binding again.

Second, the oneway keyword don't have any impact if the service and client are in same application or in same process. Your example looks like having all in one app. So the asynchronous behavior that you expect wont happen.