这是一系列的 Binder 文章,会从内核层到 Framework 层,再到使用层,深入浅出,介绍整个 Binder 的规划。详见《图解 Binder:概述》。
本文基于 Android platform 分支 android-13.0.0_r1 和内核分支 common-android13-5.15 解析。
一些要害代码的链接,可能会由于源码的变动,发生位置偏移、丢失等现象。能够搜索函数名,从头进行定位。
AIDL(Android Interface Definition Language)是一种支持跨进程通讯 (IPC) 的接口界说言语。在 Android 系统中,各个进程一般运用 Binder 通讯。Android 供给的 AIDL 也是基于 Binder 的。经过 AIDL,咱们能够使用其他进程的 Service,调用其他进程的函数。
AIDL 的效果,其实便是为开发者生成两个类:Stub 和 Proxy。这两个类都是一些模板代码,主要目的除了减轻开发者的工作量以外,也是为了隐藏跨进程通讯 (IPC) 的各种细节在这两个类中,使得开发者只需求重视完成详细的服务逻辑,而无需关怀底层通讯的细节。
Stub 一般用于服务端,Proxy 一般用于客户端。
AIDL 的运用
要在 Java 中运用 AIDL,咱们需求履行以下步骤:
-
无论是客户端,仍是服务端,都要界说 AIDL 接口:创立一个后缀为 .aidl 的文件,并在其中界说一个接口。接口中能够声明需求跨进程调用的函数。例如,创立一个名为 IExampleService.aidl 的文件,其内容如下:
package com.example; interface IExampleService { String getMessage(); }
-
编译生成代码:编译项目时,AIDL 编译器会主动为界说的 AIDL 接口生成对应的 Java 文件:IExampleService.java。生成的文件里包含了 IExampleService 接口、Stub 类和 Proxy 类。
-
在服务端里供给一个 Service,由 Service 供给 Binder 实体:Stub 类承继自 Binder,这意味它本身便是个 Binder 实体,但是它是个抽象类,不供给 getMessage() 的完成。所以,需求咱们承继 Stub,然后完成 getMessage()。最终,再创立一个 ExampleService(承继自 Service 类),然后在它的 onBind 里,回来咱们的 Binder 实体。
package com.example; public class ExampleService extends Service { private final IExampleService.Stub mBinder = new IExampleService.Stub() { @Override public String getMessage() { return "Hello from ExampleService!"; } }; @Override public IBinder onBind(Intent intent) { return mBinder; } }
当然,不要忘了在服务端的 AndroidManifest.xml 中注册服务:
<service android:name=".ExampleService" android:exported="true" android:enabled="true"> <intent-filter> <action android:name="com.example.IExampleService"/> </intent-filter> </service>
-
客户端经过 AIDL ,调用服务端里的 getMessage():
先在客户端进程中,bindService() 绑定服务端的 ExampleService 服务。例如:
private IExampleService mExampleService; private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { mExampleService = IExampleService.Stub.asInterface(service); } @Override public void onServiceDisconnected(ComponentName className) { mExampleService = null; } }; void bindService() { Intent intent = new Intent("com.example.IExampleService"); intent.setPackage("com.example"); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } void unbindService() { if (mExampleService != null) { unbindService(mConnection); mExampleService = null; } }
这样,在客户端进程能够经过 AIDL 生成的 Proxy 的 getMessage(),调用服务端的 getMessage():
try { String message = mExampleService.getMessage(); } catch (RemoteException e) { e.printStackTrace(); }
Stub 和 Proxy
在 AIDL 主动生成的 IExampleService.java里,最要害的是 Stub 和 Proxy。它们之间的关系如下图:
Proxy 一般用于客户端,最要害的是它的 getMessage() :
public String getMessage() throws android.os.RemoteException {
// _data 是写缓冲区
android.os.Parcel _data = android.os.Parcel.obtain();
// _reply 是读缓冲区
android.os.Parcel _reply = android.os.Parcel.obtain();
String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
// TRANSACTION_getMessage 是函数索引
// mRemote 是 BinderProxy 的实例
boolean _status = mRemote.transact(Stub.TRANSACTION_getMessage, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
return getDefaultImpl().getMessage();
}
_reply.readException();
// 从读缓冲区读取长途调用的成果
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
Stub 一般用于服务端。Stub 承继自 Binder,代表它便是一个 Binder 实体。它是一个抽象类,不会完成 getMessage(),交给子类去完成。咱们需求留意一下它的 onTransact():
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)
throws android.os.RemoteException {
String descriptor = DESCRIPTOR;
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(descriptor);
return true;
}
// 目标函数的索引
case TRANSACTION_getMessage: {
data.enforceInterface(descriptor);
// 调用 getMessage()
String _result = this.getMessage();
reply.writeNoException();
// 回来成果给客户端
reply.writeString(_result);
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
在一次 getMessage() 的跨进程调用里,它们的效果如下:
transact()
transact() 会向 Binder 驱动建议业务,大致的调用链路是:
BinderProxy.java
└─transact()
└──transactNative()
└───android_util_Binder.cpp.cpp
└────android_os_BinderProxy_transact()
└─────BpBinder.cpp
└──────transact()
└───────IPCThreadState.cpp
└────────self()
└─────────transact()
└──────────writeTransactionData()
└──────────waitForResponse()
└───────────talkWithDriver()
└────────────ioctl.cpp
└─────────────ioctl()
注意:从 transact() 到 ioctl() ,这个过程都是同步调用。即当咱们经过 AIDL 调用长途服务时,客户端会等待服务端完成处理并回来成果。整个过程中,客户端线程会堵塞,直到收到来自服务端的回应。所以,咱们千万别在主线程建议调用。
onTransact()
服务端的 Binder 线程池的线程接收到 BR_TRANSACTION 音讯后,会一路调用到 onTransact():
IPCThreadState.cpp
└─executeCommand() // 读取服务端的读缓冲区数据,处理 BR_TRANSACTION 音讯
└──Binder.cpp
└───BBinder::transact() // 根据业务数据里的函数索引、参数,完成函数调用。
└────JavaBBinder.cpp(承继自 BBinder)
└─────onTransact()
└──────Binder.java
└───────execTransact()
└────────execTransactInternal()
└─────────onTransact() // Stub 会覆盖父类的 onTransact()
BpBinder 与 BinderProxy、BBinder 与 Binder
transact() 和 onTransact() 的调用链路里出现了 BpBinder、BinderProxy、BBinder(JavaBBinder)和 Binder。
在 Binder 业务一文,已经提到过,BBinder 即 Binder 实体,而 BpBinder 即 Binder 署理,持有着 Binder 引证。它们两个都是 C++ 里的类。
而 Binder、BinderProxy 则是它们的 Java 层表明。如下图:
使用级服务
服务端供给的 ExampleService 属于使用级服务。在前面的示例中,咱们在客户端里会经过 bindService() 发动它,并在 ServiceConnection 回调里,拿到了所需的 Binder 引证。
使用等级的服务一般不会注册到 ServiceManager,而是由 AMS 进行管理。
当客户端建议 bindService() 调用后,会经过 Binder 调用到 AMS 的 bindServiceLocked(),进行服务的绑定。假如服务还没发动,AMS 会经过 Binder 通讯,告诉服务端创立、发动和绑定服务。服务端履行绑定逻辑后,会传递 Binder 实体给 Binder 驱动,Binder 驱动转化为 Binder 引证后,再传给 AMS。最终由 AMS 转交给客户端,即最终会履行 ServiceConnection 回调的 onServiceConnected()。
- Binder 实体是服务端里的 IExampleService.Stub mBinder。
- Binder 引证均是经过 Binder 驱动转化的,上图没有画出 Binder 驱动。
aidl-cpp
C++ 层也能够经过 aidl-cpp 来运用 AIDL。