前言
在我们应用开发过程中常见的binder跨进程,除了通过跨进程调用系统服务外,就是通过AIDL实现两个应用进程间的跨进程调用了。本文写在对AIDL实现跨进程通信的原理的讲解之前,先简单介绍一下AIDL在binder跨进程通信过程中做了什么,起到什么作用。熟悉了这个结构,在后续文章涉及AIDL时就可以一句带过了。
aidl生成类展示
创建aidl文件
AIDL
// ITestService.aidl
package com.lingchen.test.ipc;
interface ITestService {
String getName();
int getProcessId();
}
编译后生成aidl对应接口代码展示:
Java
package com.lingchen.test.ipc;
public interface ITestService extends android.os.IInterface
{
public static class Default implements com.lingchen.test.ipc.ITestService
{
@Override public java.lang.String getName() throws android.os.RemoteException
{
return null;
}
@Override public int getProcessId() throws android.os.RemoteException
{
return 0;
}
@Override
public android.os.IBinder asBinder() {
return null;
}
}
public static abstract class Stub extends android.os.Binder implements com.lingchen.test.ipc.ITestService
{
private static final java.lang.String DESCRIPTOR = "com.lingchen.test.ipc.ITestService";
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
public static com.lingchen.test.ipc.ITestService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.lingchen.test.ipc.ITestService))) {
return ((com.lingchen.test.ipc.ITestService)iin);
}
return new com.lingchen.test.ipc.ITestService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getName:
{
data.enforceInterface(descriptor);
java.lang.String _result = this.getName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_getProcessId:
{
data.enforceInterface(descriptor);
int _result = this.getProcessId();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.lingchen.test.ipc.ITestService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public java.lang.String getName() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getName();
}
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
@Override public int getProcessId() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getProcessId, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getProcessId();
}
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
public static com.lingchen.test.ipc.ITestService sDefaultImpl;
}
static final int TRANSACTION_getName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getProcessId = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
public static boolean setDefaultImpl(com.lingchen.test.ipc.ITestService impl) {
if (Stub.Proxy.sDefaultImpl != null) {
throw new IllegalStateException("setDefaultImpl() called twice");
}
if (impl != null) {
Stub.Proxy.sDefaultImpl = impl;
return true;
}
return false;
}
public static com.lingchen.test.ipc.ITestService getDefaultImpl() {
return Stub.Proxy.sDefaultImpl;
}
}
public java.lang.String getName() throws android.os.RemoteException;
public int getProcessId() throws android.os.RemoteException;
}
解释
客户端
Java
// 使用
// asInterface得到的是一个代理类Proxy
mService = ITestService.Stub.asInterface(service);
String name = mService.getName();
Java
// AIDL
public static com.lingchen.test.ipc.ITestService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.lingchen.test.ipc.ITestService))) {
return ((com.lingchen.test.ipc.ITestService)iin);
}
return new com.lingchen.test.ipc.ITestService.Stub.Proxy(obj);
}
在客户端可以通过调用 asInterface 可以获得Proxy代理对象,这里的service是在客户端本地代表对端server的binder引用。
asInterface的实现就是创建一个Proxy代理对象。
Java
private static class Proxy implements com.lingchen.test.ipc.ITestService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
Proxy是实现了ITestService接口的代理类,它持有代表对端的IBinder对象。
Java
// Proxy
@Override public java.lang.String getName() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
boolean _status = mRemote.transact(Stub.TRANSACTION_getName, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getName();
}
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
当我们在客户端通过Proxy代理调用接口提供的方法时,Proxy代理会帮调用者做一些组织数据等的动作,然后调用mRemote.transact携带着数据发起binder通信。
服务端
Java
public class TestBinder extends ITestService.Stub {
@Override
public String getName() throws RemoteException {
...
}
@Override
public int getProcessId() throws RemoteException {
...
}
}
通过继承 ITestService.Stub 成为binder服务端,并具体实现ITestService接口方法。
Java
public static abstract class Stub extends android.os.Binder implements com.lingchen.test.ipc.ITestService
{
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_getName:
{
data.enforceInterface(descriptor);
// 调用实现
java.lang.String _result = this.getName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_getProcessId:
{
data.enforceInterface(descriptor);
// 调用实现
int _result = this.getProcessId();
reply.writeNoException();
reply.writeInt(_result);
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
服务端接收到请求后会触发 onTransact 处理,在onTransact中对数据进行解析并调用实现类的具体方法去做具体实现。
使用过程
简单画了个草图:
- client端通过asInterface获取到代理类Proxy
- 通过Proxy代理对象调用其实现的跨进程接口方法发起binder通信
- Proxy代理方法中帮助调用者做了数据封装动作
- Proxy持有代表对端的IBinder对象mRemote,通过mRemote发起实际的binder通信
- server端接收到通信,触发onTransact方法做具体响应
- onTransact方法在aidl生成类的Stub中
- Stub是Binder实现类,服务端通过继承Stub成为binder服务端
- onTransact方法对远程调用的处理是1处理传入的数据2调用this(binder服务实现类)实现的对应的ipc接口方法做具体处理。
对于使用者,在客户端只需要asInterface获取到代理类,直接调用目标方法;在服务端只需要继承Stub成为binder服务端,实现IPC接口要实现的方法即可。而其中的客户端封装数据,调用binder.transact,服务端onTransact响应binder通信,解析数据,回调server具体实现方法,这些繁琐且固定的动作都由AIDL生成类固定封装好了,调用者不需要关心,方便了使用。