用户空间与驱动之间的数据交换
每个binder线程维护两个缓冲区 mOut 和 mIn,用于用户空间与驱动之间的数据交换。mOut 维护用户空间向驱动写入的数据,mIn 维护用户空间接受驱动写入的数据。
mOut 和 mIn 是 Parcel 类型,内部存入的数据为 cmd(通信协议)、binder_transaction_data(通信数据)。
通信数据内容如下:
struct binder_transaction_data {
// 只用于 bcTRANSACTION(客户端->驱动) and brTRANSACTION(驱动->服务端),表明通信的目标
union {
size_t handle; /* binder_ref 的句柄值 desc,bcTRANSACTION 时有效 */
void *ptr; /* 服务端引用计数 weakref_type 的地址,brTRANSACTION 时有效 */
} target;
void *cookie; /* 服务端 BBinder 对象的地址,brTRANSACTION 时有效 */
unsigned int code; /* 通信协议码 */
/* General information about the transaction. */
unsigned int flags; // oneway等
pid_t sender_pid;
uid_t sender_euid;
size_t data_size; /* 通信数据的字节大小 */
size_t offsets_size; /* flat_binder_object 偏移数组的字节大小 */
// 如果传输的是服务的通信数据,则要保存数据的地址和数组中 flat_binder_object 偏移数组的地址
union {
struct {
/* 通信数据的地址 */
const void *buffer;
/* flat_binder_object 偏移数组的地址 */
const void *offsets;
} ptr;
uint8_t buf[8];
} data;
};
数据类型 binder_write_read 描述两个缓冲区(数据大小、地址)和驱动对其的消费情况。用户空间在使用系统调用 ioctl() 时传入binder_write_read对象,驱动根据 write_size 判断是否需要处理用户空间写入数据的数据(请求)和根据 read_size 判断用户空间是否接受驱动写入数据(响应)。驱动在处理完数据(write_buffer,read_buffer)后修改这个对象的 write_consumed 和 read_consumed 字段,并写回用户空间。用户空间以此决定是否清空之前写入的数据、处理驱动写入的数据。
// kernel, drivers/staging/android/binder.h
struct binder_write_read {
signed long write_size; /* 表示用户空间已写入的字节数,驱动以此判断是否需要读取 */
signed long write_consumed; /* 表示驱动已消费的字节数,用户空间以此判断是否清空缓冲区 */
unsigned long write_buffer; /* 表示用户空间写入的缓冲区地址*/
signed long read_size; /* 表示用户空间可以读入的字节数,驱动以此判断是否需要写入数据 */
signed long read_consumed; /* 表示驱动已写入的字节数,用户空间以此判断是否有数据要处理 */
unsigned long read_buffer; /* 表示驱动写入的缓冲区的地址*/
};
用户空间流程
服务端调用链:
joinThreadPool()
getAndExecuteCommand()
talkWithDriver()
executeCommand()
// case BR_TRANSACTION:
// transact() -> onTransact() 服务端响应,调用具体的业务方法
// sendReply(); 服务端把结果返回客户端
// writeTransactionData()
// waitForResponse()
客户端调用链
transact() // 客户端调用代理对象的业务方法进入这里
writeTransactionData()
waitForResponse()
talkWithDriver()
// case BR_REPLY: // handle response data;
// ...
把请求数据写入缓冲区 mOut;
- 创建 binder_transaction_data 对象;
- 把目标(handle)、flags、服务方法code及参数(data)等写入 binder_transaction_data 对象;
- 把通信协议(cmd)和通信数据(binder_transaction_data)写入 mOut 缓冲区;
// IPCThreadState.cpp
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;
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle; // binder_ref 的句柄值 desc
tr.code = code; // 自定义的服务code,对应具体的方法
tr.flags = binderFlags; // one_way 等
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck(); // data 为服务方法的参数
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(); // binder对象(flat_binder_object)的偏移数组
}
...
// 通信协议和通信数据写入 mOut 缓冲区
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
与驱动交换数据
- 创建 transaction_write_binder 对象;
- 通过系统调用传入驱动;
- 根据驱动修改后的 transaction_write_binder 对象,清空 mOut 缓冲区、更新 mInt 中的 dataSize 和 dataPosition 从而在后面处理驱动返回的数据;
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
if (mProcess->mDriverFD < 0) {
return -EBADF;
}
binder_write_read bwr;
// dataPosition 是读指针位置,这里表示已经读完驱动返回的数据了;需要再接受驱动的数据
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// mIn 缓冲区中的数据还没有处理完并且请求读取下一次数据,这时不写入数据
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
// 描述写缓存信息
bwr.write_size = outAvail; // 表示向驱动写入数据的大小,等于 0 表示不向写入数据
bwr.write_buffer = (uintptr_t)mOut.data(); // 写入数据的地址
// 描述读缓冲信息
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity(); // read_size 为 mIn 最大容量
bwr.read_buffer = (uintptr_t)mIn.data(); // 地址为 mIn 中的 data 地址
} else { // 不读入时,read_size 置为 0,表示本次不接受驱动返回数据
bwr.read_size = 0;
bwr.read_buffer = 0;
}
// Return immediately if there is nothing to do.
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
// 初始化 write_consumed,read_consumed,这两个值之后由驱动修改
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
// 通过系统调用于驱动通信,驱动处理后修改 binder_write_read 对象并写回用户空间
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
...
} while (err == -EINTR);
if (err >= NO_ERROR) {
// 驱动消费了数据
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
...
else { // 驱动消费了所有用户空间写入的数据, mOut 的 dataSize 置为 0
mOut.setDataSize(0);
processPostWriteDerefs();
}
}
// 驱动返回了数据,设置 mIn 的 dataSize 和 dataPosition(读写指针位置),
// 在 waitForResponse 中处理驱动返回数据
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
处理驱动返回的数据 mIn
客户端
- 从缓冲区 mIn 中读取数据到 reply 中,作为代理端业务方法的返回值;
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(); // 从缓冲区 mIn 读出协议码,根据协议码做不同的处理
switch (cmd) {
...
case BR_TRANSACTION_COMPLETE: // binder 驱动收到了 请求数据
if (!reply && !acquireResult) goto finish;
break; // 继续等待服务端返回
...
case BR_REPLY: // 客户端收到了返回数据
{
binder_transaction_data tr;
err = mIn.read(&tr, sizeof(tr)); // 从缓冲区 mIn 读数据到 tr 中
if (err != NO_ERROR) goto finish;
if (reply) { // 如果服务方法有返回值
if ((tr.flags & TF_STATUS_CODE) == 0) {
// 将 tr.data.ptr.buffer, tr.data_size, tr.data.ptr.offsets, tr.offsets_size
// 写入返回数据 reply 中
// freeBuffer 是函数对象,释放缓存
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);
} else {
// 错误处理、释放缓存
...
}
} else {
// 释放缓存
...
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;
logExtendedError();
}
return err;
}
服务端
- 从缓冲区 mIn 中拷贝数据到 buffer, 作为业务方法的参数;
- 调用业务方法前增加强引用计数;
- 调用业务方法,并把结果写入 reply 中;
- 减少引用计数;
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
...
// 增减引用计数相关
case BR_ACQUIRE:
case BR_RELEASE:
case BR_INCREFS:
case BR_DECREFS:
case BR_ATTEMPT_ACQUIRE:
break;
// Binder 死亡通知相关
case BR_DEAD_BINDER:
case BR_CLEAR_DEATH_NOTIFICATION_DONE:
break;
case BR_TRANSACTION_SEC_CTX:
case BR_TRANSACTION: // 服务端收到驱动转发的客户端请求数据
{
binder_transaction_data_secctx tr_secctx;
binder_transaction_data& tr = tr_secctx.transaction_data;
if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
result = mIn.read(&tr_secctx, sizeof(tr_secctx));
} else {
result = mIn.read(&tr, sizeof(tr)); // 从缓冲区 mIn 读数据到 tr 中
tr_secctx.secctx = 0;
}
...
// tr 中的数据写入 buffer, 作为服务端服务方法的参数,并释放缓存
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);
...
Parcel reply;
status_t error;
if (tr.target.ptr) {
// 调用服务方法前,先增加强引用
if (reinterpret_cast<RefBase::weakref_type*>(
tr.target.ptr)->attemptIncStrong(this)) {
// cookie 为 BBinder 对象地址,类型转换后调用 BBinder::transact() -> onTransact();
// 服务中复写 onTransact(), 最终调用具体的业务方法,返回数据写入 reply
error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
// 服务完成后,减少引用计数
reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
} else {
...
}
...
}
break;
...
}
...
return result;
}
驱动流程
用户空间通过系统调用 ioctl() 进入内核空间,对于 BINDER_WRITE_READ 类型的调用,在 binder_ioctl_write_read() 函数中处理。
- 首先把 binder_write_read 对象copy到内核空间;
- 其次,根据 write_size 和 read_size 处理用户空间的写和读请求;
- 最后,再修改 binder_write_read 后,写回用户空间;
binder_ioctl()
binder_ioctl_write_read() // case BINDER_WRITE_READ:
copy_from_user() // 把 binder_write_read 对象从用户空间copy到内核空间
binder_thread_write() // 处理用户空间写入的数据
binder_transaction() // 生成 binder_work 和 binder_transaction,写入目标线程的任务队列
binder_thread_read() // 从任务队列中取出任务生成 binder_transaction_data,写入用户空间的缓冲区 mIn
copy_to_user() // 把 修改后的 binder_write_read 对象写回用户空间
binder_ioctl_write_read
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;
...
// 把 binder_write_read 对象从用户空间copy到内核空间
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
// 用户空间有写入数据,binder_thread_write 处理
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
if (ret < 0) { // 错误处理,未消费数据
bwr.read_consumed = 0;
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
// 用户空间可以接受数据,binder_thread_read 处理
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
binder_inner_proc_lock(proc);
// 唤醒线程
if (!binder_worklist_empty_ilocked(&proc->todo))
binder_wakeup_proc_ilocked(proc);
binder_inner_proc_unlock(proc);
if (ret < 0) { // 错误处理
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
// 修改后的 binder_write_read 写回用户空间
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
out:
return ret;
}
binder_thread_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)
{
uint32_t cmd;
struct binder_context *context = proc->context;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer; // write_buffer 写入数据地址
void __user *ptr = buffer + *consumed; // write_sonsumed 已消费字节数,ptr 读指针
void __user *end = buffer + size;
while (ptr < end && thread->return_error.cmd == BR_OK) {
int ret;
if (get_user(cmd, (uint32_t __user *)ptr)) // 从用户空间读取通信协议码cmd
return -EFAULT;
ptr += sizeof(uint32_t); // 更新读指针
...
switch (cmd) {
// 引用计数相关
case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS:
case BC_INCREFS_DONE:
case BC_ACQUIRE_DONE:
case BC_ATTEMPT_ACQUIRE:
case BC_ACQUIRE_RESULT:
case BC_FREE_BUFFER:
case BC_TRANSACTION_SG:
case BC_REPLY_SG:
// 用户空间向驱动写入的请求或响应数据
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
// // 从用户空间读取通信数据 binder_transaction_data,在 binder_transaction 处理
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr,
cmd == BC_REPLY, 0);
break;
}
// 服务端 Looper 相关
case BC_REGISTER_LOOPER:
case BC_ENTER_LOOPER:
case BC_EXIT_LOOPER:
// 死亡通知相关
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION:
case BC_DEAD_BINDER_DONE:;
*consumed = ptr - buffer; // 修改已消费写缓存数据大小,之后用户空间根据此清空写缓存 mOut
}
return 0;
}
binder_transaction
创建2个跨进程通信事务:BINDER_WORK_TRANSACTION, 插入目标线程,BINDER_WORK_TRANSACTION_COMPLETE,返回当前线程。
- 获取目标进程、线程信息;查找 binder_ref, binder_node;
- 生成跨进程通信数据 binder_transaction;
- 设置 binder_work 类型:目标线程和返回当前线程;
- 在目标进程的内存映射缓冲区分配内存,从发起进程的用户空间拷贝数据到目标进程的内存映射缓冲区;
- 把上述2个事务插入对应线程的目标队列,并唤醒目标线程。
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply,
binder_size_t extra_buffers_size)
{
int ret;
struct binder_transaction *t; // 跨进程通信数据
struct binder_work *w; //
struct binder_work *tcomplete;
...
// 目标进程、线程和 binder 实体对象
struct binder_proc *target_proc = NULL;
struct binder_thread *target_thread = NULL;
struct binder_node *target_node = NULL;
...
const void __user *user_buffer = (const void __user *)
(uintptr_t)tr->data.ptr.buffer;
...
// 获取目标线程、进程信息
if (reply) { // BC_REPLY 服务端响应数据
binder_inner_proc_lock(proc);
...
thread->transaction_stack = in_reply_to->to_parent;
binder_inner_proc_unlock(proc);
target_thread = binder_get_txn_from_and_acq_inner(in_reply_to);
...
binder_inner_proc_unlock(target_thread->proc);
} else { // BC_TRANSACTION 客户端请求数据
// 查找 binder_ref, binder_node
if (tr->target.handle) {
struct binder_ref *ref;
// 之后要处理服务端响应数据,所以要确保 binder_ref 有强引用,不被回收
binder_proc_lock(proc);
// 通过 handle 在 binder_proc 的红黑树中查找 binder_ref,
// true 表示同时对 binder_ref 增加强引用计数
ref = binder_get_ref_olocked(proc, tr->target.handle,
true);
// 通过 binder_ref 查找 binder_node
if (ref) {
target_node = binder_get_node_refs_for_txn(
ref->node, &target_proc,
&return_error);
}
binder_proc_unlock(proc);
}
...
}
// 为 binder_transaction *t 分配内存
t = kzalloc(sizeof(*t), GFP_KERNEL);
// ...
// 为 binder_work *tcomplete 分配内存,// BINDER_WORK_TRANSACTION_COMPLETE
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
// ...
// 填充跨进程通信数据 binder_transaction
t->start_time = t_start_time;
if (!reply && !(tr->flags & TF_ONE_WAY)) // BC_TRANSACTION, 非oneway-同步调用
t->from = thread;
else
t->from = NULL;
// 发起端信息
t->from_pid = proc->pid;
t->from_tid = thread->pid;
t->sender_euid = task_euid(proc->tsk);
// 目的端信息
t->to_proc = target_proc;
t->to_thread = target_thread;
// 通信协议码
t->code = tr->code;
t->flags = tr->flags;
t->is_nested = is_nested;
// 设置目的线程优先级
if (!(t->flags & TF_ONE_WAY) &&
binder_supported_policy(current->policy)) {
/* Inherit supported policies for synchronous transactions */
t->priority.sched_policy = current->policy;
t->priority.prio = current->normal_prio;
} else {
/* Otherwise, fall back to the default priority */
t->priority = target_proc->default_priority;
}
...
// 在目标进程内存映射缓冲区分配内存
t->buffer = binder_alloc_new_buf(&target_proc->alloc, tr->data_size,
tr->offsets_size, extra_buffers_size,
!reply && (t->flags & TF_ONE_WAY), current->tgid);
...
t->buffer->transaction = t;
t->buffer->target_node = target_node;
// 从发起进程的用户空间拷贝数据到目标进程的内存映射缓冲区
if (binder_alloc_copy_user_to_buffer(
&target_proc->alloc,
t->buffer,
ALIGN(tr->data_size, sizeof(void *)),
(const void __user *)
(uintptr_t)tr->data.ptr.offsets,
tr->offsets_size)) {
...
}
...
// 设置 binder_work 类型
if (t->buffer->oneway_spam_suspect)
tcomplete->type = BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT;
else
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
t->work.type = BINDER_WORK_TRANSACTION;
if (reply) { // BC_REPLY
// tcomplete 插入当前线程
binder_enqueue_thread_work(thread, tcomplete);
binder_inner_proc_lock(target_proc);
...
// t 插入目标线程的任务队列
binder_enqueue_thread_work_ilocked(target_thread, &t->work);
binder_inner_proc_unlock(target_proc);
// ...
// 唤醒目标线程
wake_up_interruptible_sync(&target_thread->wait);
// 恢复服务端线程的优先级
binder_restore_priority(thread, &in_reply_to->saved_priority);
binder_free_transaction(in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) { // BC_TRANSACTION 非oneway
binder_inner_proc_lock(proc);
// 把 BINDER_WORK_TRANSACTION_COMPLETE 延迟插入当前线程的任务队列;当服务端响应(BC_REPLY)返回时再处理
binder_enqueue_deferred_thread_work_ilocked(thread, tcomplete);
...
binder_inner_proc_unlock(proc);
// 把 BINDER_WORK_TRANSACTION 插入目标线程的任务队列,并唤醒目标线程
return_error = binder_proc_transaction(t,
target_proc, target_thread);
...
} else { // BC_TRANSACTION oneway
...
}
//
return;
...
}
binder_thread_read
- 从当前线程或进程的todo任务队列取出任务 binder_work;
- 通过成员 binder_work 获取 binder_transaction 结构体地址;
- 填充 binder_transaction_data 对象,binder_transaction 中的数据写入 binder_transaction_data;
- 把通信协议码和通信数据写入用户空间缓冲区 mIn;
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed, int non_block)
{
void __user *buffer = (void __user *)(uintptr_t)binder_buffer; // read_buffer - mIn
void __user *ptr = buffer + *consumed; // mIn 写指针
void __user *end = buffer + size;
int ret = 0;
int wait_for_proc_work;
...
retry:
binder_inner_proc_lock(proc);
// 用户空间进入到这里,阻塞;有任务插入队列时,被唤醒
wait_for_proc_work = binder_available_for_proc_work_ilocked(thread);
...
while (1) {
uint32_t cmd;
struct binder_transaction_data_secctx tr;
struct binder_transaction_data *trd = &tr.transaction_data; // 写回用户空间的通信数据
struct binder_work *w = NULL; // 跨进程通信事务类型
struct list_head *list = NULL; // todo 队列
struct binder_transaction *t = NULL; // 跨进程通信数据
struct binder_thread *t_from;
size_t trsize = sizeof(*trd);
binder_inner_proc_lock(proc);
if (list)
goto skip;
// 当前线程或进程的todo任务队列
if (!binder_worklist_empty_ilocked(&thread->todo))
list = &thread->todo;
else if (!binder_worklist_empty_ilocked(&proc->todo) &&
wait_for_proc_work)
list = &proc->todo;
else {
binder_inner_proc_unlock(proc);
/* no data added */
if (ptr - buffer == 4 && !thread->looper_need_return)
goto retry;
break;
}
skip:
if (end - ptr < sizeof(tr) + 4) {
binder_inner_proc_unlock(proc);
break;
}
// 从todo任务队列中取出任务 binder_work
w = binder_dequeue_work_head_ilocked(list);
//...
// 根据 binder_work 的类型做不同的处理
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
// 通过成员 binder_work 获取 binder_transaction 结构体地址
t = container_of(w, struct binder_transaction, work);
} break;
//...
case BINDER_WORK_TRANSACTION_COMPLETE:
case BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT: {
if (proc->oneway_spam_detection_enabled &&
w->type == BINDER_WORK_TRANSACTION_ONEWAY_SPAM_SUSPECT)
cmd = BR_ONEWAY_SPAM_SUSPECT;
else // 返回协议码为 BR_TRANSACTION_COMPLETE
cmd = BR_TRANSACTION_COMPLETE;
binder_inner_proc_unlock(proc);
kfree(w); // 释放 binder_work 对象
// 把通信协议写入用户空间的缓冲区 mIn
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t); // 更新写指针位置
} break;
// binder_node 增加引用计数
case BINDER_WORK_NODE:
// 死亡通知
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION:
}
// 下面为 BINDER_WORK_TRANSACTION 的逻辑
if (!t)
continue;
if (t->buffer->target_node) { // target_node 不为空,表示这是服务端响应请求 - 返回协议
struct binder_node *target_node = t->buffer->target_node;
trd->target.ptr = target_node->ptr; // 服务端 weak_ref
trd->cookie = target_node->cookie; // 服务端 BBinder
binder_transaction_priority(thread, t, target_node); // 设置服务端线程优先级
cmd = BR_TRANSACTION; // 设置通信协议码
} else { // 客户端接受服务端的响应
trd->target.ptr = 0;
trd->cookie = 0;
cmd = BR_REPLY;
}
trd->code = t->code; // 通信协议
trd->flags = t->flags;
trd->sender_euid = from_kuid(current_user_ns(), t->sender_euid);
// 设置进程id
t_from = binder_get_txn_from(t);
if (t_from) {
struct task_struct *sender = t_from->proc->tsk;
trd->sender_pid =
task_tgid_nr_ns(sender,
task_active_pid_ns(current));
} else {
trd->sender_pid = 0;
}
// ...
// binder_transaction 中的数据写入 binder_transaction_data
trd->data_size = t->buffer->data_size;
trd->offsets_size = t->buffer->offsets_size;
trd->data.ptr.buffer = (uintptr_t)t->buffer->user_data;
trd->data.ptr.offsets = trd->data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *));
tr.secctx = t->security_ctx;
if (t->security_ctx) {
cmd = BR_TRANSACTION_SEC_CTX;
trsize = sizeof(tr);
}
// 把通信协议码和数据写入用户空间
if (put_user(cmd, (uint32_t __user *)ptr)) {
}
ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, trsize)) {
}
ptr += trsize; // 更新写指针
//...
break;
}
done:
// ...
return 0;
}
通信协议
通信协议分为2种:命令协议,用户空间向驱动写入,以BC_开头;返回协议,驱动向用户空间写入,以BR_开头;
事务类型:客户端-驱动-服务端,为 TRANSACTION;服务端-驱动-客户端,为 REPLY;
驱动收到用户空间的请求,返回的协议码以 COMPLETE 结尾;
命令协议
enum binder_driver_command_protocol {
BC_TRANSACTION = _IOW('c', 0, struct binder_transaction_data), // 客户端请求
BC_REPLY = _IOW('c', 1, struct binder_transaction_data), // 服务端响应
// 通信数据为 binder_transaction_data
BC_ACQUIRE_RESULT = _IOW('c', 2, __s32),
// 不支持
BC_FREE_BUFFER = _IOW('c', 3, binder_uintptr_t),
// 释放缓冲区
BC_INCREFS = _IOW('c', 4, __u32), // 增加 binder_ref 的弱引用计数
BC_ACQUIRE = _IOW('c', 5, __u32), // 增加 binder_ref 的强引用计数
BC_RELEASE = _IOW('c', 6, __u32), // 减少 binder_ref 的强引用计数
BC_DECREFS = _IOW('c', 7, __u32), // 减少 binder_ref 的弱引用计数
// 通信数据为 binder_ref 的句柄值 desc
BC_INCREFS_DONE = _IOW('c', 8, struct binder_ptr_cookie),
BC_ACQUIRE_DONE = _IOW('c', 9, struct binder_ptr_cookie),
// 成功增加 binder_node 强弱引用计数后
BC_ATTEMPT_ACQUIRE = _IOW('c', 10, struct binder_pri_desc),
// 不支持
BC_REGISTER_LOOPER = _IO('c', 11),
BC_ENTER_LOOPER = _IO('c', 12),
BC_EXIT_LOOPER = _IO('c', 13),
// 注册、进入、退出 binder 线程池
BC_REQUEST_DEATH_NOTIFICATION = _IOW('c', 14,
struct binder_handle_cookie),
// 发送 binder 死亡通知
BC_CLEAR_DEATH_NOTIFICATION = _IOW('c', 15,
struct binder_handle_cookie),
// 注销 binder 死亡通知
BC_DEAD_BINDER_DONE = _IOW('c', 16, binder_uintptr_t),
// 完成处理 binder 死亡通知
};
返回协议
enum binder_driver_return_protocol {
BR_ERROR = _IOR('r', 0, __s32),
// 驱动异常
BR_OK = _IO('r', 1),
// 驱动处理完成
BR_TRANSACTION_SEC_CTX = _IOR('r', 2,
struct binder_transaction_data_secctx),
// 设置 service manager
BR_TRANSACTION = _IOR('r', 2, struct binder_transaction_data), // 驱动转发给服务端的请求
BR_REPLY = _IOR('r', 3, struct binder_transaction_data), // 驱动转发给客户端端的响应
// 通信数据为 binder_transaction_data
BR_ACQUIRE_RESULT = _IOR('r', 4, __s32),
// 不支持
BR_DEAD_REPLY = _IO('r', 5),
// 目标进程或线程已经死亡
BR_TRANSACTION_COMPLETE = _IO('r', 6),
// 驱动收到用户空间发送的命令
BR_INCREFS = _IOR('r', 7, struct binder_ptr_cookie),
BR_ACQUIRE = _IOR('r', 8, struct binder_ptr_cookie),
BR_RELEASE = _IOR('r', 9, struct binder_ptr_cookie),
BR_DECREFS = _IOR('r', 10, struct binder_ptr_cookie),
// 增加 service 的强弱引用计数
BR_ATTEMPT_ACQUIRE = _IOR('r', 11, struct binder_pri_ptr_cookie),
// 不支持
BR_NOOP = _IO('r', 12),
/*
* No parameters. Do nothing and examine the next command. It exists
* primarily so that we can replace it with a BR_SPAWN_LOOPER command.
*/
BR_SPAWN_LOOPER = _IO('r', 13),
// 驱动通知进程增加 binder 线程
BR_FINISHED = _IO('r', 14),
// 不支持
BR_DEAD_BINDER = _IOR('r', 15, binder_uintptr_t),
// 通知客户端,服务端对象死亡
BR_CLEAR_DEATH_NOTIFICATION_DONE = _IOR('r', 16, binder_uintptr_t),
// 驱动完成注销死亡通知
BR_FAILED_REPLY = _IO('r', 17),
// 驱动处理 bcTRANSACTION or bcATTEMPT_ACQUIRE 发送异常
BR_ONEWAY_SPAM_SUSPECT = _IO('r', 19),
// 通知进程发送了太多的异常调用,缓冲区分配超过阈值
};