Each application in Android runs in its own process. An application cannot directly access another application's memory space. This is called application sandboxing.
In order to allow cross-application communication, Android provides an implementation of interprocess communication (IPC) protocol. IPC protocols tend to get complicated because of all the marshaling/un marshaling of data that is necessary.
To help with this, Android provides Android Interface Definition Language, or AIDL. It is a lightweight implementation of IPC using a syntax that is very familiar to Java developers, and a tool that automates the stub creation.
In order to allow for one application to call into another, we typically have to:
1. Define the AIDL interface
2. Implement the Stub for the remote service
3. Expose the remote service to the local client
Defining the AIDL
The AIDL syntax is very similar to regular Java interface. You simply define the method signature. The datatypes supported by AIDL are somewhat different than regular Java interfaces. For one, all Java primitive datatypes are supported. So are String
, List
, Map
, and CharSequence
classes. Also, all other AIDL datatypes that you defined are supported. In addition to that, all Parcelable
classes are supported, but this is not going to be covered in this example. I'm trying to keep this example somewhat simpler to start with.
/src/com.marakana/IAdditionService.aidl
package com.marakana;
// Declare the interface.
interface IAdditionService {
// You can pass values in, out, or inout.
// Primitive datatypes (such as int, boolean, etc.) can only be passed in.
int add(in int value1, in int value2);
}
Implementing the Remote Service
Once you create your AIDL file and put it in the right place, the Eclipse+AIDL tool will generate a file with the same name, but .java extension. So I now have /gen/com.protechtraining.com/IAdditionService.java file. This is an auto-generated file so you don't want to edit it. What is important is that it contains a Stub class that we'll want to implement for our remote service.
To implement our remote service, we'll return the IBinder
from onBind()
method in our service class, AdditionService
. The IBinder
represents the implementation of the remote service. To implement IBinder
, we subclass IAddtionService.Stub
class from the auto-generated Java code, and provide implementation for our AIDL-defined methods, in this case add()
.
/src/com.marakana/AdditionService.java
package com.marakana;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
/**
* This class exposes the remote service to the client
*/
public class AdditionService extends Service {
private static final String TAG = "AdditionService";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate()");
}
@Override
public IBinder onBind(Intent intent) {
return new IAdditionService.Stub() {
/**
* Implementation of the add() method
*/
public int add(int value1, int value2) throws RemoteException {
Log.d(TAG, String.format("AdditionService.add(%d, %d)",value1, value2));
return value1 + value2;
}
};
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy()");
}
}
Exposing the Service Locally
Once we have the service implement the onBind()
properly, we are ready to connect to that service from our client. In this case, we have AIDLDemo
activity connecting to that service. To establish the connection, we need to implement ServiceConnection
class. Our activity in this example provides this implementation in AdditionServiceConnection
inner class by implementing onServiceConnected()
and onServiceDiconnected()
methods. Those callbacks will get the stub implementation of the remote service upon connection. We need to cast them from stubs to our AIDL service implementation. To do that, we use the IAdditionService.Stub.asInterface((IBinder) boundService)
helper method.
From that point on, we have a local service object that we can use to make calls against the remote service.
/src/com.marakana/AIDLDemo.java
package com.marakana;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class AIDLDemo extends Activity {
private static final String TAG = "AIDLDemo";
IAdditionService service;
AdditionServiceConnection connection;
/**
* This class represents the actual service connection. It casts the bound
* stub implementation of the service to the AIDL interface.
*/
class AdditionServiceConnection implements ServiceConnection {
public void onServiceConnected(ComponentName name, IBinder boundService) {
service = IAdditionService.Stub.asInterface((IBinder) boundService);
Log.d(AIDLDemo.TAG, "onServiceConnected() connected");
Toast.makeText(AIDLDemo.this, "Service connected", Toast.LENGTH_LONG)
.show();
}
public void onServiceDisconnected(ComponentName name) {
service = null;
Log.d(AIDLDemo.TAG, "onServiceDisconnected() disconnected");
Toast.makeText(AIDLDemo.this, "Service connected", Toast.LENGTH_LONG)
.show();
}
}
/** Binds this activity to the service. */
private void initService() {
connection = new AdditionServiceConnection();
Intent i = new Intent();
i.setClassName("com.marakana", com.marakana.AdditionService.class.getName());
boolean ret = bindService(i, connection, Context.BIND_AUTO_CREATE);
Log.d(TAG, "initService() bound with " + ret);
}
/** Unbinds this activity from the service. */
private void releaseService() {
unbindService(connection);
connection = null;
Log.d(TAG, "releaseService() unbound.");
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initService();
// Setup the UI
Button buttonCalc = (Button) findViewById(R.id.buttonCalc);
buttonCalc.setOnClickListener(new OnClickListener() {
TextView result = (TextView) findViewById(R.id.result);
EditText value1 = (EditText) findViewById(R.id.value1);
EditText value2 = (EditText) findViewById(R.id.value2);
public void onClick(View v) {
int v1, v2, res = -1;
v1 = Integer.parseInt(value1.getText().toString());
v2 = Integer.parseInt(value2.getText().toString());
try {
res = service.add(v1, v2);
} catch (RemoteException e) {
Log.d(AIDLDemo.TAG, "onClick failed with: " + e);
e.printStackTrace();
}
result.setText(new Integer(res).toString());
}
});
}
/** Called when the activity is about to be destroyed. */
@Override
protected void onDestroy() {
releaseService();
}
}
The UI in this case is very simple. There are couple of TextView
s and EditText
fields and a button The button handles its events in an anonymous inner class OnClickListener
. The button simply invokes the add()
method on the service as if it was a local call.
The layout for this example is not that significant, but I'm including it here for completeness purposes.
/res/layout/main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="AIDL Demo"
android:textSize="22sp" />
<EditText android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/value1"
android:hint="Value 1"></EditText>
<TextView android:id="@+id/TextView01" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="+"
android:textSize="36sp"></TextView>
<EditText android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/value2"
android:hint="Value 2"></EditText>
<Button android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/buttonCalc"
android:text="="></Button>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content" android:text="result"
android:textSize="36sp" android:id="@+id/result"></TextView>
</LinearLayout>
The output of your code should look like this:
Output

Source code
https://www.protechtraining.com/static/tutorials/AIDLDemo.zip
Additional Resources
I highly recommend getting the details on AIDL from Designing a Remote Interface Using AIDL.