Does oneway declaration in Android .aidl guarantee that method will be called in a separate thread?
Asked Answered
S

2

8

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.

Savil answered 14/6, 2010 at 23:45 Comment(0)
F
27

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.

Fancyfree answered 15/6, 2010 at 4:28 Comment(1)
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.Savil
B
2

From Android document

The oneway keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the Binder thread pool as a normal remote call. If oneway is used with a local call, there is no impact and the call is still synchronous

For example, we have a Client app and a Server app, and an AIDL interface like

interface IRemoteService {
     oneway void onewayFunctionCall(int value); // function take 1 seconds to complete
     void noneOneWayFunctionCall(int value); // function take 1 seconds to complete
}

oneway will affect the method in the Client app (remote call).
For example, we call server service from Client app like

for (i in 0..5) {
    Log.i("TAG", "call $i") // fired each 1 second
    iRemoteService?.noneOneWayFunctionCall(i)
}
// run synchronous
for(i in 0..5) {
    serverService.onewayFunctionCall(i); // fired right after previous function call
}
// run asynchronous

Because oneway method call and don't wait for the result so it must be void function.

In the above case, we call server service from a single thread (main thread) so the function can block. So I think oneway only useful in a single thread.

If we call from a single thread in the client app, the method in the server (oneway / none oneway) still executes synchronously.

If we use multiple threads in the client app to call server service, the method in the server will execute asynchronously

Barbicel answered 1/2, 2021 at 10:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.