306 lines
15 KiB
Plaintext
306 lines
15 KiB
Plaintext
page.title=Designing a Remote Interface Using AIDL
|
|
@jd:body
|
|
|
|
|
|
<div id="qv-wrapper">
|
|
<div id="qv">
|
|
<h2>In this document</h2>
|
|
<ol>
|
|
<li><a href="#implementing">Implementing IPC Using AIDL</a>
|
|
<ol>
|
|
<li><a href="#aidlsyntax">Create an .aidl File</a></li>
|
|
<li><a href="#implementtheinterface">Implementing the Interface</a></li>
|
|
<li><a href="#exposingtheinterface">Exposing Your Interface to Clients</a></li>
|
|
<li><a href="#parcelable">Pass by value Parameters using Parcelables</a></li>
|
|
</ol>
|
|
</li>
|
|
<li><a href="#calling">Calling an IPC Method</a></li>
|
|
</ol>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<p>Since each application runs in its own process, and you can write a service that
|
|
runs in a different process from your Application's UI, sometimes you need to pass objects
|
|
between processes. On the Android platform, 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.</p>
|
|
|
|
<p>The code to do that marshalling is tedious to write, so we provide the AIDL tool to do it
|
|
for you.</p>
|
|
|
|
<p>AIDL (Android Interface Definition Language) is an <a
|
|
href="http://en.wikipedia.org/wiki/Interface_description_language">IDL</a>
|
|
language used to generate code that enables two processes on an Android-powered device
|
|
to talk using interprocess communication (IPC). If you have code
|
|
in one process (for example, in an Activity) that needs to call methods on an
|
|
object in another process (for example, a Service), you would use AIDL to
|
|
generate code to marshall the parameters.</p>
|
|
<p>The AIDL IPC mechanism
|
|
is interface-based, similar to COM or Corba, but lighter weight. It uses a proxy
|
|
class to pass values between the client and the implementation. </p>
|
|
|
|
|
|
<h2 id="implementing">Implementing IPC Using AIDL</h2>
|
|
<p>Follow these steps to implement an IPC service using AIDL.</p>
|
|
<ol>
|
|
<li><strong><a href="#aidlsyntax">Create your .aidl file</a> </strong>- This
|
|
file defines an interface (<em>YourInterface</em>.aidl) that defines the
|
|
methods and fields available to a client. </li>
|
|
<li><strong>Add the .aidl file to your makefile</strong> - (the ADT Plugin for Eclipse
|
|
manages this for you). Android includes the compiler, called
|
|
AIDL, in the <code>tools/</code> directory. </li>
|
|
<li><strong><a href="#implementtheinterface">Implement your interface methods</a></strong> -
|
|
The AIDL compiler creates an interface in the Java programming language from your AIDL interface.
|
|
This interface has an inner abstract class named Stub that inherits the
|
|
interface (and implements a few additional methods necessary for the IPC
|
|
call). You must create a class that extends <em>YourInterface</em>.Stub
|
|
and implements the methods you declared in your .aidl file. </li>
|
|
<li><strong><a href="#exposingtheinterface">Expose your interface to clients</a></strong> -
|
|
If you're writing a service, you should extend {@link
|
|
android.app.Service Service} and override {@link android.app.Service#onBind
|
|
Service.onBind(Intent)} to return an instance of your class that implements your
|
|
interface. </li>
|
|
</ol>
|
|
|
|
<h3 id="aidlsyntax">Create an .aidl File</h3>
|
|
<p>AIDL is a simple syntax that lets you declare an interface with one or more
|
|
methods, that can take parameters and return values. These parameters and return
|
|
values can be of any type, even other AIDL-generated interfaces. <em>However, it
|
|
is important to note</em> that you <em>must</em> import all non-built-in types,
|
|
<em>even if they are defined in the same package as your interface</em>.
|
|
Here are the data types that AIDL can support: </p>
|
|
<ul>
|
|
<li>Primitive Java programming language types (int, boolean, etc)
|
|
— No <code>import</code> statement is needed. </li>
|
|
<li>One of the following classes (no <code>import</code> statements needed):
|
|
<ul>
|
|
<li><strong>String</strong></li>
|
|
<li><strong>List</strong> - All elements in the List must be one of the types
|
|
in this list, including other AIDL-generated interfaces and
|
|
parcelables. 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 ArrayList, although the method will be generated
|
|
to use the List interface. </li>
|
|
<li><strong>Map</strong> - All elements in the Map must be of one of the
|
|
types in this list, including other AIDL-generated interfaces and
|
|
parcelables. Generic maps, (e.g. of the form Map<String,Integer>
|
|
are not supported.
|
|
The actual concrete class that the other side will receive
|
|
will always be a HashMap, although the method will be generated
|
|
to use the Map interface.</li>
|
|
<li><strong>CharSequence</strong> - This is useful for the CharSequence
|
|
types used by {@link android.widget.TextView TextView} and other
|
|
widget objects. </li>
|
|
</ul>
|
|
</li>
|
|
<li>Other AIDL-generated interfaces, which are always passed by reference.
|
|
An <code>import</code> statement is always needed for these.</li>
|
|
<li>Custom classes that implement the <a href="#parcelable">Parcelable
|
|
protocol</a> and are passed by value.
|
|
An <code>import</code> statement is always needed for these.</li>
|
|
</ul>
|
|
<p>Here is the basic AIDL syntax:</p>
|
|
<pre>// My AIDL file, named <em>SomeClass</em>.aidl
|
|
// Note that standard comment syntax is respected.
|
|
// Comments before the import or package statements are not bubbled up
|
|
// to the generated interface, but comments above interface/method/field
|
|
// declarations are added to the generated interface.
|
|
|
|
// Include your fully-qualified package statement.
|
|
package com.android.sample;
|
|
|
|
// See the list above for which classes need
|
|
// import statements (hint--most of them)
|
|
import com.android.sample.IAtmService;
|
|
|
|
// Declare the interface.
|
|
interface IBankAccountService {
|
|
|
|
// Methods can take 0 or more parameters, and
|
|
// return a value or void.
|
|
int getAccountBalance();
|
|
void setOwnerNames(in List<String> names);
|
|
|
|
// Methods can even take other AIDL-defined parameters.
|
|
BankAccount createAccount(in String name, int startingDeposit, in IAtmService atmService);
|
|
|
|
// All non-Java primitive parameters (e.g., int, bool, etc) require
|
|
// a directional tag indicating which way the data will go. Available
|
|
// values are in, out, inout. (Primitives are in by default, and cannot be otherwise).
|
|
// Limit the direction to what is truly needed, because marshalling parameters
|
|
// is expensive.
|
|
int getCustomerList(in String branch, out String[] customerList);
|
|
}</pre>
|
|
|
|
<h3 id="implementtheinterface">Implementing the Interface</h3>
|
|
<p>AIDL generates an interface file for you with the same name as your .aidl
|
|
file. If you are using the Eclipse plugin, AIDL will automatically be run as part of
|
|
the build process (you don't need to run AIDL first and then build your project).
|
|
If you are not using the plugin, you should run AIDL first. </p>
|
|
<p>The generated interface
|
|
includes an abstract inner class named Stub that declares all the methods
|
|
that you declared in your .aidl file. Stub also defines a few helper methods,
|
|
most notably asInterface(), which takes an IBinder (passed to a client's onServiceConnected()
|
|
implementation when applicationContext.bindService() succeeds), and returns an
|
|
instance of the interface used to call the IPC methods. See the section
|
|
<a href="#calling">Calling an IPC Method</a> for more details on how to make this cast.</p>
|
|
<p>To implement your interface, extend <em>YourInterface</em>.Stub,
|
|
and implement the methods. (You can create the .aidl file and implement the stub
|
|
methods without building between--the Android build process will process .aidl
|
|
files before .java files.) </p>
|
|
<p>Here is an example of implementing an interface called IRemoteService, which exposes
|
|
a single method, getPid(), using an anonymous instance:</p>
|
|
<pre>// No need to import IRemoteService if it's in the same project.
|
|
private final IRemoteService.Stub mBinder = new IRemoteService.Stub(){
|
|
public int getPid(){
|
|
return Process.myPid();
|
|
}
|
|
}</pre>
|
|
<p>A few rules about implementing your interface: </p>
|
|
<ul>
|
|
<li>No exceptions that you throw will be sent back to the caller.</li>
|
|
<li>By default, IPC calls are synchronous. If you know that an IPC service takes more than
|
|
a few milliseconds to complete, you should not call it in the Activity/View thread,
|
|
because it might hang the application (Android might display an "Application
|
|
is Not Responding" dialog).
|
|
Try to call them in a separate thread. </li>
|
|
<li>Only methods are supported; you cannot declare static fields in an AIDL interface.</li>
|
|
</ul>
|
|
|
|
<h3 id="exposingtheinterface">Exposing Your Interface to Clients</h3>
|
|
<p>Now that you've got your interface implementation, you need to expose it to clients.
|
|
This is known as "publishing your service." To publish a service,
|
|
inherit {@link android.app.Service Service} and implement {@link android.app.Service#onBind
|
|
Service.onBind(Intent)} to return an instance of the class that implements your interface.
|
|
Here's a code snippet of a service that exposes the IRemoteService
|
|
interface to clients. </p>
|
|
<pre>public class RemoteService extends Service {
|
|
...
|
|
{@include development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java
|
|
exposing_a_service}
|
|
}</pre>
|
|
|
|
|
|
<h3 id="parcelable">Pass by value Parameters using Parcelables</h3>
|
|
|
|
<p>If you have a class that you would like to send from one process to another through
|
|
an AIDL interface, you can do that. You must ensure that the code for your class is available
|
|
to the other side of the IPC. Generally, that means that you're talking to a service that you
|
|
started.</p>
|
|
<p>There are five parts to making a class support the Parcelable protocol:</b>
|
|
<ol>
|
|
<li>Make your class implement the {@link android.os.Parcelable} interface.</li>
|
|
<li>Implement the method <code>public void writeToParcel(Parcel out)</code> that takes the
|
|
current state of the object and writes it to a parcel.</li>
|
|
value in a parcel into your object.</li>
|
|
<li>Add a static field called <code>CREATOR</code> to your class which is an object implementing
|
|
the {@link android.os.Parcelable.Creator Parcelable.Creator} interface.</li>
|
|
<li>Last but not least, create an aidl file
|
|
that declares your parcelable class (as shown below). If you are using a custom build process,
|
|
do not add the aidl file to your build. Similar to a header file in C, the aidl file isn't
|
|
compiled.</li>
|
|
</ol>
|
|
|
|
<p>AIDL will use these methods and fields in the code it generates to marshall and unmarshall
|
|
your objects.</p>
|
|
<p>Here is an example of how the {@link android.graphics.Rect} class implements the
|
|
Parcelable protocol.</p>
|
|
|
|
<pre class="prettyprint">
|
|
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();
|
|
}
|
|
}
|
|
</pre>
|
|
|
|
<p>Here is Rect.aidl for this example</p>
|
|
|
|
<pre class="prettyprint">
|
|
package android.graphics;
|
|
|
|
// Declare Rect so AIDL can find it and knows that it implements
|
|
// the parcelable protocol.
|
|
parcelable Rect;
|
|
</pre>
|
|
|
|
<p>The marshalling in the 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.</p>
|
|
|
|
<p class="warning"><b>Warning:</b> Don't forget the security implications of receiving data from
|
|
other processes. In this case, the rect will read four numbers from the 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
|
|
<a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> for more
|
|
on how to keep your application secure from malware.</p>
|
|
|
|
<h2 id="calling">Calling an IPC Method</h2>
|
|
<p>Here are the steps a calling class should make to call your remote interface: </p>
|
|
<ol>
|
|
<li>Declare a variable of the interface type that your .aidl file defined. </li>
|
|
<li>Implement {@link android.content.ServiceConnection ServiceConnection}. </li>
|
|
<li>Call {@link android.content.Context#bindService(android.content.Intent,android.content.ServiceConnection,int)
|
|
Context.bindService()}, passing in your ServiceConnection implementation. </li>
|
|
<li>In your implementation of {@link android.content.ServiceConnection#onServiceConnected(android.content.ComponentName,android.os.IBinder)
|
|
ServiceConnection.onServiceConnected()}, you will receive an {@link android.os.IBinder
|
|
IBinder} instance (called <em>service</em>). Call <code><em>YourInterfaceName</em>.Stub.asInterface((IBinder)<em>service</em>)</code> to
|
|
cast the returned parameter to <em>YourInterface</em> type.</li>
|
|
<li>Call the methods that you defined on your interface. You should always trap
|
|
{@link android.os.DeadObjectException} exceptions, which are thrown when
|
|
the connection has broken; this will be the only exception thrown by remote
|
|
methods.</li>
|
|
<li>To disconnect, call {@link android.content.Context#unbindService(android.content.ServiceConnection)
|
|
Context.unbindService()} with the instance of your interface. </li>
|
|
</ol>
|
|
<p>A few comments on calling an IPC service:</p>
|
|
<ul>
|
|
<li>Objects are reference counted across processes. </li>
|
|
<li>You can send anonymous objects
|
|
as method arguments. </li>
|
|
</ul>
|
|
<p>Here is some sample code demonstrating calling an AIDL-created service, taken
|
|
from the Remote Service sample in the ApiDemos project.</p>
|
|
<p>{@sample development/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.java
|
|
calling_a_service}</p>
|
|
|
|
|
|
|