AIDL(Android Interface Definition Language) 是 Android 系统提供的进程间通信方式,底层是根据 Binder 机制实现,是对上层代码的封装。
Android 的系统服务基本上都是通过 AIDL 实现的,比如 AMS 通过 IApplicationThread.aidl 实现,WMS 通过 IWindowManager.aidl 实现。
示例代码
源码请看 Github。
1. 在 app/src/main/aidl/com.app.aidlsample 目录下创建 IRemoteService.aidl 文件,声明服务方法:
1 2 3 4 5 6
| // 注意写上包名,不然会找不到生成的 IRemoteAidl 类 package com.app.aidlsample;
interface IRemoteAidl{ String search(String key); }
|
点击 Build > Rebuild Project 后,会在 build/generated/aidl_source_output_dir/debug/out/com.app.aidlsample 文件夹下生成和 IRemoteAidl.aidl 文件对应的 IRemoteAidl.java 文件。该文件是通过 Gradle 的 Task :app:compileDebugAidl 任务生成的。
2. 创建服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public class RemoteAidlService extends Service { public static final String TAG = "IRemoteAidl";
@Nullable @Override public IBinder onBind(Intent intent) { return new AAA(); }
private static class AAA extends IRemoteAidl.Stub { @Override public String search(String key) throws RemoteException { Log.i(TAG, "search。Key: " + key + ", Thread: " + Thread.currentThread()); SystemClock.sleep(2000); return "Hello, " + key; } } }
|
在 AndroidManifest.xml 配置:
1 2 3
| <service android:name=".RemoteAidlService" android:process=":remote" />
|
android:process=":remote" 说明 RemoteAidlService 服务运行在子进程。
3. 绑定服务,调用远程服务:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class MainActivity extends AppCompatActivity { public static final String TAG = "IRemoteAidl"; private IRemoteAidl mRemoteAidlService;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
Intent intent = new Intent(this, RemoteAidlService.class); bindService(intent, new ServiceConnection() { @Override public void onServiceConnected(ComponentName componentName, IBinder iBinder) { Log.i(TAG, "onServiceConnected. componentName: " + componentName + " iBinder: " + iBinder); mRemoteAidlService = IRemoteAidl.Stub.asInterface(iBinder); }
@Override public void onServiceDisconnected(ComponentName componentName) { Log.i(TAG, "onServiceDisconnected. componentName: " + componentName);
} }, Context.BIND_AUTO_CREATE);
findViewById(R.id.tv_search).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (mRemoteAidlService != null) { try { String result = mRemoteAidlService.search("World!"); Log.i(TAG, "From Remote Service: " + result + ", Thread: " + Thread.currentThread()); } catch (RemoteException e) { e.printStackTrace(); } } } }); } }
|
Log 如下:
1 2 3
| 16:11:18.573 I/IRemoteAidl: onServiceConnected. componentName: ComponentInfo{com.app.aidlsample/com.app.aidlsample.RemoteAidlService} iBinder: android.os.BinderProxy@f4e8c9e 16:11:20.563 I/IRemoteAidl: search。Key: World!, Thread: Thread[Binder:18797_1,5,main] 16:11:22.565 I/IRemoteAidl: From Remote Service: Hello, World!, Thread: Thread[main,5,main]
|
源码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| package com.app.aidlsample;
public interface IRemoteAidl extends android.os.IInterface { public static class Default implements com.app.aidlsample.IRemoteAidl { @Override public java.lang.String search(java.lang.String key) throws android.os.RemoteException { return null; } @Override public android.os.IBinder asBinder() { return null; } } public static abstract class Stub extends android.os.Binder implements com.app.aidlsample.IRemoteAidl { private static final java.lang.String DESCRIPTOR = "com.app.aidlsample.IRemoteAidl";
public Stub() { this.attachInterface(this, DESCRIPTOR); }
public static com.app.aidlsample.IRemoteAidl asInterface(android.os.IBinder obj) { if ((obj==null)) { return null; } android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); if (((iin!=null)&&(iin instanceof com.app.aidlsample.IRemoteAidl))) { return ((com.app.aidlsample.IRemoteAidl)iin); } return new com.app.aidlsample.IRemoteAidl.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_search: { data.enforceInterface(descriptor); java.lang.String _arg0; _arg0 = data.readString(); java.lang.String _result = this.search(_arg0); reply.writeNoException(); reply.writeString(_result); return true; } default: { return super.onTransact(code, data, reply, flags); } } }
private static class Proxy implements com.app.aidlsample.IRemoteAidl { 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 search(java.lang.String key) 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); _data.writeString(key); boolean _status = mRemote.transact(Stub.TRANSACTION_search, _data, _reply, 0); if (!_status && getDefaultImpl() != null) { return getDefaultImpl().search(key); } _reply.readException(); _result = _reply.readString(); } finally { _reply.recycle(); _data.recycle(); } return _result; } public static com.app.aidlsample.IRemoteAidl sDefaultImpl; }
static final int TRANSACTION_search = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
public static boolean setDefaultImpl(com.app.aidlsample.IRemoteAidl 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.app.aidlsample.IRemoteAidl getDefaultImpl() { return Stub.Proxy.sDefaultImpl; } }
public java.lang.String search(java.lang.String key) throws android.os.RemoteException; }
|
- IBinder : IBinder 是一个接口,代表了一种跨进程通信的能力。只要实现了这个借口,这个对象就能跨进程传输。
- IInterface : IInterface 代表的就是 Server 进程对象具备什么样的能力(能提供哪些方法,其实对应的就是 AIDL 文件中定义的接口)
- Binder : Java 层的 Binder 类,代表的其实就是 Binder 本地对象,BinderProxy 代表远程进程的 Binder 对象的本地代理;这两个类都继承自 IBinder, 因而都具有跨进程传输的能力;实际上,在跨越进程的时候,Binder 驱动会自动完成这两个对象的转换。
- Stub : 是一个抽象类,类继承了 Binder, 说明它是一个 Binder 本地对象,它实现了 IInterface 接口,表明它具有 Server 承诺给 Client 的能力;具体的 IInterface 的相关实现需要服务端实现。
- Default:服务的默认实现。
AIDL 总是那么一种固定的模式:一个需要跨进程传递的对象一定继承自 IBinder,如果是 Binder 本地对象,那么一定继承 Binder 实现 IInterface,如果是代理对象,那么就实现了 IInterface 并持有了 IBinder 引用;
跨进程通信流程如下:
- Client 通过 Binder 代理对象调用远程服务,Client 线程挂起阻塞;
- Binder 代理对象将请求派发给 Binder 驱动;
- Binder 驱动再将请求派发给 Server 端,Server 端处理后将结果返回给 Binder 驱动;
- 唤醒 Client 线程,返回结果给 Client;
总结
AIDL 通过 aidl 文件生成了一个接口,接口中的 Stub 类用于服务端,Proxy 类用于服务代理 。通过继承 Stub 实现服务端,很大程度上简化 Android 进程间通信。
参考
[1] Android 接口定义语言 (AIDL)
[2] 写给 Android 应用工程师的 Binder 原理剖析