cyrushine / bookmark

4 stars 1 forks source link

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

Open cyrushine opened 1 year ago

cyrushine commented 1 year ago

https://www.jianshu.com/p/4be292a51388

static int binder_thread_read(struct binder_proc *proc,
                struct binder_thread *thread,
                binder_uintptr_t binder_buffer, size_t size,
                binder_size_t *consumed, int non_block)
{
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    void __user *ptr = buffer + *consumed;
    void __user *end = buffer + size;
    int ret = 0;
    int wait_for_proc_work;
    if (*consumed == 0) {/*当前的写入位置为bwr.read_buffer的起始位置,先写入一个BR_NOOP命令到read_buffer中,该命令在用户态是一个空操作,什么也不做,主要意义应该是在输出日志等*/
        if (put_user(BR_NOOP, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
    }
retry:
    /*如果线程事务栈和todo队列都为空,说明此时没有要当前线程处理的任务,将增加空闲线程的计数器(即将wait_for_proc_work设为1),让线程等待在**进程**的wait队列上*/
    wait_for_proc_work = thread->transaction_stack == NULL &&
                list_empty(&thread->todo);
    if (thread->return_error != BR_OK && ptr < end) {/*之前在binder_transaction或者binder death时发生了错误*/
        if (thread->return_error2 != BR_OK) { /*发送reply时发生了错误,将错误返回给进程用户态*/
            if (put_user(thread->return_error2, (uint32_t __user *)ptr))
                return -EFAULT;
            ptr += sizeof(uint32_t);
            binder_stat_br(proc, thread, thread->return_error2);
            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);
        binder_stat_br(proc, thread, thread->return_error);
        thread->return_error = BR_OK;
        goto done;
    }
/*即将进入睡眠等待区,这会导致进程/线程进入阻塞状态,先将线程状态改为BINDER_LOOPER_STATE_WAITING*/
    thread->looper |= **BINDER_LOOPER_STATE_WAITING**;
    if (wait_for_proc_work)/*进程/线程没事需要处理*/
        proc->ready_threads++;/*空闲线程数+1*/
/*线程/进程将可能进入阻塞等待状态,先释放锁,这个锁是在binder_ioctl开始执行就拿了*/
    binder_unlock(__func__);
    trace_binder_wait_for_work(wait_for_proc_work,
                !!thread->transaction_stack,
                !list_empty(&thread->todo));
    if (wait_for_proc_work) {/*线程暂时没有工作要处理,进程/线程需要等待*/
        if (!(thread->looper & (BINDER_LOOPER_STATE_REGISTERED |
                    BINDER_LOOPER_STATE_ENTERED))) {
            /* 线程还未进入binder循环,输出错误信息,并阻塞直到binder_stop_on_user_error小于2*/
            binder_user_error("%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)) /*检查当前进程是否有工作待处理,如果没有就将返回值设为-EAGAIN,以便用户进程稍后重试*/
                ret = -**EAGAIN**;
        } else/*如果是阻塞的读操作,则让进程阻塞在proc的wait队列上,直到binder_has_proc_work(thread)为true,即进程有工作待处理*/
            ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    } else {/**/
        if (non_block) {/*读操作设置了非阻塞标识*/
            if (!binder_has_thread_work(thread)) /*检查当前线程是否有工作待处理,如果没有就将返回值设为-EAGAIN,以便用户进程稍后重试*/
                ret = -**EAGAIN**;
        } else/*如果是阻塞的读操作,则让线程阻塞在thread的wait队列上,直到binder_has_thread_work(thread)为true,即线程有工作待处理*/
            ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
    }
    /*运行到这里,要么是线程/进程没有工作待处理,但是讲返回值ret设置成了-EAGAIN;要么是线程/进程已经有工作待处理了*/
    binder_lock(__func__); /*重新获取锁*/
    if (wait_for_proc_work)/*之前进入了等待操作,线程被挂起了*/
        proc->ready_threads--;/*空闲线程数减1*/
    thread->looper &= **~BINDER_LOOPER_STATE_WAITING**;/*移除线程等待标志位*/
    /* We cannot return -ERESTARTSYS here.  This code is called
    * after binder_thread_write() has already interpreted the
    * input buffer.  A restart will result in a doubled set of
    * commands.  Just return success, having consumed zero
    * bytes. */
    if (ret)
        return ret == -ERESTARTSYS ? 0 : ret;
/*开始循环处理thread/proc的todo队列上的每一个binder_work*/
    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
    /*取出一个binder work来处理*/
        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) {/*进程的待处理列表不为空,且睡眠等待前线程的`todo`队列和事务栈都为空*/
            w = list_first_entry(&proc->todo, struct binder_work, /*从进程的待处理列表的队头中取出一项工作处理*/
                        entry);
        } else {
            /* no data added */
            if (ptr - buffer == 4 &&
                !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
                goto retry;
            break;
        }
        if (end - ptr < sizeof(tr) + 4)
            break;
        switch (w->type) {
        case **BINDER_WORK_TRANSACTION**: {/*要处理的是一个事务(Binder请求)*/
            /*根据binder_work在binder_transaction的偏移计算出binder_transaction的地址*/
            t = container_of(w, struct binder_transaction, work);
        } break;
        case **BINDER_WORK_TRANSACTION_COMPLETE**: {
            /*TRANSACTION或者REPLY发送完成消息,通过给进程发送BR_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,
                    "%d:%d BR_TRANSACTION_COMPLETE\n",
                    proc->pid, thread->pid);
            list_del(&w->entry);/*从todo队列中移除*/
            kfree(w);           /*释放在binder_thread_write在处理BC_TRANSACTION命令时在binder_transaction中申请的binder_work*/
            binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE); /*更新BINDER_STAT_TRANSACTION_COMPLETE统计数据*/
        } break;
        case **BINDER_WORK_NODE**: {/*取出的binder_work是一个binder_node*/
            struct binder_node *node = container_of(w, struct binder_node, work); /*根据偏移计算出binder_node的地址*/
            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) {/*弱引用计数不为0,但是弱引用标志位为0*/
                cmd = BR_INCREFS;    /*发送BR_INCREFS命令给进程用户态,让其增加弱引用计数*/
                cmd_name = "BR_INCREFS";
                node->has_weak_ref = 1; /*设置弱引用标志位*/
                node->pending_weak_ref = 1;  /*设置pengding标志位,表示(进程用户态)有未处理的弱引用增加命令*/
                node->local_weak_refs++; /*增加本地弱引用计数器*/
            } else if (strong && !node->has_strong_ref) {/*强引用计数不为0,但是强引用标志位为0*/
                cmd = BR_ACQUIRE; /*发送BR_ACQUIRE命令给进程,让其增加强引用计数*/
                cmd_name = "BR_ACQUIRE";
                node->has_strong_ref = 1;  /*设置强引用标志位*/
                node->pending_strong_ref = 1; /*设置pengding标志位,表示(进程用户态)有未处理的强引用增加命令*/
                node->local_strong_refs++; /*增加本地强引用计数器*/
            } else if (!strong && node->has_strong_ref) {/*强引用计数为0,但是强引用标志位不为0*/
                cmd = BR_RELEASE;
                cmd_name = "BR_RELEASE";
                node->has_strong_ref = 0;
            } else if (!weak && node->has_weak_ref) {/*弱引用计数为0,但是弱引用标志位不为0*/
                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);
                /*BBinder的引用计数器的地址发送给进程的用户态地址空间read_buffer*/
                if (put_user(node->ptr,
                        (binder_uintptr_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(binder_uintptr_t);
                /*BBinder的地址发送给进程*/
                if (put_user(node->cookie,
                        (binder_uintptr_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(binder_uintptr_t);
                /*更新统计数据*/
                binder_stat_br(proc, thread, cmd);
                binder_debug(BINDER_DEBUG_USER_REFS,
                        "%d:%d %s %d u%016llx c%016llx\n",
                        proc->pid, thread->pid, cmd_name,
                        node->debug_id,
                        (u64)node->ptr, (u64)node->cookie);
            } else {/*不需要增加/减少binder_node的强/弱引用计数*/
                list_del_init(&w->entry);/*从todo队列中移出*/
                if (!weak && !strong) {/*binder_node的强弱引用计数都为0,释放该binder_node*/
                    binder_debug(BINDER_DEBUG_INTERNAL_REFS,
                            "%d:%d node %d u%016llx c%016llx deleted\n",
                            proc->pid, thread->pid,
                            node->debug_id,
                            (u64)node->ptr,
                            (u64)node->cookie);
                    rb_erase(&node->rb_node, &proc->nodes);/*从proc->nodes红黑树中移除*/
                    kfree(node);/*释放binder_node所占内存空间*/
                    binder_stats_deleted(BINDER_STAT_NODE);/*更新统计数据*/
                } else {
                    binder_debug(BINDER_DEBUG_INTERNAL_REFS,
                            "%d:%d node %d u%016llx c%016llx state unchanged\n",
                            proc->pid, thread->pid,
                            node->debug_id,
                            (u64)node->ptr,
                            (u64)node->cookie);
                }
            }
        } break;
        /*binder service死亡相关的几个命令处理*/
        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);/*根据偏移计算出包含它的binder_ref_death对象的地址*/
            if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)/*死亡通知清理完毕的消息*/
                cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;/*回复命令设为BR_CLEAR_DEATH_NOTIFICATION,告知用户进程清除通知完毕的相关处理已完成*/
            else
                cmd = BR_DEAD_BINDER;/*告诉用户进程,binder service已经死亡*/
            if (put_user(cmd, (uint32_t __user *)ptr))  /*将命令发送给用户*/
                return -EFAULT;
            ptr += sizeof(uint32_t);
            if (put_user(death->cookie,
                    (binder_uintptr_t __user *)ptr))/*客户端对象(BpBinder)对应的地址发送到用户进程*/
                return -EFAULT;
            ptr += sizeof(binder_uintptr_t);
            binder_stat_br(proc, thread, cmd);
            binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
                    "%d:%d %s %016llx\n",
                    proc->pid, thread->pid,
                    cmd == BR_DEAD_BINDER ?
                    "BR_DEAD_BINDER" :
                    "BR_CLEAR_DEATH_NOTIFICATION_DONE",
                    (u64)death->cookie);
            if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION) {
                list_del(&w->entry);
                kfree(death);
                binder_stats_deleted(BINDER_STAT_DEATH);
            } else
            /*`BINDER_WORK_DEAD_BINDER`和`BINDER_WORK_DEAD_BINDER_AND_CLEAR`移到proc->delivered_deat队列*/
                list_move(&w->entry, &proc->delivered_death);
            if (cmd == BR_DEAD_BINDER)
                goto done; /* DEAD_BINDER notifications can cause transactions */
        } break;
        }//end of switch
    /*当binder_work的类型是BINDER_WORK_TRANSACTION时,t不为NULL*/
        if (!t)
            continue;
    /*接下来开始处理**TRANSACTION**,将binder_transaction转换为进程用户态使用的binder_transaction_data*/
        BUG_ON(t->buffer == NULL);
        /* 在binder_transaction章节中我们知道,当binder客户端向binder服务端发送请求时,
        * target_node为binder服务端的binder_node地址,如果是binder服务端回复客户端,则target_node为NULL。
        */
        if (t->buffer->target_node) {/*Client->Server的binder请求*/
            struct binder_node *target_node = t->buffer->target_node;
    /*将引用计数器地址及BBinder地址写入transaction data中, 即将struct binder_transaction转化为进程用户态可处理struct binder_transaction_data结构体*/
            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 {/*Client->Server的binder请求的回复*/
            /* 将引用计数器地址及BBinder地址从transaction data清空,
            * 因为Client无法从地址中获取相应的对象,这个地址只有在服务端的进程的地址空间才有效。
            */
            tr.target.ptr = 0;
            tr.cookie = 0;
            cmd = BR_REPLY;
        }
        tr.code = t->code;/*设置transacton的业务代码,一种代码对应一种binder server提供的服务*/
        tr.flags = t->flags;/*设置transacton的标识位*/
        tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);/*请求线程的有eudi*/
    /*设置发送端进程id*/
        if (t->from) {
            struct task_struct *sender = t->from->proc->tsk;
            tr.sender_pid = task_tgid_nr_ns(sender,
                            task_active_pid_ns(current));
        } else {
            tr.sender_pid = 0;
        }
    /*数据相关信息*/
        tr.data_size = t->buffer->data_size;     /*数据大小*/
        tr.offsets_size = t->buffer->offsets_size; /*offsets区大小*/
        /*将binder_transaction_data中数据指针直接转换成binder_buffer映射到用户态地址,**这样就无需再从内核态拷贝到用户态的操作了***/
        tr.**data.ptr.buffer** = (binder_uintptr_t)( 
                    (uintptr_t)t->buffer->data +
                    proc->user_buffer_offset);
        /*将binder_transaction_data的offset区地址设置为binder_buffer中相应的offset区用户态地址*/
        tr.data.ptr.offsets = tr.data.ptr.buffer +
                    ALIGN(t->buffer->data_size,
                        sizeof(void *));
        if (**put_user(cmd, (uint32_t __user *)ptr**))/*将BINDER_TRANACTION或者BINDER_REPLEY命令发送到进程用户态*/
            return -EFAULT;
        ptr += sizeof(uint32_t);
        if (copy_to_user(ptr, &tr, sizeof(tr)))/*将binder_transaction_data拷贝到进程用户态*/
            return -EFAULT;
        ptr += sizeof(tr);
        trace_binder_transaction_received(t);
        binder_stat_br(proc, thread, cmd);/*更新统计数据*/
        binder_debug(BINDER_DEBUG_TRANSACTION,
                "%d:%d %s %d %d:%d, cmd %d size %zd-%zd ptr %016llx-%016llx\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,
                (u64)tr.data.ptr.buffer, (u64)tr.data.ptr.offsets);
        list_del(&t->work.entry);/*从todo队列中移除*/
        t->buffer->allow_user_free = 1; /*因为这块地址已经交给进程用户态使用了,因此运行进程释放该段地址空间*/
        if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {/*BINDER_TRANSACTION*/
            /*加入事务栈*/
            t->to_parent = thread->transaction_stack;
            t->to_thread = thread;
            thread->transaction_stack = t;
        } else {/*BINDER_REPLY*/
            /*一次binder通信已完成,释放binder_transaction*/
            t->buffer->transaction = NULL;
            kfree(t);
            binder_stats_deleted(BINDER_STAT_TRANSACTION);/*更新被删除相关的统计数据*/
        }
        **break;/*处理完一个BINDER_WORK_TRANSACTION,就退出循环。说明对于BINDER_WORK_TRANSACTION每次至多只处理一个*/**
    }//end while
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 */) {
        /* 没有可用的binder线程,且之前已经进入到BINDER_LOOPER_STATE_REGISTERED
        * 或者BINDER_LOOPER_STATE_ENTERED状态启动一个新的binder线程 */
        proc->requested_threads++;
        binder_debug(BINDER_DEBUG_THREADS,
                "%d:%d BR_SPAWN_LOOPER\n",
                proc->pid, thread->pid);
        if (put_user(BR_SPAWN_LOOPER, (uint32_t __user *)buffer))
            return -EFAULT;
        binder_stat_br(proc, thread, BR_SPAWN_LOOPER);
    }
    return 0;
}
cyrushine commented 9 months ago

image