views:

41

answers:

2

I am designing a framework for a client/server application for Android phones. I am fairly new to both Java and Android (but not new to programming in general, or threaded programming in particular).

Sometimes my server and client will be in the same process, and sometimes they will be in different processes, depending on the exact use case. The client and server interfaces look something like the following:

IServer.aidl:

package com.my.application;

interface IServer {

    /**
     * Register client callback object
     */
    void registerCallback( in IClient callbackObject );

    /**
     * Do something and report back
     */
    void doSomething( in String what );
  .
  .
  .
}

IClient.aidl:

package com.my.application;

oneway interface IClient {

    /**
     * Receive an answer
     */
    void reportBack( in String answer );
  .
  .
  .
}

Now here is where it gets interesting. I can foresee use cases where the client calls IServer.doSomething(), which in turn calls IClient.reportBack(), and on the basis of what is reported back, IClient.reportBack() needs to issue another call to IClient.doSomething().

The issue here is that IServer.doSomething() will not, in general, be reentrant. That's OK, as long as IClient.reportBack() is always invoked in a new thread. In that case, I can make sure that the implementation of IServer.doSomething() is always synchronized appropriately so that the call from the new thread blocks until the first call returns.

If everything works the way I think it does, then by declaring the IClient interface as oneway, I guarantee this to be the case. At least, I can't think of any way that the call from IServer.doSomething() to IClient.reportBack() can return immediately (what oneway is supposed to ensure), yet IClient.reportBack still be able to reinvoke IServer.doSomething recursively in the same thread. Either a new thread in IServer must be started, or else the old IServer thread can be re-used for the inner call to IServer.doSomething(), but only after the outer call to IServer.doSomething() has returned.

So my question is, does everything work the way I think it does? The Android documentation hardly mentions oneway interfaces.

A: 

That's OK, as long as IClient.reportBack() is always invoked in a new thread.

It will never be "invoked in a new thread", unless you are the one forking the thread. Android always calls you on the main application thread.

If everything works the way I think it does, then by declaring the IClient interface as oneway, I guarantee this to be the case.

Android has no oneway keyword that I can find.

CommonsWare
I refer you to the file samples\android-7\ApiDemos\src\com\example\android\apis\app\IRemoteServiceCallback.aidl in the Android sdk. This file, containing the word oneway is found in versions 3, 4, 7 and 8. Also, http://developer.android.com/reference/android/os/IBinder.html mentions FLAG_ONEWAY, which appears to be part of the implementation for this feature. A google search on "Android oneway" turns up the following site: http://mylifewithandroid.blogspot.com/2010/01/oneway-interfaces.html.That's the extent of the documentation that I have been able to find.
Dan Menes
Android does not "always calls you on the main application thread." According to http://developer.android.com/guide/topics/fundamentals.html "When a call on a method implemented in an IBinder object originates in the same process as the IBinder, the method is executed in the caller's thread. However, when the call originates in another process, the method is executed in a thread chosen from a pool of threads that Android maintains in the same process as the IBinder; it's not executed in the main thread of the process." This does not seem to apply to the case of a "oneway" interface, however.
Dan Menes
@Dan Menes: My apologies on the threading issue. That being said, since the details of the "pool of threads" are lacking, I would be very cautious about assuming anything regarding the the underlying implementation. Similarly, I would be very hesitant to use the generally undocumented `oneway`.
CommonsWare
@CommonsWare: I'll run some tests tomorrow and see how they turn out.
Dan Menes
+1  A: 

The oneway keyword means that if that call results in an IPC (i.e. the caller and callee are in different processes) then the calling process will not wait for the called process to handle the IPC. If it does not result in an IPC (i.e. they're both in the same process), the call will be synchronous. It's an unfortunate detail that simplifies the implementation of binder IPC a lot. If they're in the same process, the call is just a regular java method call.

joeo
Thanks. That's the kind of gotcha I was worried about.
Dan Menes
I have built a test application and confirmed that you are correct. When called from a different process, the behavior is as documented--the call to the method in the oneway interface is asynchronous--but when called from the same process, the call is synchronous.
Dan Menes