AIDL 的用法
Step 1 定义通信协议
先看一段代码,这个是一个很简单的计算,A进程发起计算,B进程进行计算,返回结果。
interface ICalculatorService {
String add(int a, int b, );
}
编译后得到AIDL文件,我们拆分一下客户端进程A使用类 和 进程B服务端使用类:
Step 2 客户端A进程代码实现
客户端A进程使用aidl做加减:
private var calculatorService: ICalculatorService? = null
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
calculatorService = ICalculatorService.Stub.asInterface(service)
isBound = true
callRemoteAdd(3, 5)
}
override fun onServiceDisconnected(name: ComponentName?) {
calculatorService = null
isBound = false
}
}
private fun callRemoteAdd(a: Int, b: Int) {
try {
val result = calculatorService?.add(a, b)
val mainProcess = currentProcessName()
val message = "主进程: $mainProcess\n调用 add($a, $b)\n返回: $result"
binding.sampleText.text = message
Log.d(TAG, message)
} catch (e: RemoteException) {
binding.sampleText.text = "AIDL 调用失败: ${e.message}"
Log.e(TAG, "AIDL call failed", e)
}
}
private fun bindCalculatorService() {
val intent = Intent(this, CalculatorService::class.java)
isBound = bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
if (!isBound) {
binding.sampleText.text = "绑定 CalculatorService 失败"
}
}
这个是客户端的代码,点击按钮调用 bindCalculatorService(),回调中返回了onServiceConnected IBinder,然后ICalculatorService.Stub.asInterface 转为Proxy,我们看一看Proxy都做了什么:
public static com.example.wu.myapplication.ICalculatorService asInterface(android.os.IBinder obj){
return new com.example.wu.myapplication.ICalculatorService.Stub.Proxy(obj);
}
把一个远程的iBinder对象包装了一下变为ICalculatorService.Stub.Proxy 我们再看看这个ICalculatorService.Stub.Proxy都干了什么
private static class Proxy implements com.example.wu.myapplication.ICalculatorService
{
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 add(int a, int b) 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.writeInt(a);
_data.writeInt(b);
boolean _status = mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
主要看add 做了什么 1.把数据入参使用Parcel封装一下 2.mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0); 3._reply.readException(); _result = _reply.readString();
这个看起来就是我拿到了一个B进程的一个binder,AIDL文件帮我们生成帮助代理类,实际是用B进程返回的binder进行transact调用,等待结果。
Step 3 进程A怎么得到的binder对象
具体流程如下:
1)Activity作为Client发起bindService,最终会调度到AMS去执行bindService。在这个过程中,Client要去调用AMS的代码,所以此时就会涉及到跨进程调度,基于第三章的Binder通信模型我们不难知道,Client会先和ServiceManager通信,从ServiceManager中拿到AMS的IBinder。
2)Activity拿到AMS的IBinder后,跨进程执行AMS的BindService函数;
3)由于AMS管理所有的应用进程,因此AMS中持有了应用进程的Binder,所以此时AMS可以发起第4步也就是跨进程调度scheduleBindService();
4)Server端会在收到AMS的bindService的请求后,会将自己的IBinder发送给Client,但是Server必须通过AMS才能将Binder对象传过去,所以此时需要跨进程从ServiceManager中去拿到AMS的binder;
5)Serve端通过AMS的binder直接调用AMS的代码publishService(),将service的Binder发送给AMS;
6)经过层层调用,最终AMS讲Server端的binder通过回调connect函数传递给了Client端的Activity;
以上就是bindService的全流程,这个流程主要的目的是将server端的Binder对象发送给Client端。从此以后,Client端就可以通过Server端的binder与Server端像调用自己的代码一样完成跨进程通信了。
下面是一步一步的分析
bindService() 会先通过 ServiceManager 找到系统的 activity 服务,也就是 ActivityManagerService。
// ContextImpl.java
private boolean bindServiceCommon(Intent service, ServiceConnection conn, long flags,
String instanceName, Handler handler, Executor executor, UserHandle user) {
...
int res = ActivityManager.getService().bindServiceInstance(
mMainThread.getApplicationThread(), getActivityToken(), service,
service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, instanceName, getOpPackageName(), user.getIdentifier());
ActivityManager.getService() 这里才会查 ServiceManager,拿到的是 AMS:
// ActivityManager.java
public static IActivityManager getService() {
return IActivityManagerSingleton.get();
}
private static final Singleton<IActivityManager> IActivityManagerSingleton =
new Singleton<IActivityManager>() {
@Override
protected IActivityManager create() {
final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
final IActivityManager am = IActivityManager.Stub.asInterface(b);
return am;
}
};
到了 system_server 以后,AMS 转给 ActiveServices:
// ActivityManagerService.java
synchronized (this) {
return mServices.bindServiceLocked(caller, token, service, resolvedType, connection,
flags, instanceName, isSdkSandboxService, sdkSandboxClientAppUid,
sdkSandboxClientAppPackage, sdkSandboxClientApplicationThread,
callingPackage, userId);
}
ActiveServices 再根据 Intent、ComponentName、包名、userId 等去解析并维护 ServiceRecord、ConnectionRecord,而不是查 native ServiceManager:
// ActivityManagerService.java
ServiceLookupResult res = retrieveServiceLocked(service, instanceName,
isSdkSandboxService, sdkSandboxClientAppUid, sdkSandboxClientAppPackage,
resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg,
isBindExternal, allowInstant, null /* fgsDelegateOptions */,
inSharedIsolatedProcess, inPrivateSharedIsolatedProcess, matchQuarantined);
...
ServiceRecord s = res.record;
final AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp, attributedApp);
服务进程起来后,AMS 会让目标 app 执行 Service.onBind():
// ActivityServices.java
r.app.getThread().scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.mState.getReportedProcState(), mBindServiceSeqCounter++);
目标 app 的 onBind() 返回的通常就是你 AIDL 生成的 Stub 对象,我们这里说一下B进程的服务端:
private val binder = object : ICalculatorService.Stub() {
override fun add(a: Int, b: Int): String {
val processName = currentProcessName()
val sum = a + b
Log.d(TAG, "add($a, $b) = $sum in process=$processName, pid=${android.os.Process.myPid()}")
return "$processName: $sum"
}
}
override fun onBind(intent: Intent?): IBinder {
Log.d(TAG, "onBind in process=${currentProcessName()}, pid=${android.os.Process.myPid()}")
return binder
}
我们再看看stub的定义:
public static abstract class Stub extends android.os.Binder implements com.example.wu.myapplication.ICalculatorService
{
/** Construct the stub at attach it to the interface. */
@SuppressWarnings("this-escape")
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.wu.myapplication.ICalculatorService interface,
* generating a proxy if needed.
*/
@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;
if (code >= android.os.IBinder.FIRST_CALL_TRANSACTION && code <= android.os.IBinder.LAST_CALL_TRANSACTION) {
data.enforceInterface(descriptor);
}
if (code == INTERFACE_TRANSACTION) {
reply.writeString(descriptor);
return true;
}
switch (code)
{
case TRANSACTION_add:
{
int _arg0;
_arg0 = data.readInt();
int _arg1;
_arg1 = data.readInt();
java.lang.String _result = this.add(_arg0, _arg1);
reply.writeNoException();
reply.writeString(_result);
break;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
return true;
}
static final int TRANSACTION_add = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
Stub也就是一个 Java Binder。这个 IBinder 再通过 AMS 回调给客户端:
// ActivityServices.java
b.binder = service;
b.requested = true;
b.received = true;
...
c.conn.connected(clientSideComponentName, service, false);
客户端 ServiceConnection.onServiceConnected(name, binder) 收到这个 binder 后,你通常写:
ICalculatorService.Stub.asInterface(service)
这就攒起来了,从客户端A出发,拿到服务端B的一个binder了。
Step 4 一次add(1,2)怎么拿到的结果
...
mRemote.transact(TRANSACTION_add, _data, _reply, 0);
transact 做了什么
如果是跨进程,mRemote 通常是 BinderProxy。
AOSP 里 BinderProxy.transact() 最终会调用 native:
// BinderProxy.java
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
// ...
final boolean result = transactNative(code, data, reply, flags);
JNI 层在 android_util_Binder.cpp:
// android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags)
{
// ...
IBinder* target = getBPNativeData(env, obj)->mObject.get();
// ...
status_t err = target->transact(code, *data, reply, flags);
native Binder 再进入 IPCThreadState::transact(),写 BC_TRANSACTION 给 Binder 驱动:
// IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
// ...
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, nullptr);
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
err = waitForResponse(reply);
}
普通 AIDL 方法不是 oneway,所以客户端线程会阻塞在 waitForResponse(reply),等服务端算完返回。
服务端怎么进入 onTransact
服务端进程有 Binder 线程池,线程等待 Binder 驱动消息。驱动把请求送到服务端后,服务端 native 层收到 BR_TRANSACTION:
// IPCThreadState.cpp
case BR_TRANSACTION:
// ...
Parcel buffer;
buffer.ipcSetDataReference(...);
Parcel reply;
status_t error;
if (tr.target.ptr) {
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(
tr.code, buffer, &reply, tr.flags);
如果服务端对象是 Java Binder,native 会回调 Java 的 Binder.execTransact():
//android_util_Binder.cpp
status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
{
// ...
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
Java 层 Binder.execTransactInternal() 再调用真正的 onTransact():
// Binder.java
res = onTransact(code, data, reply, flags);
// ...
res = onTransact(code, data, reply, flags);
Binder.java 就是在进程B中Stub 的实现类,Binder是他们的父类
服务端 onTransact 如何做加法
请求到达后,Stub 根据 code 判断是哪一个方法:
// ICalculatorService.Stub()
case TRANSACTION_add:
data.enforceInterface(DESCRIPTOR);
int _arg0 = data.readInt(); // 读出 a
int _arg1 = data.readInt(); // 读出 b
String _result = this.add(_arg0, _arg1); // 真正执行加法
reply.writeNoException();
reply.writeString(_result);
return true;
// 服务端进程B的实现
private val binder = object : ICalculatorService.Stub() {
override fun add(a: Int, b: Int): String {
val processName = currentProcessName()
val sum = a + b
Log.d(TAG, "add($a, $b) = $sum in process=$processName, pid=${android.os.Process.myPid()}")
return "$processName: $sum"
}
}
终于到了B进程得到了 “进程B : 3” 再会写到reply
reply.writeNoException();
reply.writeString("3");
服务端 native 层把 reply 通过 Binder 驱动发回客户端。客户端 waitForResponse(reply) 返回后,Proxy.add() 继续执行:
_reply.readException();
String _result = _reply.readString();
return _result;
从南阳到南洋,根深叶茂啊,从binder到binder,一个来回啊
客户端 service.add(1,2)
-> Proxy.add()
-> _data.writeInt(1), _data.writeInt(2)
-> BinderProxy.transact(TRANSACTION_add, _data, _reply, 0)
-> native Binder / Binder 驱动
-> 服务端 Binder 线程收到 BR_TRANSACTION
-> Java Binder.execTransact()
-> Stub.onTransact()
-> data.readInt(), data.readInt()
-> this.add(1,2)
-> reply.writeString("3")
-> Binder 驱动返回
-> Proxy 读 _reply.readString()
-> 客户端得到 "3"