美文网首页
注册service_manager(native层)

注册service_manager(native层)

作者: 涛涛123759 | 来源:发表于2021-12-23 15:29 被阅读0次

    Android知识总结

    一、ServiceManager 服务简介

    • ServiceManager 分为 framework 层和 native 层,framework 层只是对 native 层进行了封装方便调用,图上展示的是 native 层的 ServiceManager 启动过程。

    • ServiceManager 的启动是系统在开机时,init 进程解析 init.rc 文件调用 service_manager.c 中的 main() 方法入口启动的。 native 层有一个 binder.c 封装了一些与 Binder 驱动交互的方法。

    • ServiceManager 的启动分为三步,首先打开驱动创建全局链表 binder_procs,然后将自己当前进程信息保存到 binder_procs 链表,最后开启 loop 不断的处理共享内存中的数据,并处理 BR_xxx 命令(ioctl 的命令,BR 可以理解为 binder reply 驱动处理完的响应)。

    • ServiceManager 其实就是对server (AMS)的 IBinder 对象的管理。如:AMS 会把 AMS-iBinder 对象注册到 SM 中,然后 Client 后从SM 中拿到 AMS-iBinder 对象和AMS尽行通信。

    二、注册 service_manager 服务

    2.1、启动ServiceManager进程

    ServiceManager是由init进程通过解析init.rc文件而创建的,其所对应的可执行程序servicemanager,所对应的源文件是service_manager.c,进程名为servicemanager。
    system/core/rootdir/init.rc

    service servicemanager /system/bin/servicemanager
        class core
        user system
        group system
        critical
        onrestart restart healthd
        onrestart restart zygote
        onrestart restart media
        onrestart restart surfaceflinger
        onrestart restart drm
    

    2.2、main

    启动ServiceManager的入口函数是 service_manager.c 中的main()方法。
    frameworks/native/cmds/servicemanager/service_manager.c

    int main(int argc, char **argv)
    {
        struct binder_state *bs;
        //打开 binder驱动,申请 128k字节大小的内存空间
        bs = binder_open(128*1024);
        if (!bs) {
            ALOGE("failed to open binder driver\n");
            return -1;
        }
        //设为守护进程,成为 binder大管理者
        if (binder_become_context_manager(bs)) {
            ALOGE("cannot become context manager (%s)\n", strerror(errno));
            return -1;
        }
    
        selinux_enabled = is_selinux_enabled();
        sehandle = selinux_android_service_context_handle();
        selinux_status_open(true);
    
        if (selinux_enabled > 0) {
            if (sehandle == NULL) {
                ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
                abort();
            }
    
            if (getcon(&service_manager_context) != 0) {
                ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
                abort();
            }
        }
    
        union selinux_callback cb;
        cb.func_audit = audit_callback;
        selinux_set_callback(SELINUX_CB_AUDIT, cb);
        cb.func_log = selinux_log_callback;
        selinux_set_callback(SELINUX_CB_LOG, cb);
        //进入无限循环,处理client端发来的请求
        binder_loop(bs, svcmgr_handler);
    
        return 0;
    }
    
    • 1、binder_open
      frameworks/native/cmds/servicemanager/binder.c
    struct binder_state *binder_open(size_t mapsize)
    {
        //这个结构体记录了 service_manager 中有关于 binder 的所有信息
        struct binder_state *bs;
        struct binder_version vers;
        //申请内存空间
        bs = malloc(sizeof(*bs));
        if (!bs) {
            errno = ENOMEM;
            return NULL;
        }
        //打开 binder驱动,得到文件描述符
        bs->fd = open("/dev/binder", O_RDWR);
        if (bs->fd < 0) {
            fprintf(stderr,"binder: cannot open device (%s)\n",
                    strerror(errno));
            goto fail_open;
        }
    
        if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
            (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
            fprintf(stderr,
                    "binder: kernel driver version (%d) differs from user space version (%d)\n",
                    vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
            goto fail_open;
        }
        //service_manager自己设置的,大小为 128kb
        bs->mapsize = mapsize;
        //通过系统调用,mmap内存映射,mmap必须是 page的整数倍(即 4kb的整数倍)
        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;
    }
    
    • 2、binder_become_context_manager
      frameworks/native/cmds/servicemanager/binder.c
    int binder_become_context_manager(struct binder_state *bs){
        return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
    }
    
    • binder_ioctl
      frameworks/native/cmds/servicemanager/binder.c
    static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
    {
        int ret;
        struct binder_proc *proc = filp->private_data;
        struct binder_thread *thread;
        unsigned int size = _IOC_SIZE(cmd);
        void __user *ubuf = (void __user *)arg;
    
        /*pr_info("binder_ioctl: %d:%d %x %lx\n",
                proc->pid, current->pid, cmd, arg);*/
    
        trace_binder_ioctl(cmd, arg);
    
        ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
        if (ret)
            goto err_unlocked;
    
        binder_lock(__func__);
        thread = binder_get_thread(proc);
        if (thread == NULL) {
            ret = -ENOMEM;
            goto err;
        }
    
        switch (cmd) {
        case BINDER_WRITE_READ:
            // binder_write
            ret = binder_ioctl_write_read(filp, cmd, arg, thread);
            if (ret)
                goto err;
            break;
        case BINDER_SET_MAX_THREADS:
            if (copy_from_user(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
                ret = -EINVAL;
                goto err;
            }
            break;
        case BINDER_SET_CONTEXT_MGR:
            // 2 ioctl
            ret = binder_ioctl_set_ctx_mgr(filp);
            if (ret)
                goto err;
            break;
        case BINDER_THREAD_EXIT:
            binder_debug(BINDER_DEBUG_THREADS, "%d:%d exit\n",
                     proc->pid, thread->pid);
            binder_free_thread(proc, thread);
            thread = NULL;
            break;
        case BINDER_VERSION: {
            struct binder_version __user *ver = ubuf;
    
            if (size != sizeof(struct binder_version)) {
                ret = -EINVAL;
                goto err;
            }
            if (put_user(BINDER_CURRENT_PROTOCOL_VERSION,
                     &ver->protocol_version)) {
                ret = -EINVAL;
                goto err;
            }
            break;
        }
        default:
            ret = -EINVAL;
            goto err;
        }
        ret = 0;
    err:
        if (thread)
            thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
        binder_unlock(__func__);
        wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
        if (ret && ret != -ERESTARTSYS)
            pr_info("%d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
    err_unlocked:
        trace_binder_ioctl_done(ret);
        return ret;
    }
    
    • binder_ioctl_set_ctx_mgr
    static int binder_ioctl_set_ctx_mgr(struct file *filp){
        int ret = 0;
        struct binder_proc *proc = filp->private_data;
        struct binder_context *context = proc->context;
    
        kuid_t curr_euid = current_euid();
        //保证只创建一次 mgr_node对象,不为 null就直接返回
        if (context->binder_context_mgr_node) {
            pr_err("BINDER_SET_CONTEXT_MGR already set\n");
            ret = -EBUSY;
            goto out;
        }
        ret = security_binder_set_context_mgr(proc->tsk);
        if (ret < 0)
            goto out;
        //uid是否有效,当前是无效的
        if (uid_valid(context->binder_context_mgr_uid)) {
            if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {
                pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
                       from_kuid(&init_user_ns, curr_euid),
                       from_kuid(&init_user_ns,
                         context->binder_context_mgr_uid));
                ret = -EPERM;
                goto out;
            }
        } else {
            //设置当前线程 euid作为 service_manager的 uid
            context->binder_context_mgr_uid = curr_euid;
        }
        //创建 service_manager实体
        context->binder_context_mgr_node = binder_new_node(proc, 0, 0);
        if (!context->binder_context_mgr_node) {
            ret = -ENOMEM;
            goto out;
        }
        //将 binder_context_mgr_node的强弱引用各加 1
        context->binder_context_mgr_node->local_weak_refs++;
        context->binder_context_mgr_node->local_strong_refs++;
        context->binder_context_mgr_node->has_strong_ref = 1;
        context->binder_context_mgr_node->has_weak_ref = 1;
    out:
        return ret;
    }
    
    • binder_new_node
    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;
        }
        //给新创建的binder_node 分配内核空间
        node = kzalloc(sizeof(*node), GFP_KERNEL);
        if (node == NULL)
            return NULL;
        binder_stats_created(BINDER_STAT_NODE);
        //将新创建的 node对象添加到 proc红黑树
        rb_link_node(&node->rb_node, parent, p);
        rb_insert_color(&node->rb_node, &proc->nodes);
        node->debug_id = ++binder_last_id;
        //初始化 binder_node
        node->proc = proc;
        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;
    }
    
    • 3、binder_loop
      frameworks/native/cmds/servicemanager/binder.c
    void binder_loop(struct binder_state *bs, binder_handler func)
    {
        int res;
        struct binder_write_read bwr;
        uint32_t readbuf[32];
        // 初始化为 0
        bwr.write_size = 0;
        bwr.write_consumed = 0;
        bwr.write_buffer = 0;
        // 读写要处理的命令
        readbuf[0] = BC_ENTER_LOOPER;
        // 设置线程的 looper状态为循环状态
        binder_write(bs, readbuf, sizeof(uint32_t));
    
        for (;;) {
            bwr.read_size = sizeof(readbuf);
            bwr.read_consumed = 0;
            bwr.read_buffer = (uintptr_t) readbuf;
            //不断地 binder读数据,没有数据会进入休眠状态
            res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    
            if (res < 0) {
                ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
                break;
            }
    
            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;
            }
        }
    }
    
    • binder_write
    int binder_write(struct binder_state *bs, void *data, size_t len)
    {
        struct binder_write_read bwr;
        int res;
        // 大于 0,进入 binder_thread_write
        bwr.write_size = len;
        bwr.write_consumed = 0;
        // 此处 data为 BC_ENTER_LOOPER
        bwr.write_buffer = (uintptr_t) data;
        // read 不会进去
        bwr.read_size = 0;
        bwr.read_consumed = 0;
        bwr.read_buffer = 0;
        //设置线程的 looper状态为循环状态
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        if (res < 0) {
            fprintf(stderr,"binder_write: ioctl failed (%s)\n",
                    strerror(errno));
        }
        return res;
    }
    

    然后binder_ioctl的方法见上,这里就不展示了

    • binder_ioctl_write_read
      frameworks/native/cmds/servicemanager/binder.c
    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;
        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;
        }
        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);
    
        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) {
                bwr.read_consumed = 0;
                if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
                    ret = -EFAULT;
                goto out;
            }
        }
        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);
            if (!list_empty(&proc->todo))
                wake_up_interruptible(&proc->wait);
            if (ret < 0) {
                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);
        if (copy_to_user(ubuf, &bwr, sizeof(bwr))) {
            ret = -EFAULT;
            goto out;
        }
    out:
        return ret;
    }
    
    • binder_thread_write
      frameworks/native/cmds/servicemanager/binder.c
    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;
        struct binder_context *context = proc->context;
        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) {
            //获取命令,即 BC_ENTER_LOOPER
            if (get_user(cmd, (uint32_t __user *)ptr))
                return -EFAULT;
            ptr += sizeof(uint32_t);
            trace_binder_command(cmd);
            if (_IOC_NR(cmd) < ARRAY_SIZE(binder_stats.bc)) {
                binder_stats.bc[_IOC_NR(cmd)]++;
                proc->stats.bc[_IOC_NR(cmd)]++;
                thread->stats.bc[_IOC_NR(cmd)]++;
            }
            switch (cmd) {
            case BC_INCREFS:
            case BC_ACQUIRE:
            case BC_RELEASE:
            case BC_DECREFS: {
                uint32_t target;
                struct binder_ref *ref;
                const char *debug_string;
    
                if (get_user(target, (uint32_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(uint32_t);
                if (target == 0 && context->binder_context_mgr_node &&
                    (cmd == BC_INCREFS || cmd == BC_ACQUIRE)) {
                    ref = binder_get_ref_for_node(proc,
                        context->binder_context_mgr_node);
                    if (ref->desc != target) {
                        binder_user_error("%d:%d tried to acquire reference to desc 0, got %d instead\n",
                            proc->pid, thread->pid,
                            ref->desc);
                    }
                } else
                    ref = binder_get_ref(proc, target,
                                 cmd == BC_ACQUIRE ||
                                 cmd == BC_RELEASE);
                if (ref == NULL) {
                    binder_user_error("%d:%d refcount change on invalid ref %d\n",
                        proc->pid, thread->pid, target);
                    break;
                }
                switch (cmd) {
                case BC_INCREFS:
                    debug_string = "IncRefs";
                    binder_inc_ref(ref, 0, NULL);
                    break;
                case BC_ACQUIRE:
                    debug_string = "Acquire";
                    binder_inc_ref(ref, 1, NULL);
                    break;
                case BC_RELEASE:
                    debug_string = "Release";
                    binder_dec_ref(ref, 1);
                    break;
                case BC_DECREFS:
                default:
                    debug_string = "DecRefs";
                    binder_dec_ref(ref, 0);
                    break;
                }
                binder_debug(BINDER_DEBUG_USER_REFS,
                         "%d:%d %s ref %d desc %d s %d w %d for node %d\n",
                         proc->pid, thread->pid, debug_string, ref->debug_id,
                         ref->desc, ref->strong, ref->weak, ref->node->debug_id);
                break;
            }
            case BC_INCREFS_DONE:
            case BC_ACQUIRE_DONE: {
                binder_uintptr_t node_ptr;
                binder_uintptr_t cookie;
                struct binder_node *node;
    
                if (get_user(node_ptr, (binder_uintptr_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(binder_uintptr_t);
                if (get_user(cookie, (binder_uintptr_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(binder_uintptr_t);
                node = binder_get_node(proc, node_ptr);
                if (node == NULL) {
                    binder_user_error("%d:%d %s u%016llx no match\n",
                        proc->pid, thread->pid,
                        cmd == BC_INCREFS_DONE ?
                        "BC_INCREFS_DONE" :
                        "BC_ACQUIRE_DONE",
                        (u64)node_ptr);
                    break;
                }
                if (cookie != node->cookie) {
                    binder_user_error("%d:%d %s u%016llx node %d cookie mismatch %016llx != %016llx\n",
                        proc->pid, thread->pid,
                        cmd == BC_INCREFS_DONE ?
                        "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
                        (u64)node_ptr, node->debug_id,
                        (u64)cookie, (u64)node->cookie);
                    break;
                }
                if (cmd == BC_ACQUIRE_DONE) {
                    if (node->pending_strong_ref == 0) {
                        binder_user_error("%d:%d BC_ACQUIRE_DONE node %d has no pending acquire request\n",
                            proc->pid, thread->pid,
                            node->debug_id);
                        break;
                    }
                    node->pending_strong_ref = 0;
                } else {
                    if (node->pending_weak_ref == 0) {
                        binder_user_error("%d:%d BC_INCREFS_DONE node %d has no pending increfs request\n",
                            proc->pid, thread->pid,
                            node->debug_id);
                        break;
                    }
                    node->pending_weak_ref = 0;
                }
                binder_dec_node(node, cmd == BC_ACQUIRE_DONE, 0);
                binder_debug(BINDER_DEBUG_USER_REFS,
                         "%d:%d %s node %d ls %d lw %d\n",
                         proc->pid, thread->pid,
                         cmd == BC_INCREFS_DONE ? "BC_INCREFS_DONE" : "BC_ACQUIRE_DONE",
                         node->debug_id, node->local_strong_refs, node->local_weak_refs);
                break;
            }
            case BC_ATTEMPT_ACQUIRE:
                pr_err("BC_ATTEMPT_ACQUIRE not supported\n");
                return -EINVAL;
            case BC_ACQUIRE_RESULT:
                pr_err("BC_ACQUIRE_RESULT not supported\n");
                return -EINVAL;
    
            case BC_FREE_BUFFER: {
                binder_uintptr_t data_ptr;
                struct binder_buffer *buffer;
    
                if (get_user(data_ptr, (binder_uintptr_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(binder_uintptr_t);
    
                buffer = binder_buffer_lookup(proc, data_ptr);
                if (buffer == NULL) {
                    binder_user_error("%d:%d BC_FREE_BUFFER u%016llx no match\n",
                        proc->pid, thread->pid, (u64)data_ptr);
                    break;
                }
                if (!buffer->allow_user_free) {
                    binder_user_error("%d:%d BC_FREE_BUFFER u%016llx matched unreturned buffer\n",
                        proc->pid, thread->pid, (u64)data_ptr);
                    break;
                }
                binder_debug(BINDER_DEBUG_FREE_BUFFER,
                         "%d:%d BC_FREE_BUFFER u%016llx found buffer %d for %s transaction\n",
                         proc->pid, thread->pid, (u64)data_ptr,
                         buffer->debug_id,
                         buffer->transaction ? "active" : "finished");
    
                if (buffer->transaction) {
                    buffer->transaction->buffer = NULL;
                    buffer->transaction = NULL;
                }
                if (buffer->async_transaction && buffer->target_node) {
                    BUG_ON(!buffer->target_node->has_async_transaction);
                    if (list_empty(&buffer->target_node->async_todo))
                        buffer->target_node->has_async_transaction = 0;
                    else
                        list_move_tail(buffer->target_node->async_todo.next, &thread->todo);
                }
                trace_binder_transaction_buffer_release(buffer);
                binder_transaction_buffer_release(proc, buffer, NULL);
                binder_free_buf(proc, buffer);
                break;
            }
    
            case BC_TRANSACTION_SG:
            case BC_REPLY_SG: {
                struct binder_transaction_data_sg tr;
    
                if (copy_from_user(&tr, ptr, sizeof(tr)))
                    return -EFAULT;
                ptr += sizeof(tr);
                binder_transaction(proc, thread, &tr.transaction_data,
                           cmd == BC_REPLY_SG, tr.buffers_size);
                break;
            }
            case BC_TRANSACTION:
            case BC_REPLY: {
                struct binder_transaction_data tr;
    
                if (copy_from_user(&tr, ptr, sizeof(tr)))
                    return -EFAULT;
                ptr += sizeof(tr);
                binder_transaction(proc, thread, &tr,
                           cmd == BC_REPLY, 0);
                break;
            }
    
            case BC_REGISTER_LOOPER:
                binder_debug(BINDER_DEBUG_THREADS,
                         "%d:%d BC_REGISTER_LOOPER\n",
                         proc->pid, thread->pid);
                if (thread->looper & BINDER_LOOPER_STATE_ENTERED) {
                    thread->looper |= BINDER_LOOPER_STATE_INVALID;
                    binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called after BC_ENTER_LOOPER\n",
                        proc->pid, thread->pid);
                } else if (proc->requested_threads == 0) {
                    thread->looper |= BINDER_LOOPER_STATE_INVALID;
                    binder_user_error("%d:%d ERROR: BC_REGISTER_LOOPER called without request\n",
                        proc->pid, thread->pid);
                } else {
                    proc->requested_threads--;
                    proc->requested_threads_started++;
                }
                thread->looper |= BINDER_LOOPER_STATE_REGISTERED;
                break;
            case BC_ENTER_LOOPER:
                //设置该线程的 looper状态
                binder_debug(BINDER_DEBUG_THREADS,
                         "%d:%d BC_ENTER_LOOPER\n",
                         proc->pid, thread->pid);
                if (thread->looper & BINDER_LOOPER_STATE_REGISTERED) {
                    thread->looper |= BINDER_LOOPER_STATE_INVALID;
                    binder_user_error("%d:%d ERROR: BC_ENTER_LOOPER called after BC_REGISTER_LOOPER\n",
                        proc->pid, thread->pid);
                }
                thread->looper |= BINDER_LOOPER_STATE_ENTERED;
                break;
            case BC_EXIT_LOOPER:
                binder_debug(BINDER_DEBUG_THREADS,
                         "%d:%d BC_EXIT_LOOPER\n",
                         proc->pid, thread->pid);
                thread->looper |= BINDER_LOOPER_STATE_EXITED;
                break;
    
            case BC_REQUEST_DEATH_NOTIFICATION:
            case BC_CLEAR_DEATH_NOTIFICATION: {
                uint32_t target;
                binder_uintptr_t cookie;
                struct binder_ref *ref;
                struct binder_ref_death *death;
    
                if (get_user(target, (uint32_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(uint32_t);
                if (get_user(cookie, (binder_uintptr_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(binder_uintptr_t);
                ref = binder_get_ref(proc, target, false);
                if (ref == NULL) {
                    binder_user_error("%d:%d %s invalid ref %d\n",
                        proc->pid, thread->pid,
                        cmd == BC_REQUEST_DEATH_NOTIFICATION ?
                        "BC_REQUEST_DEATH_NOTIFICATION" :
                        "BC_CLEAR_DEATH_NOTIFICATION",
                        target);
                    break;
                }
    
                binder_debug(BINDER_DEBUG_DEATH_NOTIFICATION,
                         "%d:%d %s %016llx ref %d desc %d s %d w %d for node %d\n",
                         proc->pid, thread->pid,
                         cmd == BC_REQUEST_DEATH_NOTIFICATION ?
                         "BC_REQUEST_DEATH_NOTIFICATION" :
                         "BC_CLEAR_DEATH_NOTIFICATION",
                         (u64)cookie, ref->debug_id, ref->desc,
                         ref->strong, ref->weak, ref->node->debug_id);
    
                if (cmd == BC_REQUEST_DEATH_NOTIFICATION) {
                    if (ref->death) {
                        binder_user_error("%d:%d BC_REQUEST_DEATH_NOTIFICATION death notification already set\n",
                            proc->pid, thread->pid);
                        break;
                    }
                    death = kzalloc(sizeof(*death), GFP_KERNEL);
                    if (death == NULL) {
                        thread->return_error = BR_ERROR;
                        binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
                                 "%d:%d BC_REQUEST_DEATH_NOTIFICATION failed\n",
                                 proc->pid, thread->pid);
                        break;
                    }
                    binder_stats_created(BINDER_STAT_DEATH);
                    INIT_LIST_HEAD(&death->work.entry);
                    death->cookie = cookie;
                    ref->death = death;
                    if (ref->node->proc == NULL) {
                        ref->death->work.type = BINDER_WORK_DEAD_BINDER;
                        if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
                            list_add_tail(&ref->death->work.entry, &thread->todo);
                        } else {
                            list_add_tail(&ref->death->work.entry, &proc->todo);
                            wake_up_interruptible(&proc->wait);
                        }
                    }
                } else {
                    if (ref->death == NULL) {
                        binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification not active\n",
                            proc->pid, thread->pid);
                        break;
                    }
                    death = ref->death;
                    if (death->cookie != cookie) {
                        binder_user_error("%d:%d BC_CLEAR_DEATH_NOTIFICATION death notification cookie mismatch %016llx != %016llx\n",
                            proc->pid, thread->pid,
                            (u64)death->cookie,
                            (u64)cookie);
                        break;
                    }
                    ref->death = NULL;
                    if (list_empty(&death->work.entry)) {
                        death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
                        if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
                            list_add_tail(&death->work.entry, &thread->todo);
                        } else {
                            list_add_tail(&death->work.entry, &proc->todo);
                            wake_up_interruptible(&proc->wait);
                        }
                    } else {
                        BUG_ON(death->work.type != BINDER_WORK_DEAD_BINDER);
                        death->work.type = BINDER_WORK_DEAD_BINDER_AND_CLEAR;
                    }
                }
            } break;
            case BC_DEAD_BINDER_DONE: {
                struct binder_work *w;
                binder_uintptr_t cookie;
                struct binder_ref_death *death = NULL;
    
                if (get_user(cookie, (binder_uintptr_t __user *)ptr))
                    return -EFAULT;
    
                ptr += sizeof(cookie);
                list_for_each_entry(w, &proc->delivered_death, entry) {
                    struct binder_ref_death *tmp_death = container_of(w, struct binder_ref_death, work);
    
                    if (tmp_death->cookie == cookie) {
                        death = tmp_death;
                        break;
                    }
                }
                binder_debug(BINDER_DEBUG_DEAD_BINDER,
                         "%d:%d BC_DEAD_BINDER_DONE %016llx found %p\n",
                         proc->pid, thread->pid, (u64)cookie,
                         death);
                if (death == NULL) {
                    binder_user_error("%d:%d BC_DEAD_BINDER_DONE %016llx not found\n",
                        proc->pid, thread->pid, (u64)cookie);
                    break;
                }
    
                list_del_init(&death->work.entry);
                if (death->work.type == BINDER_WORK_DEAD_BINDER_AND_CLEAR) {
                    death->work.type = BINDER_WORK_CLEAR_DEATH_NOTIFICATION;
                    if (thread->looper & (BINDER_LOOPER_STATE_REGISTERED | BINDER_LOOPER_STATE_ENTERED)) {
                        list_add_tail(&death->work.entry, &thread->todo);
                    } else {
                        list_add_tail(&death->work.entry, &proc->todo);
                        wake_up_interruptible(&proc->wait);
                    }
                }
            } break;
    
            default:
                pr_err("%d:%d unknown command %d\n",
                       proc->pid, thread->pid, cmd);
                return -EINVAL;
            }
            *consumed = ptr - buffer;
        }
        return 0;
    }
    
    • binder_thread_read
      frameworks/native/cmds/servicemanager/binder.c
    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
        if (*consumed == 0) {
            if (put_user(BR_NOOP, (uint32_t __user *)ptr))
                return -EFAULT;
            ptr += sizeof(uint32_t);
        }
    
    retry:
        wait_for_proc_work = thread->transaction_stack == NULL &&
                    list_empty(&thread->todo);
    
        if (thread->return_error != BR_OK && ptr < end) {
            if (thread->return_error2 != BR_OK) {
                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;
        }
    
    
        thread->looper |= BINDER_LOOPER_STATE_WAITING;
        //准备就绪的线程个数加 1
        if (wait_for_proc_work)
            proc->ready_threads++;
    
        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_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);
            // 非阻塞操作,service_manager是阻塞的,所以 if不命中
            if (non_block) {
                if (!binder_has_proc_work(proc, thread))
                    ret = -EAGAIN;
            } else
            // 进入 else,开始等待
                ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
        } else {
            if (non_block) {
                if (!binder_has_thread_work(thread))
                    ret = -EAGAIN;
            } else
                ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
        }
    
        binder_lock(__func__);
    
        if (wait_for_proc_work)
            proc->ready_threads--;
        thread->looper &= ~BINDER_LOOPER_STATE_WAITING;
    
        if (ret)
            return ret;
    
        while (1) {
            uint32_t cmd;
            struct binder_transaction_data tr;
            struct binder_work *w;
            struct binder_transaction *t = NULL;
    
            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) {
                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: {
                t = container_of(w, struct binder_transaction, work);
            } break;
            case BINDER_WORK_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);
                kfree(w);
                binder_stats_deleted(BINDER_STAT_TRANSACTION_COMPLETE);
            } break;
            case BINDER_WORK_NODE: {
                struct binder_node *node = container_of(w, struct binder_node, work);
                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) {
                    cmd = BR_INCREFS;
                    cmd_name = "BR_INCREFS";
                    node->has_weak_ref = 1;
                    node->pending_weak_ref = 1;
                    node->local_weak_refs++;
                } else if (strong && !node->has_strong_ref) {
                    cmd = BR_ACQUIRE;
                    cmd_name = "BR_ACQUIRE";
                    node->has_strong_ref = 1;
                    node->pending_strong_ref = 1;
                    node->local_strong_refs++;
                } else if (!strong && node->has_strong_ref) {
                    cmd = BR_RELEASE;
                    cmd_name = "BR_RELEASE";
                    node->has_strong_ref = 0;
                } else if (!weak && node->has_weak_ref) {
                    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);
                    if (put_user(node->ptr,
                             (binder_uintptr_t __user *)ptr))
                        return -EFAULT;
                    ptr += sizeof(binder_uintptr_t);
                    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 {
                    list_del_init(&w->entry);
                    if (!weak && !strong) {
                        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);
                        kfree(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;
            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);
                if (w->type == BINDER_WORK_CLEAR_DEATH_NOTIFICATION)
                    cmd = BR_CLEAR_DEATH_NOTIFICATION_DONE;
                else
                    cmd = BR_DEAD_BINDER;
                if (put_user(cmd, (uint32_t __user *)ptr))
                    return -EFAULT;
                ptr += sizeof(uint32_t);
                if (put_user(death->cookie,
                         (binder_uintptr_t __user *)ptr))
                    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
                    list_move(&w->entry, &proc->delivered_death);
                if (cmd == BR_DEAD_BINDER)
                    goto done; /* DEAD_BINDER notifications can cause transactions */
            } break;
            }
    
            if (!t)
                continue;
    
            BUG_ON(t->buffer == NULL);
            if (t->buffer->target_node) {
                struct binder_node *target_node = t->buffer->target_node;
    
                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 {
                tr.target.ptr = 0;
                tr.cookie = 0;
                cmd = BR_REPLY;
            }
            tr.code = t->code;
            tr.flags = t->flags;
            tr.sender_euid = from_kuid(current_user_ns(), t->sender_euid);
    
            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;
            tr.data.ptr.buffer = (binder_uintptr_t)(
                        (uintptr_t)t->buffer->data +
                        proc->user_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))
                return -EFAULT;
            ptr += sizeof(uint32_t);
            if (copy_to_user(ptr, &tr, sizeof(tr)))
                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);
            t->buffer->allow_user_free = 1;
            if (cmd == BR_TRANSACTION && !(t->flags & TF_ONE_WAY)) {
                t->to_parent = thread->transaction_stack;
                t->to_thread = thread;
                thread->transaction_stack = t;
            } else {
                t->buffer->transaction = NULL;
                kfree(t);
                binder_stats_deleted(BINDER_STAT_TRANSACTION);
            }
            break;
        }
    
    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 */) {
            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;
    }
    

    三、总结

    根据上面分析 SM 注册完成主要进行下面三个步骤

    • 1、打开 binder驱动,映射内存;
    • 2、设为守护进程,设置SM为大管家并成为 binder 的大管理者(为了管理系统服务);
      1)、创建 binder_node 结构体对象
      2)、proc --> binder_node
      3)、创建 work 和 todo (类似 MessageQueue)
    • 3、进入无限循环,处理client端发来的请求 (BC_ENTER_LOOPER命令)
      1)、写入状态 Loop
      2)、去读数据;ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread)) 进入等待,

    相关文章

      网友评论

          本文标题:注册service_manager(native层)

          本文链接:https://www.haomeiwen.com/subject/cinyiltx.html