cyrushine / bookmark

4 stars 1 forks source link

Binder驱动之设备控制 binder_ioctl -- 二(源码分析)- 巫屋 - 简书 #42

Open cyrushine opened 1 year ago

cyrushine commented 1 year ago

https://www.jianshu.com/p/12bec1b16a5b

static int binder_ioctl_write_read(struct file *filp,
                unsigned int cmd, unsigned long arg,
                struct binder_thread *thread)
{
    int ret = 0;
    struct binder_proc *proc = filp->private_data;
    /*读取arg的大小,通过3.2.1 可知改大小应为 sizeof(struct binder_write_read) 的大小 */
    unsigned int size = _IOC_SIZE(cmd);
    void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;
    if (size != sizeof(struct binder_write_read)) {
        ret = -EINVAL;
        goto out;
    }
    /* 从用户态地址读取struct binder_write_read结构体 */
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
    binder_debug(BINDER_DEBUG_READ_WRITE,
            "%d:%d write %lld at %016llx, read %lld at %016llx\n",
            proc->pid, thread->pid,
            (u64)bwr.write_size, (u64)bwr.write_buffer,
            (u64)bwr.read_size, (u64)bwr.read_buffer);
    /* write_size大于0,表示用户进程有数据发送到驱动,则调用binder_thread_write发送数据 详见:3.2.2.1*/
    if (bwr.write_size > 0) {
        ret = **binder_thread_write**(proc, thread,
                    bwr.write_buffer,
                    bwr.write_size,
                    &bwr.write_consumed);
        trace_binder_write_done(ret);
        if (ret < 0) {
            /*binder_thread_write中有错误发生,则read_consumed设为0,表示kernel没有数据返回给进程*/
            bwr.read_consumed = 0;
            /*将bwr返回给用户态调用者,bwr在binder_thread_write中会被修改*/
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    /*read_size大于0, 表示进程用户态地址空间希望有数据返回给它,则调用binder_thread_read进行处理*/
    if (bwr.read_size > 0) {
        ret = **binder_thread_read**(proc, thread, bwr.read_buffer,
                    bwr.read_size,
                    &bwr.read_consumed,
                    **filp->f_flags & O_NONBLOCK**);
        trace_binder_read_done(ret);
        /*读取完后,如果proc->todo链表不为空,则唤醒在proc->wait等待队列上的进程*/
        if (!list_empty(&proc->todo))
            wake_up_interruptible(&proc->wait);
        if (ret < 0) {
            /*如果binder_thread_read返回小于0,可能处理一半就中断了,需要将bwr拷贝回进程的用户态地址*/
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
    }
    binder_debug(BINDER_DEBUG_READ_WRITE,
            "%d:%d wrote %lld of %lld, read return %lld of %lld\n",
            proc->pid, thread->pid,
            (u64)bwr.write_consumed, (u64)bwr.write_size,
            (u64)bwr.read_consumed, (u64)bwr.read_size);
    /* 处理成功的情况,也需要将bwr拷贝回进程的用户态地址空间*/
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
out:
    return ret;
}

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;
        /*填充日志信息*/
    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;
      /*先确定目标线程(target_thread)和目标进程(target_proc)*/
    if (reply) { /*BC_REPLY命令,说明这是一个Server发给Client的事务处理回复。在server端的线程上。*/
        /*从取出栈顶reply对应的transaction*/
        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;
        }
        binder_set_nice(in_reply_to->saved_priority);
        /*transaction的目标线程需是当前线程*/
        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;
        }
        /*从栈顶移除该transaction*/
        thread->transaction_stack = in_reply_to->to_parent;
        /*本次reply的目标线程是对应transaction的发起线程*/
        target_thread = in_reply_to->from;
        if (target_thread == NULL) {
            return_error = BR_DEAD_REPLY;
            goto err_dead_binder;
        }
        /*目标线程(client)的栈顶事务需是本次reply对应的transaction的*/
        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;
    } else {/*BC_TRANSACTION 命令,说明这是一个Client发给Server的请求事务。在Client端线程上。*/
        /*第一步:先确定target_node*/
        if (tr->target.handle) {/*目标service是普通service,handle > 0 */
            struct binder_ref *ref;
            ref = binder_get_ref(proc, tr->target.handle);
            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;
        } else {/*目标service是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找到目标进程target_proc*/
        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;
        }
        /*第三步:根据目标进程target_proc查找目标线程target_thread*/
        if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) { /*非one_way, 需要replay,且transaction栈不为空*/
            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;
            }
            /* 从事务栈(transaction_stack)的栈顶向下搜索,
            * 找到最后(最早)一个目标进程中向当前进程发起事务请求的线程为本次请求的目标线程。
            */
            while (tmp) {
                if (tmp->from && tmp->from->proc == target_proc)
                    target_thread = tmp->from;
                tmp = tmp->from_parent;
            }
        }
    }
    if (target_thread) {
        /*找到target_thread, 则target_list和target_wait分别初始化为目标线程的todo和wait队列*/
        e->to_thread = target_thread->pid;
        target_list = &target_thread->todo;
        target_wait = &target_thread->wait;
    } else {
        /* 没有找到target_thread, target_list和target_wait分别初始化为目标进程的todo和wait队列
        * 这个情况只有BC_TRANSACTION命令才有可能发生
        */
        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 = kzalloc(sizeof(*t), GFP_KERNEL);
    if (t == NULL) {
        return_error = BR_FAILED_REPLY;
        goto err_alloc_t_failed;
    }
    binder_stats_created(BINDER_STAT_TRANSACTION);
/*分配一个binder_work*/
    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,
                "%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);
    if (!reply && !(tr->flags & TF_ONE_WAY)) /*BC_TRANSACTION,且不是one way,即需要replay,则发起线程(from)设为当前线程*/
      t->from = thread;
    else/*BC_REPLY,from置为空*/
        t->from = NULL;
    /*初始化binder_transaction各域*/
    t->sender_euid = task_euid(proc->tsk);
    t->to_proc = target_proc;
    t->to_thread = target_thread;
    t->code = tr->code;
    t->flags = tr->flags;
    t->priority = task_nice(current);
    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) {
        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;
    trace_binder_transaction_alloc_buf(t->buffer);
    if (target_node) /*该target_node被binder_buffer引用,所以增加引用计数*/
       binder_inc_node(target_node, 1, 0, NULL);
    /*计算offset区的起始地址*/
    offp = (binder_size_t *)(t->buffer->data +
                 ALIGN(tr->data_size, sizeof(void *)));
    /*将用户态binder_transaction_data中的数据拷贝到内核驱动的binder_buffer中,binder通信的一次拷贝就是发生在这里*/
    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;
    }
    /* 拷贝binder_transaction_data的offset区到内核驱动
    */
    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; /*offset区的结束地址*/
    off_min = 0;
    /*接下来是循环处理在前一步从binder_transaction_data中拷贝进来所有flat_binder_object*/
    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;
        }
        /*获取flat_binder_object的地址*/
        fp = (struct flat_binder_object *)(t->buffer->data + *offp);
        off_min = *offp + sizeof(struct flat_binder_object);
        switch (fp->type) {
        /*BBinder的flat_binder_object*/
        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) {
                /*内核态驱动还没有相应的binder_node来表示该binder service,则新建一个*/
                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("%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);
                return_error = BR_FAILED_REPLY;
                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;
            }
            /*在proc的`refs_by_node`红黑树中查找该binder_node对应的binder_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;
            }
            /* 转换成客户端表示,分别修改type和handle */
            if (fp->type == BINDER_TYPE_BINDER**)
                fp->type = BINDER_TYPE_HANDLE;
            else
                fp->type = BINDER_TYPE_WEAK_HANDLE;
            fp->handle = ref->desc;**
/*增加引用计数,防止该binder_ref被释放*/
            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;
        /*BpBinder的flat_binder_object*/
        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) {
                /*该flat_binder_object的目标进程是该binder service所在进程*/
                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 {
                /*该flat_binder_object的目标进程不是该binder service所在进程*/
                struct binder_ref *new_ref;
        /*在目标进程中binder_node找到对应的binder_ref。每个进程都有自己的binder_ref来对应binder_node*/
                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;/*更新handle的值,设置成目标进程binder_ref的desc*/
                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL); /*增加目标进程binde_ref的引用计数*/
                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)) {/*客户端进程不接受fd*/
                    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) {/*目标进程不接受fd*/
                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); /*根据文件描述符找到对应的struct file结构体*/
            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);
                return_error = BR_FAILED_REPLY;
                goto err_get_unused_fd_failed;
            }
            task_fd_install(target_proc, target_fd, file); /*在目标进程中,将file与刚获取到文件描述符target_fd对应起来。这样两个进程中虽然fd不同,但其实都是对应同一个struct 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;
        } 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);
        /*事务处理完成,将本次reply对应的transaction从目标线程(Client)事务栈中移除,并释放其所占用的地址空间*/
     binder_pop_transaction(target_thread, in_reply_to);
    } else if (!(t->flags & TF_ONE_WAY)) {/*一个client到server的transaction,且需要reply*/
        /*将本次事务的binder_transaction加入到本线程事务栈中*/
        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); /添加一个本线程的todo队列中,稍后在线程处理todo队列的该binder_work时,会发送个BR_WORK_TRANSCAION_COMPLETE给进程,告知请求/回复已发送出去。*/
    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:
    trace_binder_transaction_failed_buffer_release(t->buffer);
    /* 递减transaction相关的binder_node, binder_ref及data中的flat_binder_object有关的binder_ref,binder_node的引用计数
    * 如果传递的文件描述符,还要关闭该文件描述符
    */
    binder_transaction_buffer_release(target_proc, t->buffer, offp);
    t->buffer->transaction = NULL;
    /*释放之前分配的binder_buffer*/
    binder_free_buf(target_proc, t->buffer);
err_binder_alloc_buf_failed:
    /*释放binder_work*/
    kfree(tcomplete);
    binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
err_alloc_tcomplete_failed:
    /*释放binder_transaction*/
    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
        /*将错误码存储起来,以便在之后的binder_thread_read中处理*/
        thread->return_error = return_error;
}
cyrushine commented 11 months ago

image