我是靠谱客的博主 帅气大门,最近开发中收集的这篇文章主要介绍Android底层:通熟易懂的分析binder--3. 探究binder全流程通信之请求篇(1),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言

本系列文章我们来探究下binder全流程通信,这里的全流程既指请求binder服务和binder服务返回结果的过程;又指整个通信过程贯穿app,framework,jni,native,driver这五层。在讲解之前大家可以看下 Android底层:通熟易懂的分析binder--2. binder进程通信协议及“记录链路”结构体 这篇文章,它是本系列文章的基础。

我会把binder通信流程划分为请求回复两个阶段,每个阶段都会贯穿从app到driver这五层。下面是这个系列的所有文章:

  1. 探究binder全流程通信之请求篇
  2. 探究binder全流程通信之回复篇

binder进程通信其实就是一个c/s架构,因此用client代替请求binder服务的一端,server代替提供binder服务的一端。

本系列文章的分析都是基于client进程已经获取到了binder服务引用(BinderProxy对象)来分析的(关于如何获取binder服务引用后面的文章会提到)

本篇内容

  1. 请求从app层到framework层
  2. 请求从jni层到native层
  3. 小结
  4. 请求到达driver层
  5. 查找“目标”,拷贝数据给“目标”
  6. 发送“complete”给client
  7. “目标”处理收到的数据
  8. 请求到达server进程native层
  9. “真正”方法收到请求
  10. 请求流程总结

1.请求从app层到framework层

发生于client进程

我会从请求是如何在每层中传递的以及传递过程中请求的数据都发生了哪些变化来分析请求流程。

binder进程通信的其中一个妙处就在于调用远程(其他进程)方法就如调用本地(本进程)的方法一样,并且是面向接口调用。那我就从调用远程方法开始来作为起始点,来分析下client调用server的方法都经过了哪些坎坷的流程,最终才把参数等传递到server的方法。

先看段aidl生成的代码

public interface IXXX extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements IXXX {
private static final java.lang.String DESCRIPTOR
= "...IXXX";
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
​
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,
int flags) throws android.os.RemoteException {
switch (code) {
case TRANSACTION_methodXX: {
data.enforceInterface(descriptor);
// xxx 代表某一类型, data.readXXX代表读取参数
xxx _result = this.methodXX(data.readXXX());
reply.writeNoException();
reply.writeInt(_result);
return true;
}
}
}
​
省略代码...
​
// 对方进程使用代理类
private static class Proxy implements IXXX {
​
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
省略代码...
@Override
public xxx methodXX(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.writeStrongBinder((((cb != null)) ? (cb.asBinder()) : (null)));
// writeXXX代表与param对应的类型
_data.writeXXX(param);
mRemote.transact(Stub.TRANSACTION_methodXX, _data, _reply, 0);
_reply.readException();
// 读取返回结果
return _reply.readXXX();
} finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_methodXX = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void methodXX(param) throws android.os.RemoteException;
}

这段代码大家肯定很熟悉,其中的Stub类是server进程中的binder服务的父类,Proxy就是client进程中binder服务的引用。那我们在client进程调用server进程的methodXX方法的代码如下

serverProxy.methodXX(param),

这段代码就犹如在调用本地的一个方法,serverProxy是Proxy的一个实例(关于它是怎么生成的,后面章节会讲解到)。那我们进入methodXX中看下它的具体实现

public void methodXX(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.writeStrongBinder((((cb != null)) ? (cb.asBinder()) : (null)));
//进入阻塞状态
mRemote.transact(Stub.TRANSACTION_methodXX, _data, _reply, 0);
_reply.readException();
// 读取返回结果,这段代码先不考虑
return _reply.readXXX();
} finally {
_reply.recycle();
_data.recycle();
}
}

先初始化两个Parcel的实例 _data , _reply(存放返回的结果),把param参数写入 _data中,最终调用mRemote.transact方法,mRemote其实是BinderProxy的实例(同样关于它的生成时机也会在后续文章中讲解到)

transact方法的第一个参数是要调用方法对应的int值,这是通过接口的方式与server进行约定的,后面的参数就是 _data, _reply, flag。调用该方法会进入阻塞状态等待返回结果。

那我们在进入BinderProxy中看下transact的实现

public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
// 检查传输的数据是否超了 800 * 1024
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
​
省略代码...
​
try {
return transactNative(code, data, reply, flags);
} finally {
省略代码...
}
}

该方法中检查了传递的数据是否超了800*1024,没超则调用transactNative方法,从名字就能看出这是一个native方法。

小结

上面的请求过程是发生在app到framework层的。传递的数据由 param(各种参数,参数可以是基本类型,也可以是Binder) ----> code(方法),data(参数放入Parcel),reply(存储返回结果)

2.请求从jni层到native层

发生于cleint进程

2.1 transactNative的对应方法

进入jni层的android_util_Binder.cpp文件,transactNative方法最终对应的是(void*)android_os_BinderProxy_transact方法,那我们来看下它

​static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
// 把java层的Parcel对象转换为c++对象
Parcel* data = parcelForJavaObject(env, dataObj);
if (data == NULL) {
return JNI_FALSE;
}
Parcel* reply = parcelForJavaObject(env, replyObj);
if (reply == NULL && replyObj != NULL) {
return JNI_FALSE;
}
​
// 获取java层Binderproxy对象对应native层的IBinder实例
IBinder* target = getBPNativeData(env, obj)->mObject.get();
if (target == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
return JNI_FALSE;
}
省略代码...
// 最终调用点
status_t err = target->transact(code, *data, reply, flags);
​
省略代码...
return JNI_FALSE;
}

该方法中主要做了几件事情:

把java层的Parcel对象转为native层的对象

根据BindeProxy中的mObject属性找到BpBinder对象,mObject能找到BpBinder是因为BinderProxy在被jni层代码初始化时,会传递一个long值给mObject,这个long值可以理解为是BpBinder的一个指针

最终调用BpBinder的transact(code, *data, reply, flags)方法

2.2 BpBinder

那来看下BpBinder的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) {
​
省略代码...
// 进入IPCThreadState的transact方法
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
​
return status;
}
​
return DEAD_OBJECT;
}

上面方法最终调用了IPCThreadState的transact方法,注意这时候的transact方法多了一个参数 mHandle ,它的作用用来查找binder服务。

2.3 IPCThreadState

2.3.1 transact

进入transact方法,看下它的代码

status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
省略代码...
// 把数据写入binder_transaction_data中,
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
​
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
​
// 同步调用,等待返回结果
if ((flags & TF_ONE_WAY) == 0) {
省略代码...
​
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
​
省略代码...
} else {
// 异步调用,不需要返回结果,
err = waitForResponse(NULL, NULL);
}
​
return err;
}

该方法中,先把数据(BC_TRANSACTION,参数,code值,handle等)写入binder_transaction_data中,很重要一点这时候的数据多了一个BC_TRANSACTION(Android底层:通熟易懂的分析binder--2. binder进程通信协议及“记录链路”结构体 里面介绍过)它是传递给driver层的cmd。

TF_ONE_WAY代表异步调用,否则同步,不管是异步还是同步调用,最后都调用waitForResponse方法,只不过传递的参数不一样,异步调用所有参数都是null,null

2.3.2 waitForResponse

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
​
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
​
cmd = (uint32_t)mIn.readInt32();
​
switch (cmd) {
// driver层处理完毕 BC_TRANSACTION后返回BR_TRANSACTION_COMPLETE命令
case BR_TRANSACTION_COMPLETE:
// !reply && !acquireResult 异步处理不需要结果,直接结束
if (!reply && !acquireResult) goto finish;
break;
​
省略代码...
​
// 接收返回结果的命令
case BR_REPLY:
{
binder_transaction_data tr;
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) {
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;
​
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
​
finish:
if (err != NO_ERROR) {
if (acquireResult) *acquireResult = err;
if (reply) reply->setError(err);
mLastError = err;
}
​
return err;
}

该方法中有一个循环,在这个循环内会调用talkWithDriver方法(该方法已在 Android底层:通熟易懂分析binder:1.binder准备工作 的进程与driver层通信中介绍过),talkWithDriver方法中最终会通过

ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0

把数据发送给driver层,其中的cmd是BINDER_WRITE_READ,数据被放入binder_write_read中,mProcess->mDriverFD是打开binder驱动时返回的一个值。

小结

请求从jni层到native层,经历了jni层根据BinderProxy查找BpBinder---> BpBinder的transact方法 ---> IPCThreadState的transact方法 ---> IPCThreadState的waitForResponse方法, 当前线程进入中断状态。

数据由 code, data(参数), reply ---> handle, code, data, reply --->BC_TRANSACTION,handle, code, data ---> cmd: BINDER_WRITE_READ , BC_TRANSACTION,handle, code, data。在每层都会增加本层的协议和字段。

3.小结

到这需要总结下以上的流程,请求是如何一步一步从app到达native层的,传递的数据(主要是参数)都发生了哪些变化。

请求从app到native层的过程: 1.从 serverProxy.methodXX(param) 开始 。(app层)

2.进入mRemote.transact(code, data, reply, flag)方法 (mRemote是BinderProxy对象) 。(进入framework层)

3.BinderProxy实例的transact方法最终调用transactNative方法。

4.transactNative方法最终调用android_os_BinderProxy_transact方法,该方法中通过binderProxy的mObject找到BpBinder实例。(进入jni层)

5.进入BpBinder实例的transact方法,该方法中调用IPCThreadState的transact方法。(进入native层)

6.IPCThreadState的transact方法调用它的waitForResponse,该方法中先调用talkWithDriver方法把数据(参数,code等)传递给driver层,进而等待driver层返回数据。(native层)

请求数据从app到native层的变化: 1.param(调用方法的参数有基本类型,String,IBinder等)(app层)

2.code(调用方法的int值),data(Parcel类型,方法参数),reply(Parcel类型,存储返回值),flag。(framework层)

3.handle(用来查找binder服务),code,data,reply,flag。(native层)

4.BC_TRANSACTION,handle, code, data放入binder_transaction_data结构体中,最终把它写入binder_write_read结构体的write中 (native传数据到driver层)

这时候当前的线程进入中断状态,进而导致serverProxy.methodXX(param)调用处也进入中断状态(因为ioctl是进行系统调用,系统调用陷入内核态),切换到内核线程执行。稍后我们还会回到talkWithDriver方法。

记住waitForResponse, talkWithDriver方法,因为它们等待着返回数据。

请求数据经过ioctl方法后最终进入driver层,那我们进入driver层来分析。

4.请求到达driver层

我使用“driver层xx代理”来代表在driver层中记录的上层进程的信息(binder_proc,binder_thread等)的总称,xx是上层进程的名字(实在没想出一个好名字)。“driver层client代理”与client进程是对应关系,同理“driver层server代理”与server进程是对应关系。

driver层是binder进程通信是最复杂最关键的一层。比如会出现“driver层client代理”与“driver层server代理”并行执行的情况;也会出现一个处于等待,一个处于执行的情况,因此我会在相应标题后面标明当前是在哪个“driver层xx代理”执行,来标明当前是在哪执行。

我用clientInvokeStack来存放“driver层client代理”方法的调用,同理用serverInvokeStack存放“driver层server代理”方法的调用,这样有利于我们分析问题。

4.1 binder_ioctl(driver层client代理)

native层通过调用ioctl方法后,driver层的binder_ioctl(该方法入clientInvokeStack)开始执行,简单来看下它的相关代码:

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret;
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
​
省略代码...
​
// 查找上层binder线程对应的binder_thread,若不存在则创建
thread = binder_get_thread(proc);
if (thread == NULL) {
ret = -ENOMEM;
goto err;
}
​
switch (cmd) {
// BINDER_WRITE_READ类型cmd
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
​
省略代码...
​
}
省略代码...
​
}

上面代码主要做了以下几件事: 1.查找到binder_proc(有了它才能继续执行) ,arg可以理解为上层数据空间的索引

2.查找并创建binder_thread(记录上层binder线程状态)

3.当前的cmd是BINDER_WRITE_READ,因此进入binder_ioctl_write_read方法(该方法入栈)

clientInvokeStac中的方法有:binder_ioctl_write_read,binder_ioctl。(排在最前的是栈顶)

4.2 binder_ioctl_write_read(driver层client代理)

来看下这个方法代码,同理只把相关代码展示出来

static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
​
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto out;
}
​
// 把上层的数据拷贝到内核空间(数据类型binder_write_read)
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
​
// 若上层传递了数据,则进入读取上层数据流程
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
trace_binder_write_done(ret);
if (ret < 0) {
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
​
省略代码...
}

上面代码主要做了以下几件事:

1.拷贝上层的数据到binder_write_read结构体中。

2.若上层传递了数据则进入binder_thread_write方法,请求肯定是有数据的,因此该方法入栈。

clientInvokeStac中的方法有:binder_thread_write,binder_ioctl_write_read,binder_ioctl。

4.3 binder_ioctl_write(driver层client代理)

binder_ioctl_write才是真正的核心方法,这个方法里面读取上层的命令,数据。进而根据命令执行不同的操作,那我们来看下请求部分的操作代码

static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
//上层传递的命令以 BC_ 开头
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
// 类似于上层数据指针
void __user *ptr = buffer + *consumed;
// 上层数据的结束位置
void __user *end = buffer + size;
​
// ptr < end 代表上层数据还没拷贝完毕继续拷贝, BR_OK代表还没把信息返回给上层
while (ptr < end && thread->return_error == BR_OK) {
// 拷贝上层命令
if (get_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
// 数据指针移动 uint32_t
ptr += sizeof(uint32_t);
if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
binder_stats.bc[_IOC_NR(cmd)]++;
proc->stats.bc[_IOC_NR(cmd)]++;
thread->stats.bc[_IOC_NR(cmd)]++;
}
switch (cmd) {
​
省略代码...
​
// 请求的cmd是BC_TRANSACTION
case BC_TRANSACTION:
// 返回数据的cmd是BC_REPLY
case BC_REPLY: {
struct binder_transaction_data tr;
​
// 拷贝 binder_transaction_data,这个数据结构是不是很眼熟,上层就是把数据赋值给了它
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
// 指针位置移动
ptr += sizeof(tr);
// 进入 binder_transaction 方法
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
​
省略代码...
​
default:
pr_err("%d:%d unknown command %dn",
proc->pid, thread->pid, cmd);
return -EINVAL;
}
*consumed = ptr - buffer;
}
return 0;
}

上面代码做了以下几件事:

1.若上层数据没有拷贝完,继续拷贝

2.get_user(cmd, (uint32_t __user *)ptr) 拷贝cmd,cmd是上层传递给driver层的命令以BC开头

3.根据cmd进入不同的case,请求的cmd是BC_TRANSACTION,进入这个case

4.copy_from_user(&tr, ptr, sizeof(tr)),拷贝数据到binder_transaction_data中,这个结构体是不是很眼熟,在native层会把传递给driver层的数据放入这个结构体中,最终进入binder_transaction方法中(该方法入栈)。

clientInvokeStac中的方法有:binder_transaction, binder_thread_write,binder_ioctl_write_read,binder_ioctl。

5.查找“目标”,拷贝数据给“目标”

发生于“driver层client代理”

binder_transaction方法主要是处理binder进程通信请求和回复的关键核心方法。这个方法主要做了三件事情:查找“目标”;拷贝数据,构造binder_transaction;把binder_transactin交给“目标”。

这里的“目标”在请求流程中指“driver层server代理”及它包含的binder_proc,binder_thread,binder_node等。

5.1 查找“目标”

开始查找“目标”,把“目标”查找到后才能进入下个环节,否则停止交互流程,我们一段一段的分析,

​static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
// t里面的数据会存放到目标binder_proc或binder_thread的队列中
struct binder_transaction *t;
// tcomplete用来告诉client数据已经成功的交给了目标
struct binder_work *tcomplete;
// 用来对binder服务,binder服务引用做转换
binder_size_t *offp, *off_end;
binder_size_t off_min;
​
// 目标
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
​
// 代表回复的数据
struct binder_transaction *in_reply_to = NULL;
​
省略代码...
​
// 回复时执行这
if (reply) {
省略代码...
} else {
// 请求时执行这
if (tr->target.handle) {
struct binder_ref *ref;
// 找到binder_ref
ref = binder_get_ref(proc, tr->target.handle);
if (ref == NULL) {
binder_user_error("%d:%d got transaction to invalid handlen",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_invalid_target_handle;
}
target_node = ref->node;
} else {
// 没handle时代表请求的是serviceManager
target_node = binder_context_mgr_node;
if (target_node == NULL) {
return_error = BR_DEAD_REPLY;
goto err_no_context_mgr_node;
}
}
// 根据target_node找到target_proc
target_proc = target_node->proc;
if (target_proc == NULL) {
return_error = BR_DEAD_REPLY;
goto err_dead_binder;
}
if (security_binder_transaction(proc->tsk,
target_proc->tsk) < 0) {
return_error = BR_FAILED_REPLY;
goto err_invalid_target_handle;
}
​
// 同步请求
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
struct binder_transaction *tmp;
​
// 事务栈
tmp = thread->transaction_stack;
if (tmp->to_thread != thread) {
binder_user_error("%d:%d got new transaction with bad transaction stack, transaction %d has target %d:%dn",
proc->pid, thread->pid, tmp->debug_id,
tmp->to_proc ? tmp->to_proc->pid : 0,
tmp->to_thread ?
tmp->to_thread->pid : 0);
return_error = BR_FAILED_REPLY;
goto err_bad_call_stack;
}
​
// 找target_thread
while (tmp) {
if (tmp->from && tmp->from->proc == target_proc)
target_thread = tmp->from;
tmp = tmp->from_parent;
}
}
}
​
// 找到target_thread
if (target_thread) {
e->to_thread = target_thread->pid;
target_list = &target_thread->todo;
target_wait = &target_thread->wait;
} else {
// 否则使用 进程的队列
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}
​
省略代码...
}

先介绍下定义的几个变量:

binder_transaction *t:“driver层XX代理”之间交互的结构体,会存储上层的data,code,target_node等,最终会放入目标binder_proc或binder_thread的todo队列中。

binder_work *tcomplete:作用告诉client进程数据已经成功的交给了目标。

binder_size_t offp, off_end,binder_size_t off_min:在对方法的参数是的binder服务(Binder)或binder服务引用(BBinder)进行转换时需要用到。

以target开头的变量代表“目标”相关信息。

查找“目标”的流程

根据上层传递的handle(若handle为0则代表查找的是serviceManager),在当前的binder_proc的refs红黑树中找到,binder_ref

根据binder_ref找到目标binder_node,进而找到目标binder_proc,binder_thread。

若目标binder_thread找到了,则使用它的事务队列来存放事务t;否则使用目标binder_proc的事务队列存放事务t

5.2 拷贝数据,构造binder_transaction

既然“目标”找到了,那就需要把上层传递的数据(code,data)拷贝到内核空间,进而构造一个binder_transaction结构体来存放这些数据,来分析下拷贝和构造流程,还依然是binder_transaction方法,只显示了相关代码

static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
// t里面的数据会存放到目标binder_proc或binder_thread的队列中
struct binder_transaction *t;
// tcomplete用来告诉client数据已经成功的交给了目标
struct binder_work *tcomplete;
// 用来对binder服务,binder服务引用做转换
binder_size_t *offp, *off_end;
binder_size_t off_min;
​
// 目标
struct binder_proc *target_proc;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
struct list_head *target_list;
wait_queue_head_t *target_wait;
​
省略查找“目标”代码...
​
// 为t分配空间
t = kzalloc(sizeof(*t), GFP_KERNEL);
if (t == NULL) {
return_error = BR_FAILED_REPLY;
goto err_alloc_t_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION);
​
// 分配空间
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
if (tcomplete == NULL) {
return_error = BR_FAILED_REPLY;
goto err_alloc_tcomplete_failed;
}
binder_stats_created(BINDER_STAT_TRANSACTION_COMPLETE);
​
省略代码...
​
// 不是回复并且是同步,则给from赋值
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;
else
// 否则不需要from信息
t->from = NULL;
​
省略代码...
​
// 为buffer分配空间,主要是用来存放方法参数,target_node
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
if (t->buffer == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_alloc_buf_failed;
}
​
// 对buffer部分信息赋值
t->buffer->allow_user_free = 0;
t->buffer->debug_id = t->debug_id;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
trace_binder_transaction_alloc_buf(t->buffer);
if (target_node)
binder_inc_node(target_node, 1, 0, NULL);
​
offp = (binder_size_t *)(t->buffer->data +
ALIGN(tr->data_size, sizeof(void *)));
​
// 拷贝上层方法参数信息,
if (copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)
tr->data.ptr.buffer, tr->data_size)) {
binder_user_error("%d:%d got transaction with invalid data ptrn",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
​
// 拷贝参数为binder服务或服务引用信息,为binder服务,binder服务引用之间的转换做准备
if (copy_from_user(offp, (const void __user *)(uintptr_t)
tr->data.ptr.offsets, tr->offsets_size)) {
binder_user_error("%d:%d got transaction with invalid offsets ptrn",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
​
省略代码...
​
off_end = (void *)offp + tr->offsets_size;
off_min = 0;
​
// 读取参数是binder服务或binder服务引用
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
​
if (*offp > t->buffer->data_size - sizeof(*fp) ||
*offp < off_min ||
t->buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(u32))) {
binder_user_error("%d:%d got transaction with invalid offset, %lld (min %lld, max %lld)n",
proc->pid, thread->pid, (u64)*offp,
(u64)off_min,
(u64)(t->buffer->data_size -
sizeof(*fp)));
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
​
// binder扁平化信息
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
off_min = *offp + sizeof(struct flat_binder_object);
switch (fp->type) {
​
// 对binder服务进行判断转换
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
struct binder_node *node = binder_get_node(proc, fp->binder);
​
if (node == NULL) {
node = binder_new_node(proc, fp->binder, fp->cookie);
if (node == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_new_node_failed;
}
node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
}
​
省略代码...
​
// 查找ref,不存在则创建
ref = binder_get_ref_for_node(target_proc, node);
if (ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
// 修改fp的值为handle类型
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
// 把desc赋值给handle
fp->handle = ref->desc;
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
​
省略代码...
​
} break;
​
// 对handle类型binder服务引用进行转换
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
// 根据handle找到当前binder_proc中的binder_ref
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
​
if (ref == NULL) {
binder_user_error("%d:%d got transaction with invalid handle, %dn",
proc->pid,
thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
if (security_binder_transfer_binder(proc->tsk,
target_proc->tsk)) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
// 若ref的binder_node指向的binder_proc与目标proc是一样的
if (ref->node->proc == target_proc) {
// 则把binder服务引用转换为binder服务
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER;
else
fp->type = BINDER_TYPE_WEAK_BINDER;
fp->binder = ref->node->ptr;
fp->cookie = ref->node->cookie;
binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
trace_binder_transaction_ref_to_node(t, ref);
binder_debug(BINDER_DEBUG_TRANSACTION,
"
ref %d desc %d -> node %d u%016llxn",
ref->debug_id, ref->desc, ref->node->debug_id,
(u64)ref->node->ptr);
} else {
// 不是同一个binder_proc,则在目标binder_proc中创建binder_ref
struct binder_ref *new_ref;
​
new_ref = binder_get_ref_for_node(target_proc, ref->node);
if (new_ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
fp->handle = new_ref->desc;
binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
trace_binder_transaction_ref_to_ref(t, ref,
new_ref);
​
}
} break;
​
case BINDER_TYPE_FD: {
​
省略代码...
​
} break;
​
default:
省略代码...
}
}
if (reply) {
​
省略代码...
​
} else if (!(t->flags & TF_ONE_WAY)) {
// 同步的请求
BUG_ON(t->buffer->async_transaction != 0);
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
// 在 thread 的事务栈的最顶端存放当前的事务,回复时候使用
thread->transaction_stack = t;
} else {
BUG_ON(target_node == NULL);
BUG_ON(t->buffer->async_transaction != 1);
// 异步,添加到list中
if (target_node->has_async_transaction) {
target_list = &target_node->async_todo;
target_wait = NULL;
} else
target_node->has_async_transaction = 1;
}
省略代码...
}

这部分代码相对比较长,主要做了下面几件事情:

1.为变量t(binder_transaction),tcomplete(binder_work)分配空间。

2.为t的buffer分配空间,buffer主要用来存放参数,target_node以及等。

3.调用copy_from_user方法把上层的参数信息拷贝到t的buffer的data中

4.调用copy_from_user方法拷贝参数是binder服务(Binder对象)或binder引用(BpBinder对象)的位置信息

5.遍历所有参数类型是binder服务或binder服务引用,对它们进行转换。

6.对同步请求和异步请求分别处理,若为同步请求对t的need_reply,thread->transaction_stack(用作回复数据)做处理。

binder服务或binder服务引用转换规则 flat_binder_object

fp = (struct flat_binder_object *)(t->buffer->data + *offp);

执行上面代码从Parcel中把 flat_binder_object (主要存放Binder或BpBinder)读出来。 flat_binder_object的type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER,代表是Binder。

flat_binder_object的type为BINDER_TYPE_HANDLE或BINDER_TYPE_WEAK_HANDLE,代表是BpBInder。

转换规则: 1.type是Binder,则调用binder_get_node方法从当前binder_proc中取binder_node,若不存在则创建,并且把它插入当前binder_proc的nodes红黑树中。调用binder_get_ref_for_node(target_proc, node)在目标binder_proc中查找binder_ref,若不存在则创建并插入目标binder_proc的refs红黑树中,并且把最终的binder_ref的desc赋值给flat_binder_object的handle。(Binder转换为BpBinder)

2.type是BpBinder,则调用binder_get_ref(proc, fp->handle)查找binder_ref。若当前binder_proc与目标binder_proc相同,则把BpBinder转为Binder;否则,在目标binder_proc创建binder_ref并且插到它的refs红黑树中,并且把最终的binder_ref的desc赋值给flat_binder_object的handle,BpBinder转为BpBinder。(BpBinder转换为Binder或BpBinder)

为回复做准备 若当前的请求是同步,则会执行

t->need_reply = 1;
t->from_parent = thread->transaction_stack;
// 在 thread 的事务栈的最顶端存放当前的事务,回复时候使用
thread->transaction_stack = t;

记住它,在回复流程时,会用到。

5.3 把binder_transaction交给“目标”

看下代码,代码依然在binder_transaction方法中

static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
省略代码...
​
// 赋值type
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
​
// 通知上层发送BR_TRANSACTION_COMPLETE 信息
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
// 目标是处于等待状态,则去唤醒
if (target_wait)
wake_up_interruptible(target_wait);
return;
省略代码...
}

上面代码主要做了两件事:

给t(binder_transaction)的work.type赋值BINDER_WORK_TRANSACTION并且把最终的binder_work加入"目标“binder_proc或binder_thread的todo队列中。driver层内binde_proc或binder_thread之间通信时的协议是binder_work,协议的type值是以BINDER_WORK开头的,BINDER_WORK_TRANSACTION用于请求或回复环节。最终数据成功的交给了“目标”。

给tcomplete的type赋值BINDER_WORK_TRANSACTION_COMPLETE,并且把最终的binder_work加入到当前binder_thread的todo队列中。BINDER_WORK_TRANSACTION_COMPLETE主要用来告诉上层请求或回复数据已经成功的交给了“目标”。

至此binder_transaction和binder_thread_write方法执行完毕,它们执行出栈操作。

clientInvokeStac中的方法有:binder_ioctl_write_read,binder_ioctl。

接下来会并行着执行两个任务:1. “目标”处理收到的client请求数据(“driver层server代理”);2. 给client回复"complete"信息(“driver层client代理”)。

最后

以上就是帅气大门为你收集整理的Android底层:通熟易懂的分析binder--3. 探究binder全流程通信之请求篇(1)的全部内容,希望文章能够帮你解决Android底层:通熟易懂的分析binder--3. 探究binder全流程通信之请求篇(1)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部