应用层从 AIDL 说起,AIDL 全称 Android Interface Definition Language,是一个用以描述/定义 接口 的文本文件,有着与 java 类似的简单语法
下面是一个非常简单的 AIDL 文件,位于 {projectPath}/app/src/main/aidl/work/dalvik/binder/example/IAidlExampleInterface.aidl,一般不与 java/kotlin 代码同目录,它定义了一个返回所在进程 ID 的方法:getPid()
// IAidlExampleInterface.aidl
package work.dalvik.binder.example;
// Declare any non-default types here with import statements
interface IAidlExampleInterface {
int getPid(); // 获取进程 ID
}
上面所说的 接口 往往是 IPC 方法调用,当然也可以是本进程内的方法调用,实现这个接口的叫 服务端,那么调用接口的就是 客户端
使用 AIDL 时,服务端和客户端都有一份这个 AIDL 文件,执行一下 Android Studio 菜单:Build - Make Project,就会生成对应的 java 代码如下,主要有四个:
getPid() 方法
public interface IAidlExampleInterface extends android.os.IInterface {
public int getPid() throws android.os.RemoteException;
public static abstract class Stub extends android.os.Binder implements work.dalvik.binder.example.IAidlExampleInterface {
public static work.dalvik.binder.example.IAidlExampleInterface asInterface(android.os.IBinder obj) { ... }
private static class Proxy implements work.dalvik.binder.example.IAidlExampleInterface {
Proxy(android.os.IBinder remote) { mRemote = remote; }
// ...
}
// ...
}
// ...
}
注册两个 Service,一个运行在 app 进程,一个运行在 :child 子进程,从日志可以看到:
private class AidlExampleImpl: IAidlExampleInterface.Stub() {
override fun getPid(): Int = Process.myPid()
}
abstract class BaseService : Service() {
private val mBinder = AidlExampleImpl()
override fun onBind(intent: Intent): IBinder = mBinder
}
class ExampleService: BaseService()
class ChildService: BaseService()
<service android:name=".ChildService"
android:enabled="true"
android:exported="false"
android:process=":child"
/>
<service android:name=".ExampleService"
android:enabled="true"
android:exported="false"
/>
val conn = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
val binder = IAidlExampleInterface.Stub.asInterface(service)
Log.d("cyrus", "my pid: ${Process.myPid()}, service pid: ${binder.pid}, ${binder.javaClass}, ${service.javaClass}")
}
override fun onServiceDisconnected(name: ComponentName?) {}
}
bindService(Intent(this, ExampleService::class.java), conn, Context.BIND_AUTO_CREATE)
bindService(Intent(this, ChildService::class.java), conn, Context.BIND_AUTO_CREATE)
// my pid: 13070, service pid: 13070, class work.dalvik.binder.example.AidlExampleImpl, class work.dalvik.binder.example.AidlExampleImpl
// my pid: 13070, service pid: 13122, class work.dalvik.binder.example.IAidlExampleInterface$Stub$Proxy, class android.os.BinderProxy
服务端的接口实现是继承自 Stub 的,queryLocalInterface() 和 asInterface() 返回的都是自己,所以同进程的情况下客户端拿到的 IBinder 和 asInterface() 返回的都是服务端对象
不同进程的情况下客户端拿到的 IBinder 是 BinderProxy,BinderProxy.queryLocalInterface 直接返回 null 导致 asInterface 返回 Proxy 实例,Proxy 实例把接口调用代理给 BinderProxy 实例,最终接口调用在 BinderProxy.transactNative() 进入 native 层
public static work.dalvik.binder.example.IAidlExampleInterface asInterface(android.os.IBinder obj) {
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof work.dalvik.binder.example.IAidlExampleInterface))) { // 同进程
return ((work.dalvik.binder.example.IAidlExampleInterface)iin);
}
return new work.dalvik.binder.example.IAidlExampleInterface.Stub.Proxy(obj); // 不同进程
}
public class Binder implements IBinder {
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
mOwner = owner;
mDescriptor = descriptor;
}
}
// 服务端继承自 Stub 并将 mOwner 指向自己,将 mDescriptor 指向常量 DESCRIPTOR(接口的全限定名称)
public static abstract class Stub extends android.os.Binder implements work.dalvik.binder.example.IAidlExampleInterface {
private static final java.lang.String DESCRIPTOR = "work.dalvik.binder.example.IAidlExampleInterface";
/** Construct the stub at attach it to the interface. */
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
}
// BinderProxy 主要是将方法调用转换为 transact 调用,类似于 RPC 的概念
public final class BinderProxy implements IBinder {
public IInterface queryLocalInterface(String descriptor) {
return null;
}
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
// ...
try {
return transactNative(code, data, reply, flags);
} ...
}
// 不同进程的情况下,客户端的接口调用在这里进入 native 层
public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException;
}
// Proxy 如它的名称一样就是个代理模式,将所有方法调用代理至 remote
private static class Proxy implements work.dalvik.binder.example.IAidlExampleInterface
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
// 把接口调用代理至 remote,也即是 BinderProxy
@Override public int getPid() 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_getPid, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getPid();
}
_reply.readException();
_result = _reply.readInt();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}