binder 发送 BINDER_WRITE_READ 过程
2016-07-26 20:53
555 查看
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
...
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
...
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
...
}
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
...
}
...
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
...
return ret;
}
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
{
...
uint32_t cmd;
void __user *ptr = buffer + *consumed; //数据开始
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr)) //从用户空间获得命令的类型
switch (cmd) {
...
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);// 处理 BC_TRANSACTION,BC_REPLY
break;
}
...
*consumed = ptr - buffer;
}
return 0;
}
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
...
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;
}
...
if (reply) {
binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
t->need_reply = 1;
t->from_parent = thread->transaction_stack; // 传输的真实数据 binder_transaction
thread->transaction_stack = t;
...
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list); //添加到目标线程的todo工作队列
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);//添加到命令发起者的todo工作队列
if (target_wait)
wake_up_interruptible(target_wait); //唤醒目标 server 正在 binder_thread_read 等待的目标线程
return;
}
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
{
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
...
ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));//睡眠等待 todo 中的数据
...
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo))
w = list_first_entry(&thread->todo, struct binder_work, entry);
else if (!list_empty(&proc->todo) && wait_for_proc_work)
w = list_first_entry(&proc->todo, struct binder_work, entry);
...
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
t = container_of(w, struct binder_transaction, work);
} break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
cmd = BR_TRANSACTION_COMPLETE;
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
...
} break;
...
// 填充 binder_transaction_data 数据
if (t->buffer->target_node) {
...
tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
...
cmd = BR_TRANSACTION;//cmd BR_TRANSACTION
} else {
tr.target.ptr = NULL;
tr.cookie = NULL;
cmd = BR_REPLY;//cmd BR_REPLY
}
...
//从todo队列中读取的数据拷贝到用户空间
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
...
*consumed = ptr - buffer;
...
return 0;
}
binder 通信数据请求过程
1.BC_TRANSACTION //客户端第一次通过 binder驱动 向目标服务端的 todo队列 和本地调用者线程的 todo队列,添加工作项数据,再唤醒服务端的read()
//在唤醒服务端后,继续执行本地的read(),处理上面添加到本地todo的任务项数据(BR_TRANSACTION_COMPLETE)
2.BR_TRANSACTION //服务端 ioctl 里的 read()函数被唤醒后,会向自己的用户空间发送 BR_TRANSACTION 操作,
//此时服务端的用户空间就实现了RPC调用,得到返回结果后再向binder驱动发送(BC_REPLY),把数据传递到内核空间
3.BR_TRANSACTION_COMPLETE //客户端处理本地todo,此时会将数据传递到用户空间,意思是我们会跳出binder_ioctl函数返回到用户空间,
//很快由于while(1)我们会第二次进入到内核空间,在read()函数中等待服务端的处理结果
4.BC_REPLY //BR_TRANSACTION 命令后,经过一段时间服务端的数据已经处理完成,服务端的用户空间向内核空间发送 BC_REPLY,
//将处理好的数据传回给binder驱动,将工作项数据添加到目标客户的todo,再唤醒等待的客户端
5.BR_REPLY //客户端被唤醒后,是在客户端内核空间 read() 函数中处理 BR_REPLY 命令,然后将数据客户端的用户空间,
//这样客户端就拿到了服务端的处理数据,IPC就完成了
6.BR_TRANSACTION_COMPLETE //同上面一样,这时候只是 服务端处理本地todo工作项,同样也返回到用户空间,
//又会第二次进入到 ioctl 的 read()函数中,等待新的 client 的请求。
{
...
switch (cmd) {
case BINDER_WRITE_READ: {
struct binder_write_read bwr;
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL;
goto err;
}
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
...
if (bwr.write_size > 0) {
ret = binder_thread_write(proc, thread, (void __user *)bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
...
}
if (bwr.read_size > 0) {
ret = binder_thread_read(proc, thread, (void __user *)bwr.read_buffer, bwr.read_size, &bwr.read_consumed, filp->f_flags & O_NONBLOCK);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
...
}
...
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT;
goto err;
}
break;
}
...
return ret;
}
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread,
void __user *buffer, int size, signed long *consumed)
{
...
uint32_t cmd;
void __user *ptr = buffer + *consumed; //数据开始
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
if (get_user(cmd, (uint32_t __user *)ptr)) //从用户空间获得命令的类型
switch (cmd) {
...
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
if (copy_from_user(&tr, ptr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);// 处理 BC_TRANSACTION,BC_REPLY
break;
}
...
*consumed = ptr - buffer;
}
return 0;
}
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
...
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;
}
...
if (reply) {
binder_pop_transaction(target_thread, in_reply_to);
} else if (!(t->flags & TF_ONE_WAY)) {
t->need_reply = 1;
t->from_parent = thread->transaction_stack; // 传输的真实数据 binder_transaction
thread->transaction_stack = t;
...
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list); //添加到目标线程的todo工作队列
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);//添加到命令发起者的todo工作队列
if (target_wait)
wake_up_interruptible(target_wait); //唤醒目标 server 正在 binder_thread_read 等待的目标线程
return;
}
static int binder_thread_read(struct binder_proc *proc,
struct binder_thread *thread,
void __user *buffer, int size,
signed long *consumed, int non_block)
{
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
...
ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread));//睡眠等待 todo 中的数据
...
while (1) {
uint32_t cmd;
struct binder_transaction_data tr;
struct binder_work *w;
struct binder_transaction *t = NULL;
if (!list_empty(&thread->todo))
w = list_first_entry(&thread->todo, struct binder_work, entry);
else if (!list_empty(&proc->todo) && wait_for_proc_work)
w = list_first_entry(&proc->todo, struct binder_work, entry);
...
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
t = container_of(w, struct binder_transaction, work);
} break;
case BINDER_WORK_TRANSACTION_COMPLETE: {
cmd = BR_TRANSACTION_COMPLETE;
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
...
} break;
...
// 填充 binder_transaction_data 数据
if (t->buffer->target_node) {
...
tr.target.ptr = target_node->ptr;
tr.cookie = target_node->cookie;
...
cmd = BR_TRANSACTION;//cmd BR_TRANSACTION
} else {
tr.target.ptr = NULL;
tr.cookie = NULL;
cmd = BR_REPLY;//cmd BR_REPLY
}
...
//从todo队列中读取的数据拷贝到用户空间
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (copy_to_user(ptr, &tr, sizeof(tr)))
return -EFAULT;
ptr += sizeof(tr);
...
*consumed = ptr - buffer;
...
return 0;
}
binder 通信数据请求过程
1.BC_TRANSACTION //客户端第一次通过 binder驱动 向目标服务端的 todo队列 和本地调用者线程的 todo队列,添加工作项数据,再唤醒服务端的read()
//在唤醒服务端后,继续执行本地的read(),处理上面添加到本地todo的任务项数据(BR_TRANSACTION_COMPLETE)
2.BR_TRANSACTION //服务端 ioctl 里的 read()函数被唤醒后,会向自己的用户空间发送 BR_TRANSACTION 操作,
//此时服务端的用户空间就实现了RPC调用,得到返回结果后再向binder驱动发送(BC_REPLY),把数据传递到内核空间
3.BR_TRANSACTION_COMPLETE //客户端处理本地todo,此时会将数据传递到用户空间,意思是我们会跳出binder_ioctl函数返回到用户空间,
//很快由于while(1)我们会第二次进入到内核空间,在read()函数中等待服务端的处理结果
4.BC_REPLY //BR_TRANSACTION 命令后,经过一段时间服务端的数据已经处理完成,服务端的用户空间向内核空间发送 BC_REPLY,
//将处理好的数据传回给binder驱动,将工作项数据添加到目标客户的todo,再唤醒等待的客户端
5.BR_REPLY //客户端被唤醒后,是在客户端内核空间 read() 函数中处理 BR_REPLY 命令,然后将数据客户端的用户空间,
//这样客户端就拿到了服务端的处理数据,IPC就完成了
6.BR_TRANSACTION_COMPLETE //同上面一样,这时候只是 服务端处理本地todo工作项,同样也返回到用户空间,
//又会第二次进入到 ioctl 的 read()函数中,等待新的 client 的请求。
相关文章推荐
- s3c2440的网卡接口扩展(DM9000)
- Manacher算法: 最长回文子串O(N)时间内求解
- 浅谈矩阵分解在推荐系统中的应用
- Spark RDD API详解(一) Map和Reduce
- 折半查找(二分查找)
- codevs 3693 数三角形
- jquery获取当前tomcat目录
- 虚拟机 安装 CUDA 可行性说明
- Java中String和StringBuffer、StringBuilder
- handler倒计时
- 字符串的旋转
- magedu_20160725
- 如何在myeclipse中导入jar包?
- 23种java设计模式之观察者模式
- 信号量操作函数中的SEM_UNDO
- 详解SQL Server连接(内连接、外连接、交叉连接)
- POJ 3041-Asteroids(二分图匹配)
- C fork introduce
- signal函数、pause函数和可重入函数
- 类与类之间的关系