page.title=Android Interface Definition Language (AIDL) @jd:body
AIDL (Android Interface Definition Language) is similar to other IDLs you might have worked with. It allows you to define the programming interface that both the client and service agree upon in order to communicate with each other and allows for interprocess communication (IPC). On Android, one process can not normally access the memory of another process. So to talk, they need to decompose their objects into primitives that the operating system can understand, and "marshall" the object across that boundary for you. The code to do that marshalling is tedious to write, so Android handles it for you with AIDL.
Note: Using AIDL is necessary only if you allow clients from different applications to access your service for IPC and want to handle multithreading in your service. If you do not need to perform IPC across different applications, you should create your interface implementing a Binder or, if you want to perform IPC, but do not need to handle multithreading, then you should implement your interface using a Messenger.
Before you begin designing your AIDL interface, be aware that calls on to an AIDL interface are direct function calls. You can not generally make assumptions about the thread in which the call will happen. What happens is different depending on whether the call is from a thread in the local process, or coming from a remote process. Specifically:
You must define your AIDL interface in an {@code .aidl} file using the Java programming language syntax, then save it in the source code (in the {@code src/} directory) of both the application hosting the service and any other application that will bind to the service.
When you build the projects containing the {@code .aidl} file, the Android SDK tools generate an {@link android.os.IBinder} class based on your AIDL interface (and saves the file in the {@code gen/} directory). This class defines the APIs you can call to perform RPC as an interface—you must implement the interface in your service.
To create a bounded service using AIDL, follow these steps:
This file defines the programming interface with method signatures.
The Android SDK tools generate an interface in the Java programming language, based on your {@code .aidl} file. This interface has an inner abstract class named {@code Stub} that extends {@link android.os.Binder} and implements methods from your AIDL interface. You must extend the {@code Stub} class and implement the methods.
Implement a {@link android.app.Service Service} and override {@link android.app.Service#onBind onBind()} to return your implementation of the {@code Stub} class.
Caution: Any changes that you make to your AIDL interface after your first release must remain backward compatible in order to avoid breaking other applications that use your service. That is, because your {@code .aidl} file must be copied to other applications in order for them to access your service's interface, you must maintain support for the original interface.
AIDL uses a simple syntax that lets you declare an interface with one or more methods that can take parameters and return values. The parameters and return values can be of any type, even other AIDL-generated interfaces.
The syntax for the {@code .aidl} file uses the Java programming language. The file defines a single interface and requires only the interface declaration and method signatures.
By default, AIDL supports the following data types:
All elements in the {@link java.util.List} must be one of the supported data types in this
list or one of the other AIDL-generated interfaces or parcelables you've declared. A {@link
java.util.List} may optionally be used as a "generic" class (e.g. List<String>
).
The actual concrete class that the other side will receive will always be an {@link
java.util.ArrayList}, although the method will be generated to use the {@link
java.util.List} interface.
All elements in the {@link java.util.Map} must be one of the supported data types in this list or one of the other AIDL-generated interfaces or parcelables you've declared. Generic maps, (such as those of the form {@code Map<String,Integer>} are not supported. The actual concrete class that the other side will receive will always be a {@link java.util.HashMap}, although the method will be generated to use the {@link java.util.Map} interface.
You must include an {@code import} statement for each additional type not listed above, even if they are defined in the same package as your interface.
When defining methods for your service interface, be aware that:
in
, out
, or inout
(see the example below).
Primitives are in
by default, and cannot be otherwise.
Caution: You should limit the direction to what is truly needed, because marshalling parameters is expensive.
Here is an example {@code .aidl} file:
// IRemoteService.aidl package com.example.android; // Declare any non-default types here with import statements /** Example service interface */ interface IRemoteService { /** Request the process ID of this service, to do evil things with it. */ int getPid(); /** Demonstrates some basic types that you can use as parameters * and return values in AIDL. */ void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString); }
Simply save your {@code .aidl} file in your project's {@code src/} directory and when you build your application, the SDK tools will generate the binder class file in your project's {@code gen/} directory. The generated file name matches the {@code .aidl} file name, but with a {@code .java} extension (for example, {@code IRemoteService.aidl} results in {@code IRemoteService.java}).
If you use Eclipse, the incremental build generates the binder class almost immediately. If you
do not use Eclipse, then the Ant tool generates the binder class next time you build your
application—you should build your project with ant debug
(or ant
release
) as soon as you're finished writing the {@code .aidl} file, so that your code can
link against the generated class.
When you build your application, the Android SDK tools generate a {@code .java} interface file named after your {@code .aidl} file. The generated interface includes a subclass named {@code Stub} that is an abstract implementation of its parent interface (for example, {@code YourInterface.Stub}) and declares all the methods from the {@code .aidl} file.
Note: {@code Stub} also defines a few helper methods, most notably {@code asInterface()}, which takes an {@link android.os.IBinder} (usually the one passed to a client's {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback method) and returns an instance of the stub interface. See the section Calling an IPC Method for more details on how to make this cast.
To implement the interface generated from the {@code .aidl}, extend the generated {@link android.os.Binder} interface (for example, {@code YourInterface.Stub}) and implement the methods inherited from the {@code .aidl} file.
Here is an example implementation of an interface called {@code IRemoteService} (defined by the {@code IRemoteService.aidl} example, above) using an anonymous instance:
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { public int getPid(){ return Process.myPid(); } public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) { // Does nothing } };
Now the {@code mBinder} is an instance of the {@code Stub} class (a {@link android.os.Binder}), which defines the RPC interface for the service. In the next step, this instance is exposed to clients so they can interact with the service.
There are a few rules you should be aware of when implementing your AIDL interface:
Once you've implemented the interface for your service, you need to expose it to clients so they can bind to it. To expose the interface for your service, extend {@link android.app.Service Service} and implement {@link android.app.Service#onBind onBind()} to return an instance of your class that implements the generated {@code Stub} (as discussed in the previous section). Here's an example service that exposes the {@code IRemoteService} example interface to clients.
public class RemoteService extends Service { @Override public void onCreate() { super.onCreate(); } @Override public IBinder onBind(Intent intent) { // Return the interface return mBinder; } private final IRemoteService.Stub mBinder = new IRemoteService.Stub() { public int getPid(){ return Process.myPid(); } public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) { // Does nothing } }; }
Now, when a client (such as an activity) calls {@link android.content.Context#bindService bindService()} to connect to this service, the client's {@link android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback receives the {@code mBinder} instance returned by the service's {@link android.app.Service#onBind onBind()} method.
The client must also have access to the interface class, so if the client and service are in separate applications, then the client's application must have a copy of the {@code .aidl} file in its {@code src/} directory (which generates the {@code android.os.Binder} interface—providing the client access to the AIDL methods).
When the client receives the {@link android.os.IBinder} in the {@link
android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback, it must call
YourServiceInterface.Stub.asInterface(service)
to cast the returned
parameter to YourServiceInterface
type. For example:
IRemoteService mIRemoteService; private ServiceConnection mConnection = new ServiceConnection() { // Called when the connection with the service is established public void onServiceConnected(ComponentName className, IBinder service) { // Following the example above for an AIDL interface, // this gets an instance of the IRemoteInterface, which we can use to call on the service mIRemoteService = IRemoteService.Stub.asInterface(service); } // Called when the connection with the service disconnects unexpectedly public void onServiceDisconnected(ComponentName className) { Log.e(TAG, "onServiceDisconnected"); } };
For more sample code, see the {@code RemoteService.java} class in ApiDemos.
If you have a class that you would like to send from one process to another through an IPC interface, you can do that. However, you must ensure that the code for your class is available to the other side of the IPC and the class must support the {@link android.os.Parcelable} interface, in order for the objects to be decomposed into primitives and marshalled across processes by the Android system.
There are five parts to making a class support the {@link android.os.Parcelable} protocol:
CREATOR
to your class which is an object implementing
the {@link android.os.Parcelable.Creator Parcelable.Creator} interface.If you are using a custom build process, do not add the {@code .aidl} file to your build. Similar to a header file in the C language, this {@code .aidl} file isn't compiled.
AIDL will use these methods and fields in the code it generates to marshall and unmarshall your objects.
For example, here is a {@code Rect.aidl} file to create a {@code Rect} class that's parcelable:
package android.graphics; // Declare Rect so AIDL can find it and knows that it implements // the parcelable protocol. parcelable Rect;
And here is an example of how the {@link android.graphics.Rect} class implements the {@link android.os.Parcelable} protocol.
import android.os.Parcel; import android.os.Parcelable; public final class Rect implements Parcelable { public int left; public int top; public int right; public int bottom; public static final Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() { public Rect createFromParcel(Parcel in) { return new Rect(in); } public Rect[] newArray(int size) { return new Rect[size]; } }; public Rect() { } private Rect(Parcel in) { readFromParcel(in); } public void writeToParcel(Parcel out) { out.writeInt(left); out.writeInt(top); out.writeInt(right); out.writeInt(bottom); } public void readFromParcel(Parcel in) { left = in.readInt(); top = in.readInt(); right = in.readInt(); bottom = in.readInt(); } }
The marshalling in the {@code Rect} class is pretty simple. Take a look at the other methods on {@link android.os.Parcel} to see the other kinds of values you can write to a Parcel.
Warning: Don't forget the security implications of receiving data from other processes. In this case, the {@code Rect} will read four numbers from the {@link android.os.Parcel}, but it is up to you to ensure that these are within the acceptable range of values for whatever the caller is trying to do. See Security and Permissions for more information about how to keep your application secure from malware.