Binder通信机制理解
首先,我们通常说的binder驱动,并不是真有驱动,而是表示它运行在内核中,Binder IPC 是基于内存映射(mmap)来实现的,一次通信数据只拷贝一次,内核的数据缓存区跟服务端存在映射关系,所以服务端能直接读取内核数据。
image.png
一次binder通信数据传递过程
1. 客户端绑定并连接成功之后,会得到IBinder类型的对象,此对象就是BinderProxy,这个对象是在native层创建出来,此对象在创建的时候,native层还会把BpBInder对象指针传递进来.这俩是对应关系,BinderProxy中的native方法都会被调到BpBinder里面的方法中。
2. 客户端发起请求,最终会调到BinderProxy中的transact方法,再调进BinderProxy.transactNative --> BpBinder.transact --> IPCThreadState.transact
3. IPCThreadState也是在native层,主要是用来跟Binde驱动进行交互。IPCThreadState的代码一部分给客户端使用,一部分给服务端使用。这里客户端的IPCThreadState类似于socket编程中的客户端。IPCThreadState.transact最终会调到IPCThreadState.talkWithDriver,通过此方法会把数据写入Binder驱动中,如果是异步调用(比如aidl中使用oneway修饰符),直接就通信结束了,如果是同步的,还要再talkWithDriver,等服务端发送的调用结果,此时客户端处于阻塞状态。
4. 服务端也有一个IPCThreadState对象,类似于socket中的服务端,IPCThreadState在talkWithDriver()处于阻塞,等待Binder驱动的消息,当收到Binder驱动的消息后,数据会给传递到IPCThreadState.executeCommand()方法中,根据传递过来的数据,能找到BBinder(native层), BBinder跟java层的Binder对象也是对应关系。执行顺序为IPCThreadState.executeCommand() --> BBinder.transact() --> Binder$Stub.onTransact(),Binder$Stub就是服务端需要实现的Binder。
5. 客户端的IPCThreadState.talkWithDriver阻塞被唤醒,IPCThreadState从Binder驱动中读取数据。
image.png
AIDL生成java代码分析:
package com.autoai.test;
interface IMusicManager {
boolean play();
}
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.autoai.test;
public interface IMusicManager extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.autoai.test.IMusicManager {
private static final java.lang.String DESCRIPTOR = "com.autoai.test.IMusicManager";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.autoai.test.IMusicManager interface,
* generating a proxy if needed.
*/
//客户端绑定服务端之后,拿到的IBinder对象,需要调用此方法,如果传入的obj是本地Binder对象,不需要转化
//如果是远程Binder,那么obj就是BinderProxy对象,需要创建Binder代理对象
public static com.autoai.test.IMusicManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
//如果是本地Binder
if (((iin != null) && (iin instanceof com.autoai.test.IMusicManager))) {
return ((com.autoai.test.IMusicManager) iin);
}
//如果是远程Binder,创建Binder代理
return new com.autoai.test.IMusicManager.Stub.Proxy(obj);
}
@Override
public android.os.IBinder asBinder() {
return this;
}
//此方法服务端会调用,当收到客户端传递过来的数据,这里会给触发,服务端被触发的顺序为:
//TCPThreadState.executeCommand-->BBinder.transact-->Binder$Stub.onTransact
@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_play: {
data.enforceInterface(descriptor);
boolean _result = this.play();
reply.writeNoException();
reply.writeInt(((_result) ? (1) : (0)));
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}
//这里就是客户端需要用到的代理,客户端调用Proxy中方法,向服务端发起请求
private static class Proxy implements com.autoai.test.IMusicManager {
//mRemote就是BinderProxy,与之对应的native层对象是BpBinder
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 boolean play() throws android.os.RemoteException {
//_data是客户端传给服务端的数据
android.os.Parcel _data = android.os.Parcel.obtain();
//_replay是服务端传给客户端的数据
android.os.Parcel _reply = android.os.Parcel.obtain();
boolean _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//BinderProxy调用transact,触发BpBinder.transact-->TCPThreadState.transact-->TCPThreadState.talkWithDriver
//TCPThreadState.talkWithDriver调用之后会处于等待状态,等待服务器返回数据
mRemote.transact(Stub.TRANSACTION_play, _data, _reply, 0);
_reply.readException();
//读取服务端返回的数据
_result = (0 != _reply.readInt());
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_play = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public boolean play() throws android.os.RemoteException;
}
参考文章:
https://zhuanlan.zhihu.com/p/35519585
https://blog.csdn.net/learnframework/article/details/121645259
https://blog.csdn.net/freshui/article/details/55051268
https://blog.csdn.net/pi9nc/article/details/9749325/
https://blog.csdn.net/gykimo/article/details/8901192












网友评论