标签:binder
对于Binder驱动,可以一个个函数进行拆分学习,以管窥豹的方式进行理解。 以下函数分析都是基于驱动binder.c文件。
1.binder_get_ref_for_node(target_proc,binder_node),该函数用来为Binder实体节点创建一个Binder引用节点,target_proc代表binder引用所在的进程。比如client获取service的Binder引用,那么client进程就拥有该Binder引用。
static struct binder_ref *binder_get_ref_for_node(struct binder_proc *proc,
struct binder_node *node)
{
struct rb_node *n;
struct rb_node **p = &proc->refs_by_node.rb_node; //每个进程节点都有一个refs_by_node红黑树,用来保存属于该进程的Binder引用;
struct rb_node *parent = NULL;
struct binder_ref *ref, *new_ref;
while (*p) { //先查询是否进程节点中是否已经存在Binder实体的引用;
parent = *p;
ref = rb_entry(parent, struct binder_ref, rb_node_node);
if (node < ref->node)
p = &(*p)->rb_left;
else if (node > ref->node)
p = &(*p)->rb_right;
else
return ref;
}
new_ref = kzalloc(sizeof(*ref), GFP_KERNEL);
if (new_ref == NULL)
return NULL;
binder_stats_created(BINDER_STAT_REF);
new_ref->debug_id = ++binder_last_id;
new_ref->proc = proc; //binder引用节点会保存该引用节点属于哪个进程,及保存该引用节点所对应的Binder实体节点;
new_ref->node = node;
rb_link_node(&new_ref->rb_node_node, parent, p);
rb_insert_color(&new_ref->rb_node_node, &proc->refs_by_node);
//开始计算binder引用的handle值,这个值会返回给target_proc进程,从下面的handle值计算过程可以总结出:target_proc进程拥有的binder引用的handle值是从1开始递增的;所有进程拥有handle=0的binder引用都是指向service manager;同一个service的binder实体在不同进程中的binder引用的handle值可能不一样;
new_ref->desc = (node == binder_context_mgr_node) ? 0 : 1;
for (n = rb_first(&proc->refs_by_desc); n != NULL; n = rb_next(n)) {
ref = rb_entry(n, struct binder_ref, rb_node_desc);
if (ref->desc > new_ref->desc)
break;
new_ref->desc = ref->desc + 1;
}
//将new_ref插入proc->refs_by_desc红黑树中;
p = &proc->refs_by_desc.rb_node;
while (*p) {
parent = *p;
ref = rb_entry(parent, struct binder_ref, rb_node_desc);
if (new_ref->desc < ref->desc)
p = &(*p)->rb_left;
else if (new_ref->desc > ref->desc)
p = &(*p)->rb_right;
else
BUG();
}
rb_link_node(&new_ref->rb_node_desc, parent, p);
rb_insert_color(&new_ref->rb_node_desc, &proc->refs_by_desc);
if (node) {
hlist_add_head(&new_ref->node_entry, &node->refs);
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d new ref %d desc %d for node %d\n",
proc->pid, new_ref->debug_id, new_ref->desc,
node->debug_id);
} else {
binder_debug(BINDER_DEBUG_INTERNAL_REFS,
"%d new ref %d desc %d for dead node\n",
proc->pid, new_ref->debug_id, new_ref->desc);
}
return new_ref;
}
2.命令解释
BC_ACQUIRE:增加handle的强引用计数
在client进程第一次拿到service的Binder引用时会向Binder驱动发送该命令;
在service将自己添加到service manager中时,service manager拿到service的handle时也会向Binder驱动发送该消息;
BC_RELEASE:减少handle的强引用计数
BC_INCREFS:增加handle的弱引用计数
BC_DECREFS:减少handle的弱引用计数
3.binder_transaction()函数分析
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply)
{
struct binder_transaction *t;
struct binder_work *tcomplete;
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;
struct binder_transaction_log_entry *e;
uint32_t return_error;
#ifdef BINDER_MONITOR
struct binder_transaction_log_entry log_entry;
unsigned int log_idx = -1;
if ((reply && (tr->data_size < (proc->buffer_size/16))) || log_disable)
e = &log_entry;
else
{
e = binder_transaction_log_add(&binder_transaction_log);
if (binder_transaction_log.next)
log_idx = binder_transaction_log.next - 1;
else
log_idx = binder_transaction_log.size - 1;
}
#else
e = binder_transaction_log_add(&binder_transaction_log);
#endif
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;
#ifdef BINDER_MONITOR
e->code = tr->code;
/* fd 0 is also valid... set initial value to -1 */
e->fd = -1;
do_posix_clock_monotonic_gettime(&e->timestamp);
//monotonic_to_bootbased(&e->timestamp);
do_gettimeofday(&e->tv);
/* consider time zone. translate to android time */
e->tv.tv_sec -= (sys_tz.tz_minuteswest * 60);
#endif
if (reply) {
in_reply_to = thread->transaction_stack;
if (in_reply_to == NULL) {
binder_user_error("%d:%d got reply transaction with no transaction stack\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_empty_call_stack;
}
#ifdef BINDER_MONITOR
binder_cancel_bwdog(in_reply_to);
#endif
binder_set_nice(in_reply_to->saved_priority);
#ifdef RT_PRIO_INHERIT
if (rt_task(current) && (MAX_RT_PRIO != in_reply_to->saved_rt_prio) &&
!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
BINDER_LOOPER_STATE_ENTERED))) {
struct sched_param param = {
.sched_priority = in_reply_to->saved_rt_prio,
};
mt_sched_setscheduler_nocheck(current,
in_reply_to->saved_policy, ¶m);
#ifdef BINDER_MONITOR
if (log_disable & BINDER_RT_LOG_ENABLE)
{
pr_debug("reply reset %d sched_policy from %d to %d rt_prio from %d to %d\n",
proc->pid, in_reply_to->policy, in_reply_to->saved_policy,
in_reply_to->rt_prio, in_reply_to->saved_rt_prio);
}
#endif
}
#endif
if (in_reply_to->to_thread != thread) {
binder_user_error("%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;
target_thread = in_reply_to->from;
if (target_thread == NULL) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d got reply transaction "
"with bad transaction reply_from, "
"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);
#endif
return_error = BR_DEAD_REPLY;
goto err_dead_binder;
}
if (target_thread->transaction_stack != in_reply_to) {
binder_user_error("%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_proc = target_thread->proc;
#ifdef BINDER_MONITOR
e->service[0] = ‘\0‘;
#endif
} else {
} else { //client发起的transaction;
if (tr->target.handle) {
struct binder_ref *ref;
ref = binder_get_ref(proc, tr->target.handle); //获取handle值对应的binder引用节点;
if (ref == NULL) {
binder_user_error("%d:%d got transaction to invalid handle\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_invalid_target_handle;
}
target_node = ref->node; //从binder引用节点中取出binder实体节点;
} else {
target_node = binder_context_mgr_node;
if (target_node == NULL) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d "
"binder_context_mgr_node is NULL\n",
proc->pid, thread->pid);
#endif
return_error = BR_DEAD_REPLY;
goto err_no_context_mgr_node;
}
}
e->to_node = target_node->debug_id;
#ifdef BINDER_MONITOR
strcpy(e->service, target_node->name);
#endif
target_proc = target_node->proc; //从binder实体节点取出binder实体节点所在的进程节点;
if (target_proc == NULL) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d target_proc is NULL\n",
proc->pid, thread->pid);
#endif
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:%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) { //如果上面的逻辑找到target_thread,那么该transaction就指定加入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;
}
e->to_proc = target_proc->pid;
/* TODO: reuse incoming transaction for reply */
t = kzalloc(sizeof(*t), GFP_KERNEL);
if (t == NULL) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d transaction allocation failed\n",
proc->pid, thread->pid);
#endif
return_error = BR_FAILED_REPLY;
goto err_alloc_t_failed;
}
#ifdef BINDER_MONITOR
memcpy(&t->timestamp, &e->timestamp, sizeof(struct timespec));
//do_gettimeofday(&t->tv);
/* consider time zone. translate to android time */
//t->tv.tv_sec -= (sys_tz.tz_minuteswest * 60);
memcpy(&t->tv, &e->tv, sizeof(struct timeval));
if (!reply)
strcpy(t->service, target_node->name);
#endif
binder_stats_created(BINDER_STAT_TRANSACTION);
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
if (tcomplete == NULL) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d tcomplete allocation failed\n",
proc->pid, thread->pid);
#endif
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;
#ifdef BINDER_PERF_EVAL
if (!reply && (binder_perf_evalue & BINDER_PERF_SEND_COUNTER))
{
int i, j;
int err_code = 0;
proc->bc_t++;
for (i = 0; i < BC_STATS_NR; i++)
{
if (proc->bc_stats[i] == NULL)
proc->bc_stats[i] = kzalloc(sizeof(struct binder_bc_stats), GFP_KERNEL);
if (proc->bc_stats[i] == NULL) {
pr_err("perf_e kzalloc fail for proc %d bc_stats[%d]\n", proc->pid, i);
err_code = 1;
goto out_err;
}
if(!strcmp(proc->bc_stats[i]->service, "") &&
(0 == proc->bc_stats[i]->code[0]))
{
strcpy(proc->bc_stats[i]->service, e->service);
break;
}
else if (!strcmp(proc->bc_stats[i]->service, e->service))
break;
else
continue;
}
if (BC_STATS_NR == i){
pr_err("perf_e bc_Stats array size"
" is not enough\n");
err_code = 2;
goto out_err;
}
for (j = 0; j < BC_CODE_NR; j++)
{
if (0 == proc->bc_stats[i]->code[j])
{
proc->bc_stats[i]->code[j] = e->code;
proc->bc_stats[i]->code_num[j]++;
break;
}
else if (proc->bc_stats[i]->code[j] == e->code)
{
proc->bc_stats[i]->code_num[j]++;
break;
}
else
continue;
}
if (BC_CODE_NR == j) {
pr_err("perf_e bc_code array size"
" is not enough\n");
err_code = 3;
}
out_err:
pr_err("perf_e update proc %d bc_stats error %d\n", proc->pid, err_code);
}
#endif
if (reply)
binder_debug(BINDER_DEBUG_TRANSACTION,
"%d:%d BC_REPLY %d -> %d:%d, data %016llx-%016llx size %lld-%lld\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_thread->pid,
(u64)tr->data.ptr.buffer,
(u64)tr->data.ptr.offsets,
(u64)tr->data_size, (u64)tr->offsets_size);
else
binder_debug(BINDER_DEBUG_TRANSACTION,
"%d:%d BC_TRANSACTION %d -> %d - node %d, data %016llx-%016llx size %lld-%lld\n",
proc->pid, thread->pid, t->debug_id,
target_proc->pid, target_node->debug_id,
(u64)tr->data.ptr.buffer,
(u64)tr->data.ptr.offsets,
(u64)tr->data_size, (u64)tr->offsets_size);
#ifdef BINDER_MONITOR
t->fproc = proc->pid;
t->fthrd = thread->pid;
t->tproc = target_proc->pid;
t->tthrd = target_thread ? target_thread->pid : 0;
t->log_idx = log_idx;
if (!binder_check_buf_checked())
{
binder_check_buf_pid = proc->pid;
binder_check_buf_tid = thread->pid;
}
#endif
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;
else
t->from = NULL;
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);
#ifdef RT_PRIO_INHERIT
t->rt_prio = current->rt_priority;
t->policy = current->policy;
t->saved_rt_prio = MAX_RT_PRIO;
#endif
trace_binder_transaction(reply, t, 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) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d buffer allocation failed "
"on %d:0\n", proc->pid, thread->pid, target_proc->pid);
#endif
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;
#ifdef BINDER_MONITOR
t->buffer->log_entry = e;
#endif
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 ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
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 ptr\n",
proc->pid, thread->pid);
return_error = BR_FAILED_REPLY;
goto err_copy_data_failed;
}
if (!IS_ALIGNED(tr->offsets_size, sizeof(binder_size_t))) {
binder_user_error("%d:%d got transaction with invalid offsets size, %lld\n",
proc->pid, thread->pid, (u64)tr->offsets_size);
return_error = BR_FAILED_REPLY;
goto err_bad_offset;
}
off_end = (void *)offp + tr->offsets_size;
off_min = 0;
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;
}
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
off_min = *offp + sizeof(struct flat_binder_object);
switch (fp->type) {
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) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d create new node failed\n",
proc->pid, thread->pid);
#endif
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);
#ifdef BINDER_MONITOR
{
unsigned int i, len = 0;
/* this is an addService() transaction identified by:
* fp->type == BINDER_TYPE_BINDER && tr->target.handle == 0
*/
if (tr->target.handle == 0) {
/* hack into addService() payload:
* service name string is located at MAGIC_SERVICE_NAME_OFFSET,
* and interleaved with character ‘\0‘.
* for example, ‘p‘, ‘\0‘, ‘h‘, ‘\0‘, ‘o‘, ‘\0‘, ‘n‘, ‘\0‘, ‘e‘
*/
for (i = 0; (2 * i) < tr->data_size; i++) {
if ((2 * i) < MAGIC_SERVICE_NAME_OFFSET)
continue;
/* prevent array index overflow */
if (len >= (MAX_SERVICE_NAME_LEN - 1))
break;
len += sprintf((node->name) + len, "%c",
*((char *)tr->data.ptr.buffer + (2 * i)));
}
node->name[len] = ‘\0‘;
} else {
node->name[0] = ‘\0‘;
}
/* via addService of activity service, identify
* system_server‘s process id.
*/
if (!strcmp(node->name, "activity")) {
system_server_pid = proc->pid;
pr_debug("system_server %d\n", system_server_pid);
}
}
#endif
}
if (fp->cookie != node->cookie) {
binder_user_error("%d:%d sending u%016llx node %d, cookie mismatch %016llx != %016llx\n",
proc->pid, thread->pid,
(u64)fp->binder, node->debug_id,
(u64)fp->cookie, (u64)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;
}
ref = binder_get_ref_for_node(target_proc, node);
if (ref == NULL) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d get binder ref failed\n",
proc->pid, thread->pid);
#endif
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->handle = ref->desc;
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
trace_binder_transaction_node_to_ref(t, node, ref);
binder_debug(BINDER_DEBUG_TRANSACTION,
" node %d u%016llx -> ref %d desc %d\n",
node->debug_id, (u64)node->ptr,
ref->debug_id, ref->desc);
} break;
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
if (ref == NULL) {
binder_user_error("%d:%d got transaction with invalid handle, %d\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;
}
if (ref->node->proc == target_proc) {
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%016llx\n",
ref->debug_id, ref->desc, ref->node->debug_id,
(u64)ref->node->ptr);
} else {
struct binder_ref *new_ref;
new_ref = binder_get_ref_for_node(target_proc, ref->node);
if (new_ref == NULL) {
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d get new binder ref failed\n",
proc->pid, thread->pid);
#endif
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);
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("%d:%d got reply with fd, %d, 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("%d:%d got transaction with fd, %d, 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("%d:%d got transaction with invalid fd, %d\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);
#ifdef MTK_BINDER_DEBUG
binder_user_error("%d:%d to %d failed due to %d no unused fd available(%d fd leak?), %d\n",
proc->pid, thread->pid,
target_proc->pid, target_proc->pid, target_proc->pid,
target_fd);
#endif
return_error = BR_FAILED_REPLY;
goto err_get_unused_fd_failed;
}
task_fd_install(target_proc, target_fd, file);
trace_binder_transaction_fd(t, fp->handle, target_fd);
binder_debug(BINDER_DEBUG_TRANSACTION,
" fd %d -> %d\n", fp->handle, target_fd);
/* TODO: fput? */
fp->handle = target_fd;
#ifdef BINDER_MONITOR
e->fd = target_fd;
#endif
} break;
default:
binder_user_error("%d:%d got transaction with invalid object type, %x\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);
#ifdef BINDER_MONITOR
binder_update_transaction_time(&binder_transaction_log,in_reply_to, 2);
#endif
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;
}
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
#ifdef RT_PRIO_INHERIT
if (target_wait) {
unsigned long flag;
wait_queue_t *curr, *next;
bool is_lock = false;
spin_lock_irqsave(&target_wait->lock, flag);
is_lock = true;
list_for_each_entry_safe(curr, next, &target_wait->task_list, task_list) {
unsigned flags = curr->flags;
struct task_struct *tsk = curr->private;
if (tsk == NULL) {
spin_unlock_irqrestore(&target_wait->lock, flag);
is_lock = false;
wake_up_interruptible(target_wait);
break;
}
# ifdef MTK_BINDER_DEBUG
if (tsk->state == TASK_UNINTERRUPTIBLE) {
pr_err("from %d:%d to %d:%d target "
"thread state: %ld\n",
proc->pid, thread->pid,
tsk->tgid, tsk->pid, tsk->state);
show_stack(tsk, NULL);
}
# endif
if (!reply && (t->policy == SCHED_RR || t->policy == SCHED_FIFO)&&
t->rt_prio > tsk->rt_priority &&
!(t->flags & TF_ONE_WAY)) {
struct sched_param param = {
.sched_priority = t->rt_prio,
};
t->saved_rt_prio = tsk->rt_priority;
t->saved_policy = tsk->policy;
mt_sched_setscheduler_nocheck(tsk, t->policy, ¶m);
#ifdef BINDER_MONITOR
if (log_disable & BINDER_RT_LOG_ENABLE)
{
pr_debug("write set %d sched_policy from %d to %d rt_prio from %d to %d\n",
tsk->pid, t->saved_policy, t->policy,
t->saved_rt_prio, t->rt_prio);
}
#endif
}
if (curr->func(curr, TASK_INTERRUPTIBLE, 0, NULL) &&
(flags & WQ_FLAG_EXCLUSIVE))
break;
}
if (is_lock)
spin_unlock_irqrestore(&target_wait->lock, flag);
}
#else
if (target_wait)
wake_up_interruptible(target_wait);
#endif
#ifdef BINDER_MONITOR
t->wait_on = reply ? WAIT_ON_REPLY_READ : WAIT_ON_READ;
binder_queue_bwdog(t, (time_t)WAIT_BUDGET_READ);
#endif
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:
trace_binder_transaction_failed_buffer_release(t->buffer);
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:
#ifdef BINDER_MONITOR
binder_cancel_bwdog(t);
#endif
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,
"%d:%d transaction failed %d, size %lld-%lld\n",
proc->pid, thread->pid, return_error,
(u64)tr->data_size, (u64)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;
}
只有在client向service manager查询service时,才可以跨Binder传递binder引用,(type=BINDER_TYPE_HANDLE/ BINDER_TYPE_WEAK_HANDLE),其他场景下跨Binder传输只能透明传输给对端;
标签:binder
原文地址:http://blog.csdn.net/guoqifa29/article/details/43702193