Does oneway declaration in Android .aidl guarantee

2019-02-01 15:10发布

问题:

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.

回答1:

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.