Scott Main 2150553dc3 cherrypick Change-Id: I1365c6c45f8e1f75ee4afbc52c32778d21b97be4 from master
docs: Rewrite of App Fundamentals.. Part 2.
This introduces three new docs:

Services:
  Provides an introduction to using services and describes the
  service lifecycle (previously in the "Component Lifecycles" section
  of the fundamentals.jd document)
Bound Services:
  A guide for services that offer binding.
AIDL:
  A doc about using AIDL (primarily for creating a service interface)

Also includes edits to IntentService javadocs to clarify
different behaviors for some callback methods

Includes a new version of the services lifecycle diagram
and an additional diagram for determining onRebind()

These files are orphaned for now---they're not linked in the sidenav,
until I get the last couple documents submitted for the app fundamentals.

Change-Id: I7fb0a8faff1f18b7d6b9a7b59f66f55a1b6168f1
2011-01-14 14:07:29 -08:00

388 lines
18 KiB
Plaintext

page.title=Android Interface Definition Language (AIDL)
@jd:body
<p>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.</p>
<p class="note"><strong>Note:</strong> 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 <a href="Binder">implementing a
Binder</a> or, if you want to perform IPC, but do not need to handle multithreading, then you
should implement your interface <a href="#Messenger">using a Messenger</a>.</p>
<p>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:</p>
<ul>
<li>Calls from the local process are executed in the same thread that is making the call. If this is
your main UI thread, that thread will continue executing into the aidl interface. If it is another
thread, that is one that will be executing your code. Thus if only local threads are accessing the
interface, you can completely control which threads are executing in it (but if that is the case,
why are you defining an aidl interface at all?).</li>
<li>Calls from a remote process are dispatched from a thread pool the platform maintains inside of
your own process. You must be prepared for incoming calls from unknown threads, with multiple calls
happening at the same time. In other words, an implementation of an aidl interface must be
completely thread-safe.</li>
<li>The "oneway" keyword modifies the behavior of remote calls. When used, a remote call will not
block until its call completes; it simply sends the transaction data and immediately returns. The
implementation of the interface will eventually receive this as a regular call from the {@link
android.os.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.</li>
</ul>
<h2 id="Defining">Defining an AIDL Interface</h2>
<p>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.</p>
<p>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&mdash;you
must implement the interface in your service.</p>
<p>To create a bounded service using AIDL, follow these steps:</p>
<ol>
<li><a href="#CreateAidl">Create the .aidl file</a>
<p>This file defines the programming interface with method signatures.</p>
</li>
<li><a href="#ImplementTheInterface">Implement the interface</a>
<p>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.</p>
</li>
<li><a href="#ExposeTheInterface">Expose the interface to clients</a>
<p>Implement a {@link android.app.Service Service} and override {@link
android.app.Service#onBind onBind()} to return your implementation of the {@code Stub}
class.</p>
</li>
</ol>
<p class="caution"><strong>Caution:</strong> 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.</p>
<h3 id="CreateAidl">1. Create the .aidl file</h3>
<p>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.</p>
<p>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.</p>
<p>By default, AIDL supports the following data types:</p>
<ul>
<li>All primitive types in the Java programming language ({@code int}, {@code long}, {@code
char}, {@code boolean}, etc.)</li>
<li>{@link java.lang.String}</li>
<li>{@link java.lang.CharSequence}</li>
<li>{@link java.util.List}
<p>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. <code>List&lt;String&gt;</code>).
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.</p>
</li>
<li>{@link java.util.Map}
<p>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&lt;String,Integer&gt;} 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.</p>
</li>
</ul>
<p>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.</p>
<p>When defining methods for your service interface, be aware that:</p>
<ul>
<li>Methods can take zero or more parameters, and return a value or void.</li>
<li>All non-primitive parameters require a directional tag indicating which way the data will go.
Either <code>in</code>, <code>out</code>, or <code>inout</code> (see the example below).
<p>Primitives are <code>in</code> by default, and cannot be otherwise.</p>
<p class="caution"><strong>Caution:</strong> You should limit the direction to what is truly
needed, because marshalling parameters is expensive.</p></li>
<li>All code comments included in the {@code .aidl} file are included in the generated {@link
android.os.IBinder} interface (except for comments before the import and package
statements).</li>
</ul>
<p>Here is an example {@code .aidl} file:</p>
<pre>
// 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);
}
</pre>
<p>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}).</p>
<p>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&mdash;you should build your project with <code>ant debug</code> (or <code>ant
release</code>) as soon as you're finished writing the {@code .aidl} file, so that your code can
link against the generated class.</p>
<h3 id="ImplementTheInterface">2. Implement the interface</h3>
<p>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.</p>
<p class="note"><strong>Note:</strong> {@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 <a href="#calling">Calling an IPC
Method</a> for more details on how to make this cast.</p></p>
<p>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.</p>
<p>Here is an example implementation of an interface called {@code IRemoteService} (defined by the
{@code IRemoteService.aidl} example, above) using an anonymous instance:</p>
<pre>
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
}
};
</pre>
<p>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.</p>
<p>There are a few rules you should be aware of when implementing your AIDL interface: </p>
<ul>
<li>Incoming calls are not guaranteed to be executed on the main thread, so you need to think
about multithreading from the start and properly build your service to be thread-safe.</li>
<li>By default, RPC calls are synchronous. If you know that the service takes more than a few
milliseconds to complete a request, you should not call it from the activity's main thread, because
it might hang the application (Android might display an &quot;Application is Not Responding&quot;
dialog)&mdash;you should usually call them from a separate thread in the client. </li>
<li>No exceptions that you throw are sent back to the caller.</li>
<li>Only methods are supported; you cannot expose static fields in AIDL.</li>
</ul>
<h3 id="ExposeTheInterface">3. Expose the interface to clients</h3>
<p>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. </p>
<pre>
public class RemoteService extends Service {
&#64;Override
public void onCreate() {
super.onCreate();
}
&#64;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
}
};
}
</pre>
<p>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.</p>
<p>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&mdash;providing the client access to the AIDL methods).</p>
<p>When the client receives the {@link android.os.IBinder} in the {@link
android.content.ServiceConnection#onServiceConnected onServiceConnected()} callback, it must call
<code><em>YourServiceInterface</em>.Stub.asInterface(service)</code> to cast the returned
parameter to <code><em>YourServiceInterface</em></code> type. For example:</p>
<pre>
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");
}
};
</pre>
<p>For more sample code, see the <a
href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/app/RemoteService.html">{@code
RemoteService.java}</a> class in <a
href="{@docRoot}resources/samples/ApiDemos/index.html">ApiDemos</a>.</p>
<h2 id="PassingObjects">Passing Objects over IPC</h2>
<p>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.</p>
<p>There are five parts to making a class support the {@link android.os.Parcelable} protocol:</b>
<ol>
<li>Make your class implement the {@link android.os.Parcelable} interface.</li>
<li>Implement {@link android.os.Parcelable#writeToParcel writeToParcel}, which takes the
current state of the object and writes it to a {@link android.os.Parcel}.</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>Finally, create an {@code .aidl} file that declares your parcelable class (as shown for the
{@code Rect.aidl} file, below).
<p>If you are using a custom build process, do <em>not</em> add the {@code .aidl} file to your
build. Similar to a header file in the C language, this {@code .aidl} file isn't compiled.</p></li>
</ol>
<p>AIDL will use these methods and fields in the code it generates to marshall and unmarshall
your objects.</p>
<p>For example, here is a {@code Rect.aidl} file to create a {@code Rect} class that's
parcelable:</p>
<pre>
package android.graphics;
// Declare Rect so AIDL can find it and knows that it implements
// the parcelable protocol.
parcelable Rect;
</pre>
<p>And here is an example of how the {@link android.graphics.Rect} class implements the
{@link android.os.Parcelable} protocol.</p>
<pre>
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&lt;Rect&gt; CREATOR = new
Parcelable.Creator&lt;Rect&gt;() {
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>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.</p>
<p class="warning"><strong>Warning:</strong> 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 <a
href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a> for more
information about how to keep your application secure from malware.</p>