// binder驱动初始化, 进程空间方法对应驱动方法
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.mmap = binder_mmap,
.open = binder_open,
.flush = binder_flush,
.release = binder_release,
}
static struct miscdevice binder_miscdev = {
.minor = MISC_DYNAMIC_MINOR,
.name = "binder",
.fops = &binder_fops
}
static int __init binder_init(void)
{
int ret
```
ret = misc_register(&binder_miscdev)
```
return ret
}
struct binder_proc {
struct hlist_node proc_node;
struct rb_root threads;
struct rb_root nodes;
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
int pid;
struct vm_area_struct *vma;
struct mm_struct *vma_vm_mm;
struct task_struct *tsk;
struct files_struct *files;
struct hlist_node deferred_work_node;
int deferred_work;
void *buffer;
ptrdiff_t user_buffer_offset;
struct list_head buffers;
struct rb_root free_buffers;
struct rb_root allocated_buffers;
size_t free_async_space;
struct page **pages;
size_t buffer_size;
uint32_t buffer_free;
struct list_head todo;
wait_queue_head_t wait;
struct binder_stats stats;
struct list_head delivered_death;
int max_threads;
int requested_threads;
int requested_threads_started;
int ready_threads;
long default_priority;
struct dentry *debugfs_entry;
};
线程状态
enum {
BINDER_LOOPER_STATE_REGISTERED = 0x01,
BINDER_LOOPER_STATE_ENTERED = 0x02,
BINDER_LOOPER_STATE_EXITED = 0x04,
BINDER_LOOPER_STATE_INVALID = 0x08,
BINDER_LOOPER_STATE_WAITING = 0x10,
BINDER_LOOPER_STATE_NEED_RETURN = 0x20
}
struct binder_thread {
struct binder_proc *proc;
struct rb_node rb_node;
int pid;
int looper;
struct binder_transaction *transaction_stack;
struct list_head todo;
uint32_t return_error;
uint32_t return_error2;
wait_queue_head_t wait;
struct binder_stats stats;
};struct binder_thread {
struct binder_proc *proc;
struct rb_node rb_node;
int pid;
int looper;
struct binder_transaction *transaction_stack;
struct list_head todo;
uint32_t return_error;
uint32_t return_error2;
wait_queue_head_t wait;
struct binder_stats stats;
};
struct binder_work {
struct list_head entry;
enum {
BINDER_WORK_TRANSACTION = 1,
BINDER_WORK_TRANSACTION_COMPLETE,
BINDER_WORK_NODE,
BINDER_WORK_DEAD_BINDER,
BINDER_WORK_DEAD_BINDER_AND_CLEAR,
BINDER_WORK_CLEAR_DEATH_NOTIFICATION,
} type;
};
struct binder_transaction {
int debug_id;
struct binder_work work;
struct binder_thread *from;
struct binder_transaction *from_parent;
struct binder_proc *to_proc;
struct binder_thread *to_thread;
struct binder_transaction *to_parent;
unsigned need_reply:1;
struct binder_buffer *buffer;
unsigned int code;
unsigned int flags;
long priority;
long saved_priority;
uid_t sender_euid;
};
struct binder_node {
int debug_id;
struct binder_work work;
union {
struct rb_node rb_node;
struct hlist_node dead_node;
};
struct binder_proc *proc;
struct hlist_head refs;
int internal_strong_refs;
int local_weak_refs;
int local_strong_refs;
void __user *ptr;
void __user *cookie;
unsigned has_strong_ref:1;
unsigned pending_strong_ref:1;
unsigned has_weak_ref:1;
unsigned pending_weak_ref:1;
unsigned has_async_transaction:1;
unsigned accept_fds:1;
unsigned min_priority:8;
struct list_head async_todo;
};
struct binder_ref {
int debug_id;
struct rb_node rb_node_desc;
struct rb_node rb_node_node;
struct hlist_node node_entry;
struct binder_proc *proc;
struct binder_node *node;
uint32_t desc;
int strong;
int weak;
struct binder_ref_death *death;
};
struct binder_buffer {
struct list_head entry;
struct rb_node rb_node;
unsigned free:1;
unsigned allow_user_free:1;
unsigned async_transaction:1;
unsigned debug_id:29;
struct binder_transaction *transaction;
struct binder_node *target_node;
size_t data_size;
size_t offsets_size;
uint8_t data[0];
};
// 进程空间ioctl调用跃迁到驱动层
// 传输命令cmd、传输数据binder_write_read
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
int ret
// 当前调用方进程binder_proc
struct binder_proc *proc = filp->private_data
// 当前调用方线程binder_thread
struct binder_thread *thread
unsigned int size = _IOC_SIZE(cmd)
// 进程数据复制到ubuf
void __user *ubuf = (void __user *)arg
/*printk(KERN_INFO "binder_ioctl: %d:%d %x %lx\n",
proc->pid, current->pid, cmd, arg)
// 等待
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2)
if (ret)
return ret
binder_lock(__func__)
// 每个线程都有一个独一无二的pid
// 当前调用线程pid对应进程空间线程pid
thread = binder_get_thread(proc)
if (thread == NULL) {
ret = -ENOMEM
goto err
}
switch (cmd) {
// BINDER_WRITE_READ 命令
case BINDER_WRITE_READ: {
struct binder_write_read bwr
// 数据长度不够,错误
if (size != sizeof(struct binder_write_read)) {
ret = -EINVAL
goto err
}
// 将进程空间数据ubuf拷贝到驱动层bwr
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT
goto err
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d write %ld at %08lx, read %ld at %08lx\n",
proc->pid, thread->pid, bwr.write_size, bwr.write_buffer,
bwr.read_size, bwr.read_buffer)
// write_size > 0, 写数据
if (bwr.write_size > 0) {
// binder_thread_write 驱动写数据
ret = binder_thread_write(proc, thread, (void __user *)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 err
}
}
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))
// 当前binder_proc todo还有事务
// 唤醒当前线程继续处理
wake_up_interruptible(&proc->wait)
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT
goto err
}
}
binder_debug(BINDER_DEBUG_READ_WRITE,
"binder: %d:%d wrote %ld of %ld, read return %ld of %ld\n",
proc->pid, thread->pid, bwr.write_consumed, bwr.write_size,
bwr.read_consumed, bwr.read_size)
// 驱动处理之后, 拷贝数据回用户进程空间
if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
ret = -EFAULT
goto err
}
break
}
case BINDER_SET_MAX_THREADS:
// 设置proc->max_threads 最大线程数
if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret = -EINVAL
goto err
}
break
case BINDER_SET_CONTEXT_MGR:
// serviceManager成为上下午管理器
if (binder_context_mgr_node != NULL) {
printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n")
ret = -EBUSY
goto err
}
ret = security_binder_set_context_mgr(proc->tsk)
if (ret < 0)
goto err
if (binder_context_mgr_uid != -1) {
if (binder_context_mgr_uid != current->cred->euid) {
printk(KERN_ERR "binder: BINDER_SET_"
"CONTEXT_MGR bad uid %d != %d\n",
current->cred->euid,
binder_context_mgr_uid)
ret = -EPERM
goto err
}
} else
binder_context_mgr_uid = current->cred->euid
// new全局binder_context_mgr_node对象
binder_context_mgr_node = binder_new_node(proc, NULL, NULL)
if (binder_context_mgr_node == NULL) {
ret = -ENOMEM
goto err
}
binder_context_mgr_node->local_weak_refs++
binder_context_mgr_node->local_strong_refs++
binder_context_mgr_node->has_strong_ref = 1
binder_context_mgr_node->has_weak_ref = 1
break
case BINDER_THREAD_EXIT:
// 线程退出、释放线程数据置NULL
binder_debug(BINDER_DEBUG_THREADS, "binder: %d:%d exit\n",
proc->pid, thread->pid)
binder_free_thread(proc, thread)
thread = NULL
break
case BINDER_VERSION:
// 进程空间获取驱动binder版本
if (size != sizeof(struct binder_version)) {
ret = -EINVAL
goto err
}
if (put_user(BINDER_CURRENT_PROTOCOL_VERSION, &((struct binder_version *)ubuf)->protocol_version)) {
ret = -EINVAL
goto err
}
break
default:
ret = -EINVAL
goto err
}
ret = 0
err:
if (thread)
thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN
binder_unlock(__func__)
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2)
if (ret && ret != -ERESTARTSYS)
printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret)
return ret
}
// 获取当前线程pid对应的binder_thread
// 不存在则new binder_thread
static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
struct binder_thread *thread = NULL
struct rb_node *parent = NULL
struct rb_node **p = &proc->threads.rb_node
while (*p) {
parent = *p
thread = rb_entry(parent, struct binder_thread, rb_node)
if (current->pid < thread->pid)
p = &(*p)->rb_left
else if (current->pid > thread->pid)
p = &(*p)->rb_right
else
break
}
if (*p == NULL) {
thread = kzalloc(sizeof(*thread), GFP_KERNEL)
if (thread == NULL)
return NULL
binder_stats_created(BINDER_STAT_THREAD)
// 线程所属binder_proc
thread->proc = proc
// 线程pid独一无二,对应进程空间线程pid
thread->pid = current->pid
init_waitqueue_head(&thread->wait)
INIT_LIST_HEAD(&thread->todo)
rb_link_node(&thread->rb_node, parent, p)
rb_insert_color(&thread->rb_node, &proc->threads)
thread->looper |= BINDER_LOOPER_STATE_NEED_RETURN
// 线程返回码 正常BR_OK
thread->return_error = BR_OK
thread->return_error2 = BR_OK
}
return thread
}
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))
return -EFAULT;
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) {
case BC_INCREFS:
case BC_ACQUIRE:
case BC_RELEASE:
case BC_DECREFS: {
uint32_t target;
struct binder_ref *ref;
const char *debug_string;
if (get_user(target, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (target == 0 && binder_context_mgr_node &&
(cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
ref = binder_get_ref_for_node(proc,
binder_context_mgr_node);
if (ref->desc != target) {
binder_user_error("binder: %d:"
"%d tried to acquire "
"reference to desc 0, "
"got %d instead\n",
proc->pid, thread->pid,
ref->desc);
}
} else
ref = binder_get_ref(proc, target);
if (ref == NULL) {
binder_user_error("binder: %d:%d refcou"
"nt change on invalid ref %d\n",
proc->pid, thread->pid, target);
break;
}
switch (cmd) {
case BC_INCREFS:
debug_string = "IncRefs";
binder_inc_ref(ref, 0, NULL);
break;
case BC_ACQUIRE:
debug_string = "Acquire";
binder_inc_ref(ref, 1, NULL);
break;
case BC_RELEASE:
debug_string = "Release";
binder_dec_ref(ref, 1);
break;
case BC_DECREFS:
default:
debug_string = "DecRefs";
binder_dec_ref(ref, 0);
break;
}
binder_debug(BINDER_DEBUG_USER_REFS,
"binder: %d:%d %s ref %d desc %d s %d w %d for node %d\n",
proc->pid, thread->pid, debug_string, ref->debug_id,
ref->desc, ref->strong, ref->weak, ref->node->debug_id);
break;
}
case BC_INCREFS_DONE:
case BC_ACQUIRE_DONE: {
void __user *node_ptr;
void *cookie;
struct binder_node *node;
if (get_user(node_ptr, (void * __user *)ptr))
return -EFAULT;
ptr += sizeof(void *);
if (get_user(cookie, (void * __user *)ptr))
return -EFAULT;
ptr += sizeof(void *);
node = binder_get_node(proc, node_ptr);
if (node == NULL) {
binder_user_error("binder: %d:%d "
"%s u%p no match\n",
proc->pid, thread->pid,
cmd == BC_INCREFS_DONE ?
"BC_INCREFS_DONE" :
"BC_ACQUIRE_DONE",
node_ptr);
break;
}
if (cookie != node->cookie) {
binder_user_error("binder: %d:%d %s u%p node %d"
" cookie mismatch %p != %p\n",
proc->pid, thread->pid,
cmd == BC_INCREFS_DONE ?
"BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
node_ptr, node->debug_id,
cookie, node->cookie);
break;
}
if (cmd == BC_ACQUIRE_DONE) {
if (node->pending_strong_ref == 0) {
binder_user_error("binder: %d:%d "
"BC_ACQUIRE_DONE node %d has "
"no pending acquire request\n",
proc->pid, thread->pid,
node->debug_id);
break;
}
node->pending_strong_ref = 0;
} else {
if (node->pending_weak_ref == 0) {
binder_user_error("binder: %d:%d "
"BC_INCREFS_DONE node %d has "
"no pending increfs request\n",
proc->pid, thread->pid,
node->debug_id);
break;
}
node->pending_weak_ref = 0;
}
binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0);
binder_debug(BINDER_DEBUG_USER_REFS,
"binder: %d:%d %s node %d ls %d lw %d\n",
proc->pid, thread->pid,
cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
node->debug_id, node->local_strong_refs, node->local_weak_refs);
break;
}
case BC_ATTEMPT_ACQUIRE:
printk(KERN_ERR "binder: BC_ATTEMPT_ACQUIRE not supported\n");
return -EINVAL;
case BC_ACQUIRE_RESULT:
printk(KERN_ERR "binder: BC_ACQUIRE_RESULT not supported\n");
return -EINVAL;
case BC_FREE_BUFFER: {
void __user *data_ptr;
struct binder_buffer *buffer;
if (get_user(data_ptr, (void * __user *)ptr))
return -EFAULT;
ptr += sizeof(void *);
buffer = binder_buffer_lookup(proc, data_ptr);
if (buffer == NULL) {
binder_user_error("binder: %d:%d "
"BC_FREE_BUFFER u%p no match\n",
proc->pid, thread->pid, data_ptr);
break;
}
if (!buffer->allow_user_free) {
binder_user_error("binder: %d:%d "
"BC_FREE_BUFFER u%p matched "
"unreturned buffer\n",
proc->pid, thread->pid, data_ptr);
break;
}
binder_debug(BINDER_DEBUG_FREE_BUFFER,
"binder: %d:%d BC_FREE_BUFFER u%p found buffer %d for %s transaction\n",
proc->pid, thread->pid, data_ptr, buffer->debug_id,
buffer->transaction ? "active" : "finished");
if (buffer->transaction) {
buffer->transaction->buffer = NULL;
buffer->transaction = NULL;
}
if (buffer->async_transaction && buffer->target_node) {
BUG_ON(!buffer->target_node->has_async_transaction);
if (list_empty(&buffer->target_node->async_todo))
buffer->target_node->has_async_transaction = 0;
else
list_move_tail(buffer->target_node->async_todo.next, &thread->todo);
}
binder_transaction_buffer_release(proc, buffer, NULL);
binder_free_buf(proc, buffer);
break;
}
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);
break;
}
case BC_REGISTER_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
"binder: %d:%d BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
if (thread->looper & BINDER_LOOPER_STATE_ENTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("binder: %d:%d ERROR:"
" BC_REGISTER_LOOPER called "
"after BC_ENTER_LOOPER\n",
proc->pid, thread->pid);
} else if (proc->requested_threads == 0) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("binder: %d:%d ERROR:"
" BC_REGISTER_LOOPER called "
"without request\n",
proc->pid, thread->pid);
} else {
proc->requested_threads--;
proc->requested_threads_started++;
}
thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
break;
case BC_ENTER_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
"binder: %d:%d BC_ENTER_LOOPER\n",
proc->pid, thread->pid);
if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
thread->looper |= BINDER_LOOPER_STATE_INVALID;
binder_user_error("binder: %d:%d ERROR:"
" BC_ENTER_LOOPER called after "
"BC_REGISTER_LOOPER\n",
proc->pid, thread->pid);
}
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
case BC_EXIT_LOOPER:
binder_debug(BINDER_DEBUG_THREADS,
"binder: %d:%d BC_EXIT_LOOPER\n",
proc->pid, thread->pid);
thread->looper |= BINDER_LOOPER_STATE_EXITED;
break;
case BC_REQUEST_DEATH_NOTIFICATION:
case BC_CLEAR_DEATH_NOTIFICATION: {
uint32_t target;
void __user *cookie;
struct binder_ref *ref;
struct binder_ref_death *death;
if (get_user(target, (uint32_t __user *)ptr))
return -EFAULT;
ptr += sizeof(uint32_t);
if (get_user(cookie, (void __user * __user *)ptr))
return -EFAULT;
ptr += sizeof(void *);
ref = binder_get_ref(proc, target);
if (ref == NULL) {
binder_user_error("binder: %d:%d %s "
"invalid ref %d\n",
proc->pid, thread->pid,
cmd == BC_REQUEST_DEATH_NOTIFICATION ?
"BC_REQUEST_DEATH_NOTIFICATION" :
"BC_CLEAR_DEATH_NOTIFICATION",
target);
break;
}
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
"binder: %d:%d %s %p ref %d desc %d s %d w %d for node %d\n",
proc->pid, thread->pid,
cmd == BC_REQUEST_DEATH_NOTIFICATION ?
"BC_REQUEST_DEATH_NOTIFICATION" :
"BC_CLEAR_DEATH_NOTIFICATION",
cookie, ref->debug_id, ref->desc,
ref->strong, ref->weak, ref->node->debug_id);
if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
if (ref->death) {
binder_user_error("binder: %d:%"
"d BC_REQUEST_DEATH_NOTI"
"FICATION death notific"
"ation already set\n",
proc->pid, thread->pid);
break;
}
death = kzalloc(sizeof(*death), GFP_KERNEL);
if (death == NULL) {
thread->return_error = BR_ERROR;
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
"binder: %d:%d "
"BC_REQUEST_DEATH_NOTIFICATION failed\n",
proc->pid, thread->pid);
break;
}
binder_stats_created(BINDER_STAT_DEATH);
INIT_LIST_HEAD(&death->work.entry);
death->cookie = cookie;
ref->death = death;
if (ref->node->proc == NULL) {
ref->death->work.type = BINDER_WORK_DEAD_BINDER;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&ref->death->work.entry, &thread->todo);
} else {
list_add_tail(&ref->death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
}
} else {
if (ref->death == NULL) {
binder_user_error("binder: %d:%"
"d BC_CLEAR_DEATH_NOTIFI"
"CATION death notificat"
"ion not active\n",
proc->pid, thread->pid);
break;
}
death = ref->death;
if (death->cookie != cookie) {
binder_user_error("binder: %d:%"
"d BC_CLEAR_DEATH_NOTIFI"
"CATION death notificat"
"ion cookie mismatch "
"%p != %p\n",
proc->pid, thread->pid,
death->cookie, cookie);
break;
}
ref->death = NULL;
if (list_empty(&death->work.entry)) {
death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&death->work.entry, &thread->todo);
} else {
list_add_tail(&death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
} else {
BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER);
death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR;
}
}
} break;
case BC_DEAD_BINDER_DONE: {
struct binder_work *w;
void __user *cookie;
struct binder_ref_death *death = NULL;
if (get_user(cookie, (void __user * __user *)ptr))
return -EFAULT;
ptr += sizeof(void *);
list_for_each_entry(w, &proc->delivered_death, entry) {
struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
if (tmp_death->cookie == cookie) {
death = tmp_death;
break;
}
}
binder_debug(BINDER_DEBUG_DEAD_BINDER,
"binder: %d:%d BC_DEAD_BINDER_DONE %p found %p\n",
proc->pid, thread->pid, cookie, death);
if (death == NULL) {
binder_user_error("binder: %d:%d BC_DEAD"
"_BINDER_DONE %p not found\n",
proc->pid, thread->pid, cookie);
break;
}
list_del_init(&death->work.entry);
if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) {
death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
list_add_tail(&death->work.entry, &thread->todo);
} else {
list_add_tail(&death->work.entry, &proc->todo);
wake_up_interruptible(&proc->wait);
}
}
} break;
default:
printk(KERN_ERR "binder: %d:%d unknown command %d\n",
proc->pid, thread->pid, cmd);
return -EINVAL;
}
*consumed = ptr - buffer;
}
return 0;
}
/**
* binder_transaction_data数据处理
* 处理binder_transaction_data携带的flat_binder_object数据
* 传输数据到target进程
*/
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
// binder_transaction_data数据封装成一个事务binder_transaction
struct binder_transaction *t
// 事务binder_transaction处理之后发送tcomplete事务回调用端
struct binder_work *tcomplete
size_t *offp, *off_end
size_t off_min
// 事务传输到目标进程target_proc
struct binder_proc *target_proc
// 事务传输到目标线程target_thread
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
struct binder_transaction_log_entry *e
uint32_t return_error = BR_OK
e = binder_transaction_log_add(&binder_transaction_log)
e->call_type = reply ? 2 : !!(tr->flags & TF_ONE_WAY)
e->from_proc = proc->pid
e->from_thread = thread->pid
e->target_handle = tr->target.handle
e->data_size = tr->data_size
e->offsets_size = tr->offsets_size
if (reply) {
// 需要回复,从binder_thread中的transaction事务栈中弹出保存的事务
in_reply_to = thread->transaction_stack
if (in_reply_to == NULL) {
binder_user_error("binder: %d:%d got reply transaction "
"with no transaction stack\n",
proc->pid, thread->pid)
return_error = BR_FAILED_REPLY
goto err_empty_call_stack
}
binder_set_nice(in_reply_to->saved_priority)
if (in_reply_to->to_thread != thread) {
binder_user_error("binder: %d:%d got reply transaction "
"with bad transaction stack,"
" transaction %d has target %d:%d\n",
proc->pid, thread->pid, in_reply_to->debug_id,
in_reply_to->to_proc ?
in_reply_to->to_proc->pid : 0,
in_reply_to->to_thread ?
in_reply_to->to_thread->pid : 0)
return_error = BR_FAILED_REPLY
in_reply_to = NULL
goto err_bad_call_stack
}
thread->transaction_stack = in_reply_to->to_parent
// 该事务来源于哪个binder_thread from
// 找到target_thread
target_thread = in_reply_to->from
if (target_thread == NULL) {
return_error = BR_DEAD_REPLY
goto err_dead_binder
}
if (target_thread->transaction_stack != in_reply_to) {
binder_user_error("binder: %d:%d got reply transaction "
"with bad target transaction stack %d, "
"expected %d\n",
proc->pid, thread->pid,
target_thread->transaction_stack ?
target_thread->transaction_stack->debug_id : 0,
in_reply_to->debug_id)
return_error = BR_FAILED_REPLY
in_reply_to = NULL
target_thread = NULL
goto err_dead_binder
}
// 根据target_thread找到target_proc
target_proc = target_thread->proc
} else {
// target handler不为0
if (tr->target.handle) {
struct binder_ref *ref
// binder引用树查找该handle对应的binder_ref
// 每个binder_proc有棵binder_node_ref树(desc为标识对应handle句柄)
ref = binder_get_ref(proc, tr->target.handle)
if (ref == NULL) {
binder_user_error("binder: %d:%d got "
"transaction to invalid handle\n",
proc->pid, thread->pid)
return_error = BR_FAILED_REPLY
goto err_invalid_target_handle
}
// binder_ref获取target binder_node, 可查找到binder_proc
target_node = ref->node
} else {
// target handle 为0, target_node为serviceManager
target_node = binder_context_mgr_node
if (target_node == NULL) {
return_error = BR_DEAD_REPLY
goto err_no_context_mgr_node
}
}
e->to_node = target_node->debug_id
// 根据target_node 这个binderNode找到target_poc
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("binder: %d:%d got new "
"transaction with bad transaction stack"
", transaction %d has target %d:%d\n",
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
}
while (tmp) {
if (tmp->from && tmp->from->proc == target_proc)
target_thread = tmp->from
tmp = tmp->from_parent
}
}
}
if (target_thread) {
// reply 情况下是可以找到target_thread得到todo target_list
e->to_thread = target_thread->pid
target_list = &target_thread->todo
target_wait = &target_thread->wait
} else {
// 根据target_proc得到target_list todo
target_list = &target_proc->todo
target_wait = &target_proc->wait
}
e->to_proc = target_proc->pid
/* TODO: reuse incoming transaction for reply */
// 封装一个binder_transaction t放入target todo
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)
t->debug_id = ++binder_last_id
e->debug_id = t->debug_id
if (reply)
binder_debug(BINDER_DEBUG_TRANSACTION,
"binder: %d:%d BC_REPLY %d -> %d:%d, "
"data %p-%p size %zd-%zd\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_thread->pid,
tr->data.ptr.buffer, tr->data.ptr.offsets,
tr->data_size, tr->offsets_size)
else
binder_debug(BINDER_DEBUG_TRANSACTION,
"binder: %d:%d BC_TRANSACTION %d -> "
"%d - node %d, data %p-%p size %zd-%zd\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_node->debug_id,
tr->data.ptr.buffer, tr->data.ptr.offsets,
tr->data_size, tr->offsets_size)
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread
else
t->from = NULL
/* workaround code for invalid binder proc */
if (!proc->tsk) {
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
"binder: %d:%d invalid proc\n",
proc->pid, thread->pid)
return_error = BR_FAILED_REPLY
goto err_binder_alloc_buf_failed
}
// 填充binder_transaction t对象
t->sender_euid = proc->tsk->cred->euid
t->to_proc = target_proc
t->to_thread = target_thread
t->code = tr->code
t->flags = tr->flags
t->priority = task_nice(current)
// 从target_proc中申请tr->data_size以及tr->offsets_size大小空间
// 即binder_transation_data数据以及flat_binder_object偏移位置集合数据空间大小,用来接收发送端数据
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
}
t->buffer->allow_user_free = 0
t->buffer->debug_id = t->debug_id
t->buffer->transaction = t
t->buffer->target_node = target_node
if (target_node)
binder_inc_node(target_node, 1, 0, NULL)
offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)))
// 拷贝binder_transation_data tr中parcel全部数据到binder_transaction t->buffer->data里面
if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {
binder_user_error("binder: %d:%d got transaction with invalid "
"data ptr\n", proc->pid, thread->pid)
return_error = BR_FAILED_REPLY
goto err_copy_data_failed
}
// 拷贝拷贝binder_transation_data tr中parcel mObjects数据到offp中, 即所有flat_binder_object偏移位置
if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {
binder_user_error("binder: %d:%d got transaction with invalid "
"offsets ptr\n", proc->pid, thread->pid)
return_error = BR_FAILED_REPLY
goto err_copy_data_failed
}
if (!IS_ALIGNED(tr->offsets_size, sizeof(size_t))) {
binder_user_error("binder: %d:%d got transaction with "
"invalid offsets size, %zd\n",
proc->pid, thread->pid, tr->offsets_size)
return_error = BR_FAILED_REPLY
goto err_bad_offset
}
off_end = (void *)offp + tr->offsets_size
off_min = 0
// 遍历offp获取所有mObjects即flat_binder_object数据
for (
struct flat_binder_object *fp
// 每个offp表示flat_binder_object数据在t->buffer偏移地址
if (*offp > t->buffer->data_size - sizeof(*fp) ||
*offp < off_min ||
t->buffer->data_size < sizeof(*fp) ||
!IS_ALIGNED(*offp, sizeof(void *))) {
binder_user_error("%d:%d got transaction with invalid offset, %zd (min %zd, max %zd)\n",
proc->pid, thread->pid, *offp, off_min,
(t->buffer->data_size - sizeof(*fp)))
return_error = BR_FAILED_REPLY
goto err_bad_offset
}
// *offp对应mObjects数组每个flat_binder_object偏移指针
// 每读取一个offp++取下一个flat_binder_object偏移指针
// 从t->buffer->data中获取位置*offp的flat_binder_object数据
fp = (struct flat_binder_object *)(t->buffer->data + *offp)
off_min = *offp + sizeof(struct flat_binder_object)
// 根据binder类型进行相关处理
switch (fp->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
// 本地binder类型flat_binder_object
struct binder_ref *ref
// 在binder_proc binder_node树根据binder指针查找binder_node节点
struct binder_node *node = binder_get_node(proc, fp->binder)
if (node == NULL) {
// 树中没有该节点,新建binder节点插入当前进程binder_proc binder节点树(保存重要属性node-》ptr, node->cookie)
// node节点所属的binder_proc
// node->proc = proc
// 对应上层赋予的fp->binder, fp->cookie
// node->ptr = ptr
// node->cookie = cookie
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)
}
if (fp->cookie != node->cookie) {
binder_user_error("binder: %d:%d sending u%p "
"node %d, cookie mismatch %p != %p\n",
proc->pid, thread->pid,
fp->binder, node->debug_id,
fp->cookie, node->cookie)
goto err_binder_get_ref_for_node_failed
}
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
return_error = BR_FAILED_REPLY
goto err_binder_get_ref_for_node_failed
}
// 在目标进程target_proc插入binder节点引用
// desc(handle), 如果node是binder_context_mgr_node,则从0开始增加
// 如果不是从1开始增加
// 每个binder_node节点在其他target_proc中的binder_node_ref节点树中的handle值不一样
// 各自都是在binder_node_ref树中从0或者1开始递增
// 目标进程可根据handle句柄查找到对应的binder_node_ref节点,便可以得到对方的binder_node节点
// 然后根据binder_node节点得到对方binder_proc
// 本地binder对象存放两份, 一份存在自家binder_proc的binder_node节点树上
// 一份存放在目标进程target_proc的binder_node_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
}
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE
else
fp->type = BINDER_TYPE_WEAK_HANDLE
// fp type变成BINDER_TYPE_HANDLE
// handle 即 ref->desc
fp->handle = ref->desc
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo)
binder_debug(BINDER_DEBUG_TRANSACTION,
" node %d u%p -> ref %d desc %d\n",
node->debug_id, node->ptr, ref->debug_id,
ref->desc)
} break
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
// 远程binder对象,携带handle句柄
// 从上面逻辑可以知道,每个binder实体在目标进程会保存一份binder_node_ref在binder_node_ref节点树上
// 当前作为请求端自然应该存放有给binder引用
// 根据handle句柄查找到binder_ref
// 根据binder_ref便可以得到对方的binder_node节点
// 然后根据binder_node节点得到对方binder_proc
struct binder_ref *ref = binder_get_ref(proc, fp->handle)
if (ref == NULL) {
binder_user_error("binder: %d:%d got "
"transaction with invalid "
"handle, %ld\n", 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
}
//binder_ref获取binder_node进而获取binder_proc
if (ref->node->proc == target_proc) {
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER
else
fp->type = BINDER_TYPE_WEAK_BINDER
// 修改type为BINDER_TYPE_BINDER 或者 BINDER_TYPE_WEAK_BINDER
// 获取binder实体prt cookie指针
fp->binder = ref->node->ptr
fp->cookie = ref->node->cookie
binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL)
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> node %d u%p\n",
ref->debug_id, ref->desc, ref->node->debug_id,
ref->node->ptr)
} else {
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)
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> ref %d desc %d (node %d)\n",
ref->debug_id, ref->desc, new_ref->debug_id,
new_ref->desc, ref->node->debug_id)
}
} break
case BINDER_TYPE_FD: {
int target_fd
struct file *file
if (reply) {
if (!(in_reply_to->flags & TF_ACCEPT_FDS)) {
binder_user_error("binder: %d:%d got reply with fd, %ld, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle)
return_error = BR_FAILED_REPLY
goto err_fd_not_allowed
}
} else if (!target_node->accept_fds) {
binder_user_error("binder: %d:%d got transaction with fd, %ld, but target does not allow fds\n",
proc->pid, thread->pid, fp->handle)
return_error = BR_FAILED_REPLY
goto err_fd_not_allowed
}
file = fget(fp->handle)
if (file == NULL) {
binder_user_error("binder: %d:%d got transaction with invalid fd, %ld\n",
proc->pid, thread->pid, fp->handle)
return_error = BR_FAILED_REPLY
goto err_fget_failed
}
if (security_binder_transfer_file(proc->tsk, target_proc->tsk, file) < 0) {
fput(file)
return_error = BR_FAILED_REPLY
goto err_get_unused_fd_failed
}
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC)
if (target_fd < 0) {
fput(file)
return_error = BR_FAILED_REPLY
goto err_get_unused_fd_failed
}
task_fd_install(target_proc, target_fd, file)
binder_debug(BINDER_DEBUG_TRANSACTION,
" fd %ld -> %d\n", fp->handle, target_fd)
/* TODO: fput? */
fp->handle = target_fd
} break
default:
binder_user_error("binder: %d:%d got transactio"
"n with invalid object type, %lx\n",
proc->pid, thread->pid, fp->type)
return_error = BR_FAILED_REPLY
goto err_bad_object_type
}
}
if (reply) {
BUG_ON(t->buffer->async_transaction != 0)
binder_pop_transaction(target_thread, in_reply_to)
} 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->transaction_stack = t
} else {
BUG_ON(target_node == NULL)
BUG_ON(t->buffer->async_transaction != 1)
if (target_node->has_async_transaction) {
target_list = &target_node->async_todo
target_wait = NULL
} else
target_node->has_async_transaction = 1
}
// 处理完数据中的flat_binder_object binder对象之后
// 该事务类型为BINDER_WORK_TRANSACTION
t->work.type = BINDER_WORK_TRANSACTION
// 将类型为BINDER_WORK_TRANSACTION的t事务插入目标进程target_list
list_add_tail(&t->work.entry, target_list)
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE
// 在当前进程binder_thread todo插入tcomplete BINDER_WORK_TRANSACTION_COMPLETE事件
list_add_tail(&tcomplete->entry, &thread->todo)
if (target_wait)
// 唤醒目标进程
wake_up_interruptible(target_wait)
return
err_get_unused_fd_failed:
err_fget_failed:
err_fd_not_allowed:
err_binder_get_ref_for_node_failed:
err_binder_get_ref_failed:
err_binder_new_node_failed:
err_bad_object_type:
err_bad_offset:
err_copy_data_failed:
binder_transaction_buffer_release(target_proc, t->buffer, offp)
t->buffer->transaction = NULL
binder_free_buf(target_proc, t->buffer)
err_binder_alloc_buf_failed:
kfree(tcomplete)
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE)
err_alloc_tcomplete_failed:
kfree(t)
binder_stats_deleted(BINDER_STAT_TRANSACTION)
err_alloc_t_failed:
err_bad_call_stack:
err_empty_call_stack:
err_dead_binder:
err_invalid_target_handle:
err_no_context_mgr_node:
binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
"binder: %d:%d transaction failed %d, size %zd-%zd\n",
proc->pid, thread->pid, return_error,
tr->data_size, tr->offsets_size)
{
struct binder_transaction_log_entry *fe
fe = binder_transaction_log_add(&binder_transaction_log_failed)
*fe = *e
}
BUG_ON(thread->return_error != BR_OK)
if (in_reply_to) {
thread->return_error = BR_TRANSACTION_COMPLETE
binder_send_failed_reply(in_reply_to, return_error)
} else
thread->return_error = return_error
}
/**
* 驱动读todo数据填充buffer
*/
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
int ret = 0
int wait_for_proc_work
if (*consumed == 0) {
if (put_user(BR_NOOP, (uint32_t __user *)ptr))
return -EFAULT
ptr += sizeof(uint32_t)
}
retry:
wait_for_proc_work = thread->transaction_stack == NULL &&
list_empty(&thread->todo)
if (thread->return_error != BR_OK && ptr < end) {
if (thread->return_error2 != BR_OK) {
if (put_user(thread->return_error2, (uint32_t __user *)ptr))
return -EFAULT
ptr += sizeof(uint32_t)
if (ptr == end)
goto done
thread->return_error2 = BR_OK
}
if (put_user(thread->return_error, (uint32_t __user *)ptr))
return -EFAULT
ptr += sizeof(uint32_t)
thread->return_error = BR_OK
goto done
}
thread->looper |= BINDER_LOOPER_STATE_WAITING
if (wait_for_proc_work)
proc->ready_threads++
binder_unlock(__func__)
if (wait_for_proc_work) {
if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
binder_user_error("binder: %d:%d ERROR: Thread waiting "
"for process work before calling BC_REGISTER_"
"LOOPER or BC_ENTER_LOOPER (state %x)\n",
proc->pid, thread->pid, thread->looper)
wait_event_interruptible(binder_user_error_wait,
binder_stop_on_user_error < 2)
}
binder_set_nice(proc->default_priority)
if (non_block) {
if (!binder_has_proc_work(proc, thread))
ret = -EAGAIN
} else
ret = wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread))
} else {
if (non_block) {
if (!binder_has_thread_work(thread))
ret = -EAGAIN
} else
ret = wait_event_interruptible(thread->wait, binder_has_thread_work(thread))
}
binder_lock(__func__)
if (wait_for_proc_work)
proc->ready_threads--
thread->looper &= ~BINDER_LOOPER_STATE_WAITING
if (ret)
return ret
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)
else {
if (ptr - buffer == 4 && !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN)) /* no data added */
goto retry
break
}
if (end - ptr < sizeof(tr) + 4)
break
// binder_work type 区分处理
// BINDER_WORK_TRANSACTION取出binder_transaction事务数据
switch (w->type) {
case BINDER_WORK_TRANSACTION: {
t = container_of(w, struct binder_transaction, work)
} break
// BINDER_WORK_TRANSACTION_COMPLETE是客户端发送请求binder_transaction结束之后会得到该回传
case BINDER_WORK_TRANSACTION_COMPLETE: {
cmd = BR_TRANSACTION_COMPLETE
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT
ptr += sizeof(uint32_t)
binder_stat_br(proc, thread, cmd)
binder_debug(BINDER_DEBUG_TRANSACTION_COMPLETE,
"binder: %d:%d BR_TRANSACTION_COMPLETE\n",
proc->pid, thread->pid)
list_del(&w->entry)
kfree(w)
binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE)
} break
case BINDER_WORK_NODE: {
struct binder_node *node = container_of(w, struct binder_node, work)
uint32_t cmd = BR_NOOP
const char *cmd_name
int strong = node->internal_strong_refs || node->local_strong_refs
int weak = !hlist_empty(&node->refs) || node->local_weak_refs || strong
if (weak && !node->has_weak_ref) {
cmd = BR_INCREFS
cmd_name = "BR_INCREFS"
node->has_weak_ref = 1
node->pending_weak_ref = 1
node->local_weak_refs++
} else if (strong && !node->has_strong_ref) {
cmd = BR_ACQUIRE
cmd_name = "BR_ACQUIRE"
node->has_strong_ref = 1
node->pending_strong_ref = 1
node->local_strong_refs++
} else if (!strong && node->has_strong_ref) {
cmd = BR_RELEASE
cmd_name = "BR_RELEASE"
node->has_strong_ref = 0
} else if (!weak && node->has_weak_ref) {
cmd = BR_DECREFS
cmd_name = "BR_DECREFS"
node->has_weak_ref = 0
}
if (cmd != BR_NOOP) {
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT
ptr += sizeof(uint32_t)
if (put_user(node->ptr, (void * __user *)ptr))
return -EFAULT
ptr += sizeof(void *)
if (put_user(node->cookie, (void * __user *)ptr))
return -EFAULT
ptr += sizeof(void *)
binder_stat_br(proc, thread, cmd)
binder_debug(BINDER_DEBUG_USER_REFS,
"binder: %d:%d %s %d u%p c%p\n",
proc->pid, thread->pid, cmd_name, node->debug_id, node->ptr, node->cookie)
} else {
list_del_init(&w->entry)
if (!weak && !strong) {
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"binder: %d:%d node %d u%p c%p deleted\n",
proc->pid, thread->pid, node->debug_id,
node->ptr, node->cookie)
rb_erase(&node->rb_node, &proc->nodes)
kfree(node)
binder_stats_deleted(BINDER_STAT_NODE)
} else {
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"binder: %d:%d node %d u%p c%p state unchanged\n",
proc->pid, thread->pid, node->debug_id, node->ptr,
node->cookie)
}
}
} break
case BINDER_WORK_DEAD_BINDER:
case BINDER_WORK_DEAD_BINDER_AND_CLEAR:
case BINDER_WORK_CLEAR_DEATH_NOTIFICATION: {
struct binder_ref_death *death
uint32_t cmd
death = container_of(w, struct binder_ref_death, work)
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE
else
cmd = BR_DEAD_BINDER
if (put_user(cmd, (uint32_t __user *)ptr))
return -EFAULT
ptr += sizeof(uint32_t)
if (put_user(death->cookie, (void * __user *)ptr))
return -EFAULT
ptr += sizeof(void *)
binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
"binder: %d:%d %s %p\n",
proc->pid, thread->pid,
cmd == BR_DEAD_BINDER ?
"BR_DEAD_BINDER" :
"BR_CLEAR_DEATH_NOTIFICATION_DONE",
death->cookie)
if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
list_del(&w->entry)
kfree(death)
binder_stats_deleted(BINDER_STAT_DEATH)
} else
list_move(&w->entry, &proc->delivered_death)
if (cmd == BR_DEAD_BINDER)
goto done
} break
}
// 读取到事务t
if (!t)
continue
// 读取事务t中的buffer数据(parcel、flat_object_object)
BUG_ON(t->buffer == NULL)
if (t->buffer->target_node) {
struct binder_node *target_node = t->buffer->target_node
// 取出binder_transaction中t->buffer数据填入binder_transaction_data
// 找到ptr、cookie
tr.target.ptr = target_node->ptr
tr.cookie = target_node->cookie
t->saved_priority = task_nice(current)
if (t->priority < target_node->min_priority &&
!(t->flags & TF_ONE_WAY))
binder_set_nice(t->priority)
else if (!(t->flags & TF_ONE_WAY) ||
t->saved_priority > target_node->min_priority)
binder_set_nice(target_node->min_priority)
cmd = BR_TRANSACTION
} else {
tr.target.ptr = NULL
tr.cookie = NULL
cmd = BR_REPLY
}
tr.code = t->code
tr.flags = t->flags
tr.sender_euid = t->sender_euid
if (t->from) {
struct task_struct *sender = t->from->proc->tsk
tr.sender_pid = task_tgid_nr_ns(sender,
current->nsproxy->pid_ns)
} else {
tr.sender_pid = 0
}
// 根据mmap映射直接存入t->buffer数据
tr.data_size = t->buffer->data_size
tr.offsets_size = t->buffer->offsets_size
// 在binder_transaction t->buffer中data在进程空间对应地址需要加上 proc->user_buffer_offset // 用户偏移地址
tr.data.ptr.buffer = (void *)t->buffer->data +
proc->user_buffer_offset
tr.data.ptr.offsets = tr.data.ptr.buffer +
ALIGN(t->buffer->data_size,
sizeof(void *))
// 将cmd和binder_transaction_data数据拷贝回用户空间
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)
binder_stat_br(proc, thread, cmd)
binder_debug(BINDER_DEBUG_TRANSACTION,
"binder: %d:%d %s %d %d:%d, cmd %d"
"size %zd-%zd ptr %p-%p\n",
proc->pid, thread->pid,
(cmd == BR_TRANSACTION) ? "BR_TRANSACTION" :
"BR_REPLY",
t->debug_id, t->from ? t->from->proc->pid : 0,
t->from ? t->from->pid : 0, cmd,
t->buffer->data_size, t->buffer->offsets_size,
tr.data.ptr.buffer, tr.data.ptr.offsets)
// 删除该事务
list_del(&t->work.entry)
t->buffer->allow_user_free = 1
if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
t->to_parent = thread->transaction_stack
t->to_thread = thread
thread->transaction_stack = t
} else {
t->buffer->transaction = NULL
kfree(t)
binder_stats_deleted(BINDER_STAT_TRANSACTION)
}
break
}
done:
*consumed = ptr - buffer
if (proc->requested_threads + proc->ready_threads == 0 &&
proc->requested_threads_started < proc->max_threads &&
(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED)) /* the user-space code fails to */
/*spawn a new thread if we leave this out */) {
proc->requested_threads++
binder_debug(BINDER_DEBUG_THREADS,
"binder: %d:%d BR_SPAWN_LOOPER\n",
proc->pid, thread->pid)
if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
return -EFAULT
}
return 0
}