Friday, February 8, 2013

Inter Process Communication on Android: Binders and Aidl

In contrast with iOS, where an app can be responsible for only one process at a time, Android provides many ways to create an app which spawns two or many processes. On Android instead, there is the possibility for two different apps (i.e. two different apks) to communicate, or two processes that live in the same apk but in different processes.
In both cases, the system must provide a "channel" that allows two processes to communicate. In contrast with threads, two processes don't share memory for data, therefore the system must provide a way for the data to cross the process boundaries.

Historically, have been defined many ways to create a communication between two processes (for example, CORBA, or JRMI); Android has defined its own implementation: it is called AIDL, and the acronym stands for Android Interface Definition Language.

This blog post describe how to create a simple application that spawns two processes, and in detail shows two ways to implement it. The first is through the Messenger class and in many cases it is enough powerful, the second one is more low level, but requires to implement an AIDL interface. In detail, there is a simple Activity that lives in a process (the process where the app lives) and two services. Both the services are remote; the first one communicates with the activity via a Messenger, the second via the AIDL.

In the code above, there is the important part of the manifest, where the two services are declared. As we can see, to declare a service as remote, we must specify the android:process attribute. The exported attribute tells the system if a component can be exposed to other applications; in case it is true, another app can launch the component. But this is not relevant in our context.

IPC with Messenger and Handler

This mechanism allows two process to communicate and save the developer from creating AIDL files and it is more simple and straightforward; the system under the hood however will use AIDL but the developer doesn't see it.

In the code above, it is shown how the service is created and bound.

In the code above, it is shown how the remote service is implemented. If the service is remote, we must implement the method onBind(); the three fundamental components are: binder, messenger and handler.
The service use a handler, used to receive data from a remote process; the binder is as its name suggests, the "thing" that binds the two processes.  The messenger is tied to the binder and provides a convenient way for the two sides to communicate effectively. In the example above,  the activity generates a Messenger from the binder received as parameter in the onServiceConnected() callback. It will use the messenger to send data to the remote process (method sendMessage()). In the, the handler is used to receive data from the remote process.

The example shows that the Process ID of the sender is different from the process ID of the receiver and the string sent from the activity is correctly received from the service, that lives in its own process.


If we want to use AIDL, we must first specify an interface between the client process and the server one; it is a file with methods shared between the client and the server. These methods are the "entry points" for a process to start the communication with the other process.
In our case, the scenario is very simple. The aidl file contains only a method (multiply) that multiplies two numbers. The service will take care of the mathematical operation. In the example we don't return a value to the client, but of course it can be done.
When we define an aidl file, the system will generate the relative implementation in the /gen directory. If you have a look at the implementation, it is easy to spot what happens under the hood: the data which have been serialized before the dispatch, are then received as a Parcelable object, deserialized and then the method at the server side (in this case multiply) is finally called.

The service implements the Stub (defined as an abstract class in the auto-generated file); the Stub is also the binder (extends Binder).
The activity retrieves the interface to communicate with the server via this method:
multiplierService = IMultiplier.Stub.asInterface(service);
It returns a client-stub that has the same interface as the counterpart implemented at the server side (AidlService).
When we have the instance, we can banally call the multiply method as if it were a local method:

multiplierService.multiply(5, 7);

The complete code can be found here: