binder(三) servicemanager启动

使用主要交互逻辑


int main(int argc, char **argv)
{
    struct binder_state *bs;
    // 1. binder_open
    bs = binder_open(128*1024);
    if (!bs) {
        ALOGE("failed to open binder driver\n");
        return -1;
    }
    //2. 注册成为管家
    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    //3. 循环接收数据和处理时间
    binder_loop(bs, svcmgr_handler);

    return 0;
}

  1. 打开驱动,mmap映射,binder_open
struct binder_state *binder_open(size_t mapsize)
{
    struct binder_state *bs;
    struct binder_version vers;
    
    
    bs = malloc(sizeof(*bs));
    //打开驱动 ->1.1
    bs->fd = open("/dev/binder", O_RDWR);
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }
    //检测版本号 ->1.2
    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        fprintf(stderr, "binder: driver version differs from user space\n");
        goto fail_open;
    }
    
    bs->mapsize = mapsize;
    //mmap建立映射  ->1.3
     bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
     if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }
 
    return bs;
    
fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return NULL;
}


1.1 open()对应驱动层binder_open(),主要作用是创建binder_proc

static int binder_open(struct inode *nodp, struct file *filp){
    struct binder_proc *proc;
    //初始化binder_proc赋值
    
    proc = kzalloc(sizeof(*proc), GFP_KERNEL);
    get_task_struct(current);
    proc->tsk = current;
    //初始化todo
    INIT_LIST_HEAD(&proc->todo);
    //初始化等待队列
    init_waitqueue_head(&proc->wait);
    proc->default_priority = task_nice(current);
    hlist_add_head(&proc->proc_node, &binder_procs);
    proc->pid = current->group_leader->pid;
    INIT_LIST_HEAD(&proc->delivered_death);
    //把binder_proc赋值到filp->private_data
    filp->private_data = proc;
    return 0;
}

1.2 ioctl(bs->fd, BINDER_VERSION, &vers)检测版本号,对应驱动层函数binder_ioctl()

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
    //...
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    //...
    void __user *ubuf = (void __user *)arg;
    //..
    thread = binder_get_thread(proc);
    //...
    switch (cmd) {
        //...
        case BINDER_VERSION: {
            struct binder_version __user *ver = ubuf;
            //..
            //把版本号put到ver->protocol_version
            if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
                     &ver->protocol_version)) {
                ret = -EINVAL;
                goto err;
            };
        }
    }
}

1.3 mmap对应驱动层binder_mmap ==这里不清楚,需要再次查看==


static int binder_mmap(struct file *filp, struct vm_area_struct *vma){
    int ret;
    struct vm_struct *area;
    struct binder_proc *proc = filp->private_data;
    const char *failure_string;
    struct binder_buffer *buffer;
    //...
    if ((vma->vm_end - vma->vm_start) > SZ_4M)
        vma->vm_end = vma->vm_start + SZ_4M;
    }
    //...
    area = get_vm_area(vma->vm_end - vma->vm_start, VM_IOREMAP);
    
    proc->buffer = area->addr;
    proc->user_buffer_offset = vma->vm_start - (uintptr_t)proc->buffer;
    proc->pages = kzalloc(sizeof(proc->pages[0]) * ((vma->vm_end - vma->vm_start) / PAGE_SIZE), GFP_KERNEL);
    proc->buffer_size = vma->vm_end - vma->vm_start;
    //...
    vma->vm_private_data = proc;
    list_add(&buffer->entry, &proc->buffers);
    //...
    proc->vma = vma;
    proc->vma_vm_mm = vma->vm_mm;
    return 0
}

  1. 注册成为管家
int binder_become_context_manager(struct binder_state *bs)
{   
    // 和驱动交互,交互cmd是BINDER_SET_CONTEXT_MGR,2.1
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

2.1 驱动层通过BINDER_SET_CONTEXT_MGR 找到对应执行代码块,主要是用于创建binder_context_mgr_node为名称的binder_node,binder_context_mgr_node是全局唯一的,不能被重复构建。

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    //...
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    //...
    thread = binder_get_thread(proc);
    switch (cmd) {
        //...
        case BINDER_SET_CONTEXT_MGR:
            binder_ioctl_set_ctx_mgr(filp);
            security_binder_set_context_mgr(proc->tsk);
            break;
            
        //...
    }
}


static struct binder_node *binder_context_mgr_node;

static int binder_ioctl_set_ctx_mgr(struct file *filp){
    int ret = 0;
    //...
    struct binder_proc *proc = filp->private_data;
    //...
    //判断是否已经创建binder_context_mgr_node
    if (binder_context_mgr_node != NULL) {
        pr_err("BINDER_SET_CONTEXT_MGR already set\n");
        ret = -EBUSY;
        goto out;
    }
    
    //创建service_manager binder_node -> 2.1.1
    binder_context_mgr_node = binder_new_node(proc, 0, 0)
    if (binder_context_mgr_node == NULL) {
        ret = -ENOMEM;
        goto out;
    }
    //更新相关计数
    binder_context_mgr_node->local_weak_refs++;
    binder_context_mgr_node->local_strong_refs++;
    binder_context_mgr_node->has_strong_ref = 1;
    binder_context_mgr_node->has_weak_ref = 1;
out:
    return ret;
}


2.1.1 binder_new_node主要用于创建一个新的binder_node,并把proc指向当前进程binder_proc

static struct binder_node *binder_new_node(struct binder_proc *proc,
                       binder_uintptr_t ptr,
                       binder_uintptr_t cookie)
{
    struct rb_node **p = &proc->nodes.rb_node;
    struct rb_node *parent = NULL;
    struct binder_node *node;
    
    
    while (*p) {
        parent = *p;
        node = rb_entry(parent, struct binder_node, rb_node);

        if (ptr < node->ptr)
            p = &(*p)->rb_left;
        else if (ptr > node->ptr)
            p = &(*p)->rb_right;
        else
            return NULL;
    }
    //分配内存
    node = kzalloc(sizeof(*node), GFP_KERNEL);
    if (node == NULL)
        return NULL;
    binder_stats_created(BINDER_STAT_NODE);
    rb_link_node(&node->rb_node, parent, p);
    rb_insert_color(&node->rb_node, &proc->nodes);
    node->debug_id = ++binder_last_id;
    //proc 指向当前进程binder_proc
    node->proc = proc;
    //ptr 指向具体处理的函数
    node->ptr = ptr;
    node->cookie = cookie;
    node->work.type = BINDER_WORK_NODE;
    INIT_LIST_HEAD(&node->work.entry);
    INIT_LIST_HEAD(&node->async_todo);
    binder_debug(BINDER_DEBUG_INTERNAL_REFS,
             "%d:%d node %d u%016llx c%016llx created\n",
             proc->pid, current->pid, node->debug_id,
             (u64)node->ptr, (u64)node->cookie);
    return node;
    
}

  1. binder_loop()更改looper标记,开启循环读取

//svcmgr_handler 代表一个函数
binder_loop(bs, svcmgr_handler);


void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];
    
    //构造binder_write_read和ioctl交互,进行数据交换
    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;
    //记住这个命令 BC_ENTER_LOOPER
    readbuf[0] = BC_ENTER_LOOPER;
    //通知驱动开启循环,BC_ENTER_LOOPER   ->3.1
    binder_write(bs, readbuf, sizeof(uint32_t));

    //开始读取数据
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
        
        //开始读取数据 -->3.2
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }
        //解析数据  func对应svcmgr_handler函数-->3.3
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}

3.1 binder_write,主要负责构建binder_write_read结构体,然后和驱动层交互更改looper参数

int binder_write(struct binder_state *bs, void *data, size_t len)
{
    struct binder_write_read bwr;
    int res;

    bwr.write_size = len;
    bwr.write_consumed = 0;
    //BC_ENTER_LOOPER
    bwr.write_buffer = (uintptr_t) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    //和驱动交互 3.1.1
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    if (res < 0) {
        fprintf(stderr,"binder_write: ioctl failed (%s)\n",
                strerror(errno));
    }
    return res;
}


3.1.1 ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

//cmd = BINDER_WRITE_READ
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    //arg对应binder_transation_data数据
    void __user *ubuf = (void __user *)arg;
    //...
    thread = binder_get_thread(proc);
    //...
    switch (cmd) {
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread);
            //...
            break;
            
        //...
    }
    //...
}


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;
    void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;
    //...
    //将binder_transation_data数据从用户空间拷贝到内核控件
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
    //...
    //此时write_size>0
    if (bwr.write_size > 0) {
        ret = binder_thread_write(proc, thread,
                      bwr.write_buffer,
                      bwr.write_size,
                      &bwr.write_consumed);
    
        //...
    }
    
    //把处理的数据从内核控件copy到用户空间
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
    
    //...
}

static int binder_thread_write(struct binder_proc *proc,struct binder_thread *thread,binder_uintptr_t binder_buffer, size_t size,binder_size_t *consumed){
    uint32_t cmd;
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    void __user *ptr = buffer + *consumed;
    void __user *end = buffer + size;
    while (ptr < end && thread->return_error == BR_OK) {
        //根据ptr获取具体的命令 cmd == BC_ENTER_LOOPER
        if (get_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        //...
        switch (cmd) {
            //...
            case BC_ENTER_LOOPER:
                //...
                //更改标志位,开启循环
                thread->looper |= BINDER_LOOPER_STATE_ENTERED;
                break;
            //...
        }
    
    }
    
}



3.2 ioctl(bs->fd, BINDER_WRITE_READ, &bwr);,这个时候read_size有数据了,最终走到了binder_thread_read

//cmd = BINDER_WRITE_READ
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg){
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    //arg对应binder_transation_data数据
    void __user *ubuf = (void __user *)arg;
    //...
    thread = binder_get_thread(proc);
    //...
    switch (cmd) {
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread);
            //...
            break;
            
        //...
    }
    //...
}


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;
    void __user *ubuf = (void __user *)arg;
    struct binder_write_read bwr;
    //...
    //将binder_transation_data数据从用户空间拷贝到内核控件
    if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
    //...
    //read_size>0
   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);
    
        //...
        //如果binder_proc的todo链表没有数据就等待
        if (!list_empty(&proc->todo)){
            wake_up_interruptible(&proc->wait);
        }
        if (ret < 0) {
            //如果出错 ,把最终处理的数据从内核控件copy到用户控件
            if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                ret = -EFAULT;
            goto out;
        }
        //...
    }
    //...
    //把最终处理的数据从内核控件copy到用户控件
    if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
        ret = -EFAULT;
        goto out;
    }
}



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;
    //没有数据将会进入这里,将BR_NOOP设置到ptr里面
    if (*consumed == 0) {
        if (put_user(BR_NOOP, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
    }
    //...
    //循环读取todo事物进行一些操作
    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        //获取binder_work,也就是需要执行的work
        if (!list_empty(&thread->todo)) {
        //从thread->todo取
            w = list_first_entry(&thread->todo, struct binder_work,
                         entry);
        } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
         //proc->todo取
            w = list_first_entry(&proc->todo, struct binder_work,
                         entry);
        } else{
            //...
        }
        
        
        //...
        //执行具体的事件,通过取出binder_transaction_data进行读和写操作
        switch (w->type) {
            //...
        }

    }
}

3.3 binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);,通过3.2的读操作,获取到了数据到bwr结构体里面


// func: svcmgr_handler函数
int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;
     while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        
         switch(cmd) {
            //刚开始循环,没有数据第一次进入会到这里
            case BR_NOOP:
                break;
                
            //...
            
            //  正常的收到的数据,其他端发送BC_TRANSACTION
            case BR_TRANSACTION: {
                struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
                //...
                if (func) {
                    unsigned rdata[256/4];
                    struct binder_io msg;
                    struct binder_io reply;
                    int res;
                    //将binder_transaction_data转为binder_io
                    bio_init(&reply, rdata, sizeof(rdata), 4);
                    bio_init_from_txn(&msg, txn);
                    //函数处理,也就是svcmgr_handler函数 3.3.1
                    res = func(bs, txn, &msg, &reply);
                    //发送回执
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
                ptr += sizeof(*txn);
                break;
            }
            //...
         }
    }
}

3.3.1 svcmgr_handler,主要执行service_manager服务的具体cmd操作,比如增加服务,查找服务,获取所有服务


int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;

    //ALOGI("target=%x code=%d pid=%d uid=%d\n",
    //  txn->target.handle, txn->code, txn->sender_pid, txn->sender_euid);

    if (txn->target.handle != svcmgr_handle)
        return -1;

    if (txn->code == PING_TRANSACTION)
        return 0;

    // Equivalent to Parcel::enforceInterface(), reading the RPC
    // header with the strict mode policy mask and the interface name.
    // Note that we ignore the strict_policy and don't propagate it
    // further (since we do no outbound RPCs anyway).
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    if (s == NULL) {
        return -1;
    }

    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s, len));
        return -1;
    }


    switch(txn->code) {
        case SVC_MGR_GET_SERVICE:
        case SVC_MGR_CHECK_SERVICE:
            s = bio_get_string16(msg, &len);
            if (s == NULL) {
                return -1;
            }
            //根据名称从链表查找服务handle
            handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
            if (!handle)
                break;
            bio_put_ref(reply, handle);
            return 0;
    
        case SVC_MGR_ADD_SERVICE:
            s = bio_get_string16(msg, &len);
            if (s == NULL) {
                return -1;
            }
            handle = bio_get_ref(msg);
            allow_isolated = bio_get_uint32(msg) ? 1 : 0;
            //增加服务到链表
            if (do_add_service(bs, s, len, handle, txn->sender_euid,
                allow_isolated, txn->sender_pid))
                return -1;
            break;
    
        case SVC_MGR_LIST_SERVICES: {
            uint32_t n = bio_get_uint32(msg);
    
            if (!svc_can_list(txn->sender_pid)) {
                ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
                        txn->sender_euid);
                return -1;
            }
            //获取服务列表
            si = svclist;
            while ((n-- > 0) && si)
                si = si->next;
            if (si) {
                bio_put_string16(reply, si->name);
                return 0;
            }
            return -1;
        }
        default:
            ALOGE("unknown code %d\n", txn->code);
            return -1;
        }
    
        bio_put_uint32(reply, 0);
    return 0;
}

总结:

1. open驱动,生成binder_proc结构体
2. 通过mmap建立用户控件和内核空间映射
3. 通知驱动,创建一个binder_node成为binder管理的manager_node
4. 通知驱动,更改looer标记,意味着开始循环
5. 循环读取todo链表,根据binder_work的type对binder_transation_data的数据做对应的调整,返回到用户空间
6. 用户空间根据binder_transation_data的code和参数执行不同的处理,比如增加服务和查找服务,把返回数据copy到reply里面,在通过驱动交互。

推荐阅读更多精彩内容