首页 > 代码库 > 【翻译】Android Interface Definition Language (AIDL)

【翻译】Android Interface Definition Language (AIDL)

参考地址:https://developer.android.com/guide/components/aidl.html

Android Interface Definition Language (AIDL)

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 using interprocess communication (IPC). On Android, one process cannot 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 objects across that boundary for you. The code to do that marshalling is tedious to write, so Android handles it for you with AIDL.
AIDL和其他的IDL工作原理类似。你可以定义客户端和服务端进行进程间通信(IPC)的编程接口。在Android上,一个进程不能直接访问另一个进程的内存。因此,它们需要把它们的对象分解成基元来让操作系统理解并处理。处理的代码很难写,而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 concurrent IPC across different applications, you should create your 
interface by implementing a Binder or, if you want to perform IPC, but do not need to 
handle multithreading, implement your interface using a Messenger. Regardless, be sure 
that you understand Bound Services before implementing an AIDL.

注意:只有当你要让客户端和服务端通过IPC跨应用进行通信时需要使用AIDL。如果你不需要跨应用IPC通信,你应该
通过实现Binder来创建接口,或者,如果你要实现IPC,但是不需要处理多线程,可以使用Messenger来实现你的接
口。实现AIDL之前,你需要了解Bound Services。

Before you begin designing your AIDL interface, be aware that calls to an AIDL interface are direct function calls. You should not make assumptions about the thread in which the call occurs. What happens is different depending on whether the call is from a thread in the local process or a remote process. Specifically:
在你设计AIDL接口之前,你需要意识到AIDL接口是方法直接调用的。你不应该假定哪一个线程会调用它。从本地进程的一个线程或者从一个远程进程来调用产生的影响是不同的。特别地:

Calls made from the local process are executed in the same thread that is making the call. If this is your main UI thread, that thread continues to execute in the AIDL interface. If it is another thread, that is the one that executes your code in the service. Thus, if only local threads are accessing the service, you can completely control which threads are executing in it (but if that is the case, then you shouldn’t be using AIDL at all, but should instead create the interface by implementing a Binder).
本地进程的调用被执行在同一个线程。如果在你的UI线程,线程继续执行AIDL接口。如果是在其他线程,会在Service执行你的代码。因此,如果只有本地线程可以访问Service,你可以完全控制哪一个线程来执行(但如果如此,你就不应该使用AIDL,而应该选择通过实现Binder来创建接口)。

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.
远程进程的调用会从你拥有的进程维持的线程池里派发出来。你必须准备好来自未知线程的调用,包括多线程并发调用。换句话说,AIDL接口实现必须完全线程安全。

The oneway keyword modifies the behavior of remote calls. When used, a remote call does not block; it simply sends the transaction data and immediately returns. The implementation of the interface eventually receives this as a regular call from the 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.
oneway 关键字修改远程调用的行为。当使用这个关键字的时候,远程调用不会被阻塞;它会简单地发送事务并立即返回。实现的接口最终收到常规Binder线程池的远程调用。如果oneway用在本地调用,不会有作用,调用也仍然是同步的。


Defining an AIDL Interface

You must define your AIDL interface in an .aidl file using the Java programming language syntax, then save it in the source code (in the src/ directory) of both the application hosting the service and any other application that binds to the service.
你必须使用Java语法在.aidl文件定义你的AIDL接口,然后在持有Service和绑定Service的两个应用的源代码(src/directory目录)里保存。

When you build each application that contains the .aidl file, the Android SDK tools generate an IBinder interface based on the .aidl file and save it in the project’s gen/ directory. The service must implement the IBinder interface as appropriate. The client applications can then bind to the service and call methods from the IBinder to perform IPC.
当你建立每一个包含.aidl的文件的应用的时候,Android SDK工具会基于.aidl文件建立一个IBinder接口并且保存在项目的gen/目录下。Service必须按照情况实现Ibinder接口。客户端应用可以绑定到服务并且从IBinder调用方法来执行IPC。

To create a bounded service using AIDL, follow these steps:
为了使用AIDL创建一个有边界的Service,依据以下步骤:

1.Create the .aidl file
This file defines the programming interface with method signatures.
1.创建.aidl文件
这个文件定义了带签名的编程接口。

2.Implement the interface
The Android SDK tools generate an interface in the Java programming language, based on your .aidl file. This interface has an inner abstract class named Stub that extends Binder and implements methods from your AIDL interface. You must extend the Stub class and implement the methods.
2.实现接口
Android SDK工具依据你的.aidl文件用Java编程语言生成了接口。这个接口有继承Binder的叫做Stub的内部抽象类,并且从你的AIDL接口实现了方法。你必须继承Stub类并且实现方法。

3.Expose the interface to clients
Implement a Service and override onBind() to return your implementation of the Stub class.
3.向客户端暴露接口
实现一个Service并且覆写onBind()方法来返回你实现的Stub类。

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 .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接口的改变都必须向后兼容来避免其他应用使用你的Service出错。也就是
说,由于你的.aidl文件必须被拷贝到其他应用来访问你的Service接口,你必须维持对原有接口的支持。

1. Create the .aidl file

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.
AIDL使用简单的语法来让你声明,你只需要声明一个或多个带参数和返回值的方法。参数和返回值可以是任何类型,甚至是其他AIDL生成的接口。

You must construct the .aidl file using the Java programming language. Each .aidl file must define a single interface and requires only the interface declaration and method signatures.
你必须使用Java语言来构造.aidl文件。每一个.aidl文件必须定义单一的接口并且要求已经声明的接口和签名的方法。

By default, AIDL supports the following data types:
默认情况下,AIDL支持一下数据类型:

·All primitive types in the Java programming language (such as int, long, char, boolean, and so on)
所有Java基本类型(例如int,long,char,boolean等等)

·String

·CharSequence

·List
All elements in the 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 List may optionally be used as a “generic” class (for example, List <String> ). The actual concrete class that the other side receives is always an ArrayList, although the method is generated to use the List interface.
所有List里的元素必须是list支持的其中一种数据类型或者其他AIDL生成的接口或者你声明的parcelables。List可以有选择地作为一个“泛型的”类(例如 List<String>)。另一边接收的实体类常常是ArrayList,尽管方法是用List接口生成的。

·Map
All elements in the 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 Map <String,Integer>) are not supported. The actual concrete class that the other side receives is always a HashMap, although the method is generated to use the Map interface.

所有Map里的元素必须是list支持的其中一种数据类型或者其他AIDL生成的接口或者你声明的parcelables。泛型的map,(例如Map <String,Integer>)是不支持的。另一边接收的实体类常常是HashMap,尽管方法是用Map接口生成的。

You must include an import statement for each additional type not listed above, even if they are defined in the same package as your interface.
你必须添加每一个上面没有列出的类型的引用,即使他们作为你的接口定义在同一个包下。

When defining your service interface, be aware that:
当定义Service接口时,注意:

·Methods can take zero or more parameters, and return a value or void.
方法可以没有参数或多个参数,可以有返回值或者没有返回值。

·All non-primitive parameters require a directional tag indicating which way the data goes. Either in, out, or inout (see the example below).

Primitives are in by default, and cannot be otherwise.
所有非基元参数要求一个方向标签来指出数据走向。或者是in,out,inout(查看下面例子)。
基元是默认的,不会成为别的。

Caution: You should limit the direction to what is truly needed, because marshalling parameters is expensive.
注意:你应该限制真实需要的指向,因为整理参数代价昂贵。

·All code comments included in the .aidl file are included in the generated IBinder interface (except for comments before the import and package statements).
所有.aidl文件里的代码注解会生成到IBinder接口里(除了在导入包之前和包声明的注解)。

·Only methods are supported; you cannot expose static fields in AIDL.
只支持方法;你不能再AIDL里暴露静态字段。

Here is an example .aidl file:
这里是一个.aidl文件的例子:

// 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 .aidl file in your project’s src/ directory and when you build your application, the SDK tools generate the IBinder interface file in your project’s gen/ directory. The generated file name matches the .aidl file name, but with a .java extension (for example, IRemoteService.aidl results in IRemoteService.java).
简单地在项目的src/目录里保存你的.aidl文件,当你编译应用时,SDK工具会在你的项目的gen/目录生成IBinder接口文件。生成的文件名会匹配.aidl文件名,但是会变成.java后缀(例如,iRemoteService.aidl会变成IRemoteService.java)。

If you use Android Studio, the incremental build generates the binder class almost immediately. If you do not use Android Studio, then the Gradle tool generates the binder class next time you build your application—you should build your project with gradle assembleDebug (or gradle assembleRelease) as soon as you’re finished writing the .aidl file, so that your code can link against the generated class.
如果你使用Android Studio,增量式的编译会立即生成binder类。如果你不是使用Android Studio,Gradle工具会在你下一次编译应用的时候生成binder类—你应该在你写完.aidl文件时就使用gradle assembleDebug(或者gradle assembleRelease)来编译你的项目,这样的话代码才会连接到生成的类。

2. Implement the interface

When you build your application, the Android SDK tools generate a .java interface file named after your .aidl file. The generated interface includes a subclass named Stub that is an abstract implementation of its parent interface (for example, YourInterface.Stub) and declares all the methods from the .aidl file.
当你编译你的应用时,Android SDK工具会在.aidl文件对应的.java接口文件。生成的接口包含了一个叫Stub的子类,这个子类是它的父类接口的抽象实现(例如,YourInterface.Stub)和声明了所有你在.aidl文件里声明的方法。

Note: Stub also defines a few helper methods, most notably asInterface(), which takes an 
IBinder (usually the one passed to a client‘s 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.

注意:Stub也定义了一些帮助方法,尤其是 asInterface(),带有一个IBinder参数和(通常是客户端
onServiceConnected()回调方法)并且返回一个stub接口实例。查看Calling an IPC Method章节可以得到更
多关于这个的详情。

To implement the interface generated from the .aidl, extend the generated Binder interface (for example, YourInterface.Stub) and implement the methods inherited from the .aidl file.
为了实现从.aidl文件生成的接口,你需要继承生成的Binder接口(例如,YourInterface.Stub)并且实现继承自.aidl文件的方法。

Here is an example implementation of an interface called IRemoteService (defined by the IRemoteService.aidl example, above) using an anonymous instance:
这里是一个实现接口叫IRemoteService(从IRemoteService.aidl定义)的例子。

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 mBinder is an instance of the Stub class (a 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.
现在mBinder是Stub类的一个接口,它定义了RPC接口给Service。下一步,这个实力会暴露给客户端来让它们和Service进行交互。

There are a few rules you should be aware of when implementing your AIDL interface:
在实现AIDL接口之前,你需要注意到一些规则:

·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.
来电是不保证会在主线程执行,所以你需要一开始就思考多线程并且合适地建立你的Service成线程安全的。

·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 “Application is Not Responding” dialog)—you should usually call them from a separate thread in the client.
默认情况下,RPC调用是同步的。如果你知道Service会话超过几毫秒时间来完成一个请求,你不应该从Activity的主线程调用它,因为他可能会挂起应用(ANR)–你应该从客户端的另一个线程来调用它。

·No exceptions that you throw are sent back to the caller.
你没有抛出异常的话会退回到调用者。

3. Expose the interface to clients

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 Service and implement onBind() to return an instance of your class that implements the generated Stub (as discussed in the previous section). Here’s an example service that exposes the IRemoteService example interface to clients.
你一旦为你的Service实现了接口,你需要把它暴露给客户端,客户端才能绑定它。为了让你的Service暴露接口,继承Service并实现onBind()来放回一个你的类实现Stub(之前章节讨论过)的实例。这里是一个Service暴露IRemoteService接口给客户端的例子。

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 bindService() to connect to this service, the client’s onServiceConnected() callback receives the mBinder instance returned by the service’s onBind() method.
现在,当客户端(例如一个Activity)调用bindService()来连接这个Service时,客户端onServiceConnected()回调会接收到Service的onBind()方法返回的mBinder实例。

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 .aidl file in its src/ directory (which generates the android.os.Binder interface—providing the client access to the AIDL methods).
客户端也必须有访问接口类的权限,所以如果客户端和Service在不同的应用,客户端的应用必须有一份.aidl文件的拷贝在它的src/目录中(会生成android.os.Binder接口—提供AIDL方法给客户端访问)。

When the client receives the IBinder in the onServiceConnected() callback, it must call YourServiceInterface.Stub.asInterface(service) to cast the returned parameter to YourServiceInterface type. For example:
当客户端在onServiceConnected()回调接收到IBinder时,它必须调用YourServiceInterface.Stub.asInterface(service)来转换参数成YourServiceInterface类型。例如:

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, "Service has unexpectedly disconnected");
        mIRemoteService = null;
    }
};

For more sample code, see the RemoteService.java class in ApiDemos.
可以查看ApiDemos里的RemoteService.java来获取更多信息。


Passing Objects over IPC

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 channel and your class must support the Parcelable interface. Supporting the Parcelable interface is important because it allows the Android system to decompose objects into primitives that can be marshalled across processes.
如果你想要通过IPC从一个进程传送一个类到另一个进程,是可以做到的。但是,你必须确信通过IPC通道,另一边可以访问你的类,并且你的类必须支持Parcelable接口。支持Parcelable接口是很重要的,因为它让Android系统可以分解对象成基元来进行跨进程操作。

To create a class that supports the Parcelable protocol, you must do the following:
为了创界一个支持Parcelable协议的类,你必须做下面的事情:

1.Make your class implement the Parcelable interface.
1.让你的类实现Parcelable接口。

2.Implement writeToParcel, which takes the current state of the object and writes it to a Parcel.
2.实现writeToParcel,它可以获取对象当前对象以及写到Parcel。

3.Add a static field called CREATOR to your class which is an object implementing the Parcelable.Creator interface.
3.在你的类中添加一个叫做CREATOR的静态域,用来实现Parcelable.Creator接口。

4.Finally, create an .aidl file that declares your parcelable class (as shown for the Rect.aidl file, below).
4.最后,创建一个.aidl文件来声明你的parcelable类(正如下面展示的Rect.aidl文件)。

If you are using a custom build process, do not add the .aidl file to your build. Similar to a header file in the C language, this .aidl file isn’t compiled.
如果你正在使用一个定制的进程,不要天假.aidl文件到你的build。类似于C语言的头文件,这个.aidl文件是没有编译的。

AIDL uses these methods and fields in the code it generates to marshall and unmarshall your objects.
AIDL使用这些方法和代码生成的域来编码和解码你的对象。

For example, here is a Rect.aidl file to create a Rect class that’s parcelable:
举个例子,这里是Rect.aidl文件创建Rect类实现了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 Rect class implements the Parcelable protocol.
这里是一个关于Rect类如何实现Parcelable协议的例子。

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 Rect class is pretty simple. Take a look at the other methods on Parcel to see the other kinds of values you can write to a Parcel.
在Rect类里的封装相当简单。看一下Parcel的其他方法来了解你能写到Parcel的其他类型的值。

Warning: Don‘t forget the security implications of receiving data from other processes. 
In this case, the Rect reads 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 Security and Permissions for more information about how to keep your 
application secure from malware.

警告:不要忘记从其他进程获取数据的安全问题。Rect从Parcel读取四个数字,但是是由你来决定这些数据是否在可
接受范围内。查看Security和Permissions来获取更多保证你的应用安全,防止被恶意软件攻击的信息。

Calling an IPC Method

Here are the steps a calling class must take to call a remote interface defined with AIDL:
这里是调用的类必须遵循的一些步骤,关于调用定义在AIDL的远程接口:

1.Include the .aidl file in the project src/ directory.
1.在src/目录放.aidl文件。

2.Declare an instance of the IBinder interface (generated based on the AIDL).
2.声明IBinder接口实例(AIDL生成)。

3.Implement ServiceConnection.
3.实现ServiceConnection。

4.Call Context.bindService(), passing in your ServiceConnection implementation.
4.调用Context.bindService(),传入ServiceConnection的实现。

5.In your implementation of onServiceConnected(), you will receive an IBinder instance (called service). Call YourInterfaceName.Stub.asInterface((IBinder)service) to cast the returned parameter to YourInterface type.
5.你会在你的onServiceConnected()的实现接收到一个IBinder实例(叫做service)。调用YourInterfaceName.Stub.asInterface((IBinder)service)来将返回的参数转换成YourInterface类型。

6.Call the methods that you defined on your interface. You should always trap DeadObjectException exceptions, which are thrown when the connection has broken; this will be the only exception thrown by remote methods.
6.调用你定义在你的接口的方法。你应该捕获DeadObjectException异常,当连接中断时会抛出这个异常;这也是远程方法唯一会抛出的异常。

7.To disconnect, call Context.unbindService() with the instance of your interface.
7.如果想要断开连接,用你接口的实例调用Context.unbindService()。

A few comments on calling an IPC service:
一些关于调用IPC服务的注解:

·Objects are reference counted across processes.
对象被认为是跨进程引用。

·You can send anonymous objects as method arguments.
你可以发送匿名对象作为方法的参数。

For more information about binding to a service, read the Bound Services document.
参阅Bound Services文档来获取更多关于绑定Service的信息。

Here is some sample code demonstrating calling an AIDL-created service, taken from the Remote Service sample in the ApiDemos project.
这里是一些演示调用AIDL创建服务的范例代码,可以从ApiDemos的Remote Service例子获取。

public static class Binding extends Activity {
    /** The primary interface we will be calling on the service. */
    IRemoteService mService = null;
    /** Another interface we use on the service. */
    ISecondary mSecondaryService = null;

    Button mKillButton;
    TextView mCallbackText;

    private boolean mIsBound;

    /**
     * Standard initialization of this activity.  Set up the UI, then wait
     * for the user to poke it before doing anything.
     */
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.remote_service_binding);

        // Watch for button clicks.
        Button button = (Button)findViewById(R.id.bind);
        button.setOnClickListener(mBindListener);
        button = (Button)findViewById(R.id.unbind);
        button.setOnClickListener(mUnbindListener);
        mKillButton = (Button)findViewById(R.id.kill);
        mKillButton.setOnClickListener(mKillListener);
        mKillButton.setEnabled(false);

        mCallbackText = (TextView)findViewById(R.id.callback);
        mCallbackText.setText("Not attached.");
    }

    /**
     * Class for interacting with the main interface of the service.
     */
    private ServiceConnection mConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // This is called when the connection with the service has been
            // established, giving us the service object we can use to
            // interact with the service.  We are communicating with our
            // service through an IDL interface, so get a client-side
            // representation of that from the raw service object.
            mService = IRemoteService.Stub.asInterface(service);
            mKillButton.setEnabled(true);
            mCallbackText.setText("Attached.");

            // We want to monitor the service for as long as we are
            // connected to it.
            try {
                mService.registerCallback(mCallback);
            } catch (RemoteException e) {
                // In this case the service has crashed before we could even
                // do anything with it; we can count on soon being
                // disconnected (and then reconnected if it can be restarted)
                // so there is no need to do anything here.
            }

            // As part of the sample, tell the user what happened.
            Toast.makeText(Binding.this, R.string.remote_service_connected,
                    Toast.LENGTH_SHORT).show();
        }

        public void onServiceDisconnected(ComponentName className) {
            // This is called when the connection with the service has been
            // unexpectedly disconnected -- that is, its process crashed.
            mService = null;
            mKillButton.setEnabled(false);
            mCallbackText.setText("Disconnected.");

            // As part of the sample, tell the user what happened.
            Toast.makeText(Binding.this, R.string.remote_service_disconnected,
                    Toast.LENGTH_SHORT).show();
        }
    };

    /**
     * Class for interacting with the secondary interface of the service.
     */
    private ServiceConnection mSecondaryConnection = new ServiceConnection() {
        public void onServiceConnected(ComponentName className,
                IBinder service) {
            // Connecting to a secondary interface is the same as any
            // other interface.
            mSecondaryService = ISecondary.Stub.asInterface(service);
            mKillButton.setEnabled(true);
        }

        public void onServiceDisconnected(ComponentName className) {
            mSecondaryService = null;
            mKillButton.setEnabled(false);
        }
    };

    private OnClickListener mBindListener = new OnClickListener() {
        public void onClick(View v) {
            // Establish a couple connections with the service, binding
            // by interface names.  This allows other applications to be
            // installed that replace the remote service by implementing
            // the same interface.
            Intent intent = new Intent(Binding.this, RemoteService.class);
            intent.setAction(IRemoteService.class.getName());
            bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
            intent.setAction(ISecondary.class.getName());
            bindService(intent, mSecondaryConnection, Context.BIND_AUTO_CREATE);
            mIsBound = true;
            mCallbackText.setText("Binding.");
        }
    };

    private OnClickListener mUnbindListener = new OnClickListener() {
        public void onClick(View v) {
            if (mIsBound) {
                // If we have received the service, and hence registered with
                // it, then now is the time to unregister.
                if (mService != null) {
                    try {
                        mService.unregisterCallback(mCallback);
                    } catch (RemoteException e) {
                        // There is nothing special we need to do if the service
                        // has crashed.
                    }
                }

                // Detach our existing connection.
                unbindService(mConnection);
                unbindService(mSecondaryConnection);
                mKillButton.setEnabled(false);
                mIsBound = false;
                mCallbackText.setText("Unbinding.");
            }
        }
    };

    private OnClickListener mKillListener = new OnClickListener() {
        public void onClick(View v) {
            // To kill the process hosting our service, we need to know its
            // PID.  Conveniently our service has a call that will return
            // to us that information.
            if (mSecondaryService != null) {
                try {
                    int pid = mSecondaryService.getPid();
                    // Note that, though this API allows us to request to
                    // kill any process based on its PID, the kernel will
                    // still impose standard restrictions on which PIDs you
                    // are actually able to kill.  Typically this means only
                    // the process running your application and any additional
                    // processes created by that app as shown here; packages
                    // sharing a common UID will also be able to kill each
                    // other‘s processes.
                    Process.killProcess(pid);
                    mCallbackText.setText("Killed service process.");
                } catch (RemoteException ex) {
                    // Recover gracefully from the process hosting the
                    // server dying.
                    // Just for purposes of the sample, put up a notification.
                    Toast.makeText(Binding.this,
                            R.string.remote_call_failed,
                            Toast.LENGTH_SHORT).show();
                }
            }
        }
    };

    // ----------------------------------------------------------------------
    // Code showing how to deal with callbacks.
    // ----------------------------------------------------------------------

    /**
     * This implementation is used to receive callbacks from the remote
     * service.
     */
    private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
        /**
         * This is called by the remote service regularly to tell us about
         * new values.  Note that IPC calls are dispatched through a thread
         * pool running in each process, so the code executing here will
         * NOT be running in our main thread like most other things -- so,
         * to update the UI, we need to use a Handler to hop over there.
         */
        public void valueChanged(int value) {
            mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
        }
    };

    private static final int BUMP_MSG = 1;

    private Handler mHandler = new Handler() {
        @Override public void handleMessage(Message msg) {
            switch (msg.what) {
                case BUMP_MSG:
                    mCallbackText.setText("Received from service: " + msg.arg1);
                    break;
                default:
                    super.handleMessage(msg);
            }
        }

    };
}
<script type="text/javascript"> $(function () { $(‘pre.prettyprint code‘).each(function () { var lines = $(this).text().split(‘\n‘).length; var $numbering = $(‘
    ‘).addClass(‘pre-numbering‘).hide(); $(this).addClass(‘has-numbering‘).parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($(‘
  • ‘).text(i)); }; $numbering.fadeIn(1700); }); }); </script>

    【翻译】Android Interface Definition Language (AIDL)