需要了解
1. binder 整体的架构原理
2. 了解应用和binder驱动的交互原理(client 端和 Server 端与binder驱动的交互是不一样的)
3. 了解 IPC 过程中的通信协议
binder 的架构
上图从参与角色来看分为 Client、Server 和 binder 驱动,从分层来看分为 应用层、(java Framework层、Native 层)驱动层。
Client 端发起 IPC 调用后,就是将 Proxy 给到了 BinderProxy ,然后BinderProxy传入到了 Native层的 BpBinder ,然后通过 IPCThreadState 调用了 transact 把数据丢给驱动,驱动在把数据丢到 Server 进程,在他的binder线程中网上传递。
client 端
- Client 端是怎么将请求发送到 Server 端的?
以 aidl 为例,客户端和服务端有同一个 aidl 文件,服务端注册好 Service
interface IMyAidlInterface {
void go(String param);
}
编译完成后,通过连接 service 来获取 binder 对象代码如下:
private var iMyAidlInterface: IMyAidlInterface? = null
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
Log.e(tag, "onServiceConnected")
iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service)
}
override fun onServiceDisconnected(name: ComponentName?) {
Log.e(tag, "onServiceDisconnected")
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
// 点击绑定
fun bindService(view: View) {
val intent = Intent()
intent.component = ComponentName("com.example.server", "com.example.server.MyService")
bindService(intent, serviceConnection, BIND_AUTO_CREATE)
}
// 点击执行服务端的go() 方法
fun invokeFun(view: View) {
iMyAidlInterface?.go("hello aidl....")
}
aidl 文件生成.java 文件的 proxy 代理类如下:
private static class Proxy implements com.example.server.IMyAidlInterface
{
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 void go(java.lang.String param) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(param);
boolean _status = mRemote.transact(Stub.TRANSACTION_go, _data, _reply, 0);
if (!_status && getDefaultImpl() != null) {
getDefaultImpl().go(param);
return;
}
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public static com.example.server.IMyAidlInterface sDefaultImpl;
}
go() 方法先把数据都写到 Parcel 里面,然后通过 mRemote.transact() 进行底层的交互,如上图所示,走到了 BinderProxy 的 transact() 方法
- BinderProxy.java 中 transact 方法最后调用到了 transactNative 方法
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
return transactNative(code, data, reply, flags);
}
public native boolean transactNative(int code, Parcel data, Parcel reply,
int flags) throws RemoteException;
- android_util_Binder.cpp 的 android_os_BinderProxy_transact() 方法
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
// dataObj 中封装的是java层传入进来的数据 这个在 aidl 编译后生成的 Proxy 对象中可以看得到下面代码
// android.os.Parcel _data = android.os.Parcel.obtain();
// _data.writeInterfaceToken(DESCRIPTOR); 这个是记录的java层aidl接口地址
// _data.writeString(param); // 这是写入的参数
if (dataObj == NULL) {
jniThrowNullPointerException(env, NULL);
return JNI_FALSE;
}
// 先通过java对象创建 native 层的 Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
if (data == NULL) {
return JNI_FALSE;
}
Parcel* reply = parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
// 通过 binderProxy 对象 拿到 native 层的 binder 对象 ,也就是 BPBinder
IBinder* target = getBPNativeData(env, obj)->mObject.get();
// ....
// 获取到 BPBinder 以后,调用它的 transact() 方法
status_t err = target->transact(code, *data, reply, flags);
// .....
return JNI_FALSE;
}
- BPBinder.cpp 中的 transact 函数
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
BpBinder 把请求交给了 IPCThreadState ,调用了它的 transact() 函数,IPCThreadState::self() 是线程内的单例,每一个线程都有一个 IPCThreadState,传入了 mHandle ,驱动可以根据 mHandle 来确定是哪个binder
- IPCThreadState 的 transact() 函数
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err;
// 把数据写出去
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
if ((flags & TF_ONE_WAY) == 0) {
#if 0
#endif
if (reply) {
// 等待回复
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
// ...
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
IPCThreadState::transact 函数主要有 writeTransactionData() 将数据写出去,然后 waitForResponse() 等待返回结果
接下来看一下数据是怎么写出去的
- writeTransactionData()
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
// 存储数据的数据结构
binder_transaction_data tr;
// 接下来把各种数据都赋值给 data
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
tr.offsets_size = 0;
tr.data.ptr.offsets = 0;
} else {
return (mLastError = err);
}
// 写到 mOut 中,IPCThreadState 有 mIn 和 mOut 它们的功能就是和驱动进行数据的读写
// 把数据写到驱动 先写一个 cmd 命令,
mOut.writeInt32(cmd);
// 然后再把数据写进去 这里只是先写到了 mOut 中,还没有写到驱动,后面会往驱动写
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
writeTransactionData() 函数是将数据封装成 binder_transaction_data 对象,然后通过 mOut 写到驱动(这里是还未开始写到驱动,只是存储到了 mOut中)具体写到驱动是waitForResponse () 方法执行的
接下来看一下 waitForResponse () 函数
- waitForResponse()
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
// 一个交互需要多次 所以通过 while (1) 一直交互 知道后面调用 goto finish; 才结束循环
while (1) {
// talkWithDriver() 是有两种,一种是往驱动里面写,一种是从驱动里面读取,这里是通过 mOut 往驱动里面写
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
// 通过 mIn 把指令读出来 然后根据命令来执行下面的 switch 操作
cmd = (uint32_t)mIn.readInt32();
switch (cmd) {
// BR_TRANSACTION_COMPLETE 表示驱动已经收到了请求
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
case BR_DEAD_REPLY:
err = DEAD_OBJECT;
goto finish;
case BR_FAILED_REPLY:
err = FAILED_TRANSACTION;
goto finish;
case BR_ACQUIRE_RESULT:
{
ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
const int32_t result = mIn.readInt32();
if (!acquireResult) continue;
*acquireResult = result ? NO_ERROR : INVALID_OPERATION;
}
goto finish;
case BR_REPLY:// 表示客户端已经收到服务端的返回了
{
binder_transaction_data tr;
// 返回的数据是存储到了 mIn 中,读取到 binder_transaction_data 的结构中
err = mIn.read(&tr, sizeof(tr));
ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
if (err != NO_ERROR) goto finish;
if (reply) {
if ((tr.flags & TF_STATUS_CODE) == 0) {
// 把 binder_transaction_data 里面的数据给到 reply,这样就可以从 reply 中获取到数据
reply->ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t),
freeBuffer, this);
} else {
err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
}
} else {
freeBuffer(NULL,
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), this);
continue;
}
}
goto finish;
}
}
finish:
return err;
}
- 接下来看看 talkWithDriver() 是如何写到驱动的
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read bwr;
// 如果是写到驱动 需要确定好 写的大小 缓冲区等
// 如果是读则需要确定好读的大小和读的缓冲区
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
#if defined(__ANDROID__)
// 通过 ioctl 作传输
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
}
server 端
当Zygote应用启动之后, 会将当前线程设置为 binder 线程,从而为 service AMS 等 binder 跨进程的调用提供服务,
Server 端使用 aidl 是通过注册 Service 来返回 Server 端的 binder 对象,Service 的启动原理可以看这里。
// AndroidRuntime.cpp -> app_main.cpp -> onZygoteInit()
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
// ProcessState.cpp
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
- IPCThreadState::joinThreadPool()
void IPCThreadState::joinThreadPool(bool isMain)
{
LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
// 先将BC_ENTER_LOOPER : BC_REGISTER_LOOPER 写到 mOut 中,表示把当前线程注册到binder驱动,变为binder线程
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
status_t result;
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
// do while 循环中不停的执行了 getAndExecuteCommand() 获取并且执行命令
result = getAndExecuteCommand();
// ...
} while (result != -ECONNREFUSED && result != -EBADF);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
- getAndExecuteCommand();
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
// 从驱动中读取数据
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
// 先从 mIn 中读取 cmd 命令
cmd = mIn.readInt32();
// ...
pthread_mutex_unlock(&mProcess->mThreadCountLock);
// 执行这个命令
result = executeCommand(cmd);
// ...
}
return result;
}
getAndExecuteCommand() 函数从 mIn 中获取数据并且执行命令,接下来看看怎么执行的命令
- executeCommand()
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
// 根据不同的 cmd 来执行不同的操作
switch ((uint32_t)cmd) {
case BR_TRANSACTION: // 这个命令是 Client 端转发给驱动,驱动在转发给 Server 端
{
// 先把数据从 mIn 中读取出来,放入到 binder_transaction_data 中
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
if (result != NO_ERROR) break;
// buffer 是要传输给 Server 端的数据
Parcel buffer;
buffer.ipcSetDataReference(
reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
tr.data_size,
reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(binder_size_t), freeBuffer, this);
// ...
//ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid);
// reply 是要回复给 Client 端
Parcel reply;
status_t error;
if (tr.target.ptr) {
// We only have a weak reference on the target object, so we must first try to
// safely acquire a strong reference before doing anything else with it.
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
// cookie 保存的是 binder 对象 然后调用 BBinder 的 transact 往上层传递 把 buffer 和 reply 传进去
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
}
}
if ((tr.flags & TF_ONE_WAY) == 0) {
// 传输结束之后 sendReply 返回回去;
sendReply(reply, 0);
}
}
break;
executeCommand() 获取数据并且将传进来的 binder 实体对象转换为 BBinder 并且调用其 transact() 继续上传给 Server 端的 java 层
- BBinder:: transact()
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
err = onTransact(code, data, reply, flags);
break;
}
return err;
}
上面函数继续调用了android_util_Binder.cpp 的 onTransact() 函数
- onTransact(code, data, reply, flags);
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
// 根据javaVM 拿到当前线程的 JNIEnv 拿到 JNIEnv 后可以进行 jni 调用了
JNIEnv* env = javavm_to_jnienv(mVM);
IPCThreadState* thread_state = IPCThreadState::self();
const int32_t strict_policy_before = thread_state->getStrictModePolicy();
// 调用的是 jni 的 mExecTransact() 函数,mExecTransact 调用到了 binder 对象的 onTransact() 函数
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
// ...
}
onTransact() 函数实际上是获取 JNIEnv 从而可以调用到 aidl 生成的 Stub 类的 onTransact() 函数,其内部生成对应 Server 端的接口对象,然后调用本地对应的方法,然后一次完成的 IPC 调用就结束了
@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_go: {
// 根据 code
// 先解析数据,然后转换成接口对象
data.enforceInterface(descriptor);
java.lang.String _arg0;
_arg0 = data.readString();
// 再调用Server端本地的 go() 方法
this.go(_arg0);
reply.writeNoException();
return true;
}
default: {
return super.onTransact(code, data, reply, flags);
}
}
}