码迷,mamicode.com
首页 > 其他好文 > 详细

Binder驱动笔记

时间:2015-02-10 15:27:37      阅读:219      评论:0      收藏:0      [点我收藏+]

标签: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, &param);
#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, &param);
#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驱动笔记

标签:binder

原文地址:http://blog.csdn.net/guoqifa29/article/details/43702193

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!