Android Binder分析一:ServiceMananger的启动

这里来分析一下ServiceManager的启动过程,ServiceManager是管理系统所有服务的进程,用于提供API给用户注册以及查找相应的服务。ServiceManager直接与binder驱动打交道去实现跨进程的IPC。下面首先来看一下ServiceManager启动的地方,它是在init.rc脚本,这个脚本会被init程序解析并执行其中不同的服务。首先来看ServiceManager的启动命令:

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

上面命令会启动路径/system/bin/servicemanager下面的servicemanager可执行程序,并且这个service的名字也是servicemanager,后面会设置这个service的一些属性。可执行程序servicemanager的源文件是service_manager.c,我们来分析它的main函数:

int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
    binder_loop(bs, svcmgr_handler);
    return 0;
}

binder_state结构如下:

struct binder_state
{
    int fd;
    void *mapped;
    unsigned mapsize;
};

fd描述打开的/dev/binder文件句柄;mapped是映射到用户空间的内存起始地址;mapsize为映射内存区域的大小。BINDER_SERVICE_MANAGER在binder.h中定义为(void*) 0,因为ServiceManager在binder驱动中的hander ID为0,后面分析中我们会看到。接着调用binder_open去打开binder设备文件并映射到用户空间:

struct binder_state *binder_open(unsigned mapsize)
{
    struct binder_state *bs;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return 0;
    }

    bs->fd = open("/dev/binder", O_RDWR);
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }

    bs->mapsize = mapsize;
    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 0;
}

首先调用open方法去打开设备文件,我们到binder驱动文件中去分析,代码在kernel-3.4/drivers/staging/android/binder.c:

static const struct file_operations binder_fops = {
        .owner = THIS_MODULE,
        .poll = binder_poll,
        .unlocked_ioctl = binder_ioctl,
        .mmap = binder_mmap,
        .open = binder_open,
        .flush = binder_flush,
        .release = binder_release,
};

static struct miscdevice binder_miscdev = {
        .minor = MISC_DYNAMIC_MINOR,
        .name = "binder",
        .fops = &binder_fops
};

根据上面的定义,open和mmap方法最终会调用到file_operations里面的binder_open和binder_mmap两个函数指针。首先来看binder驱动中的binder_open方法:

static int binder_open(struct inode *nodp, struct file *filp)
{
        struct binder_proc *proc;

        proc = kzalloc(sizeof(*proc), GFP_KERNEL);
        if (proc == NULL)
                return -ENOMEM;
        get_task_struct(current);
        proc->tsk = current;
        INIT_LIST_HEAD(&proc->todo);
        init_waitqueue_head(&proc->wait);
        proc->default_priority = task_nice(current);

        binder_lock(__func__);

        binder_stats_created(BINDER_STAT_PROC);
        hlist_add_head(&proc->proc_node, &binder_procs);
        proc->pid = current->group_leader->pid;
        INIT_LIST_HEAD(&proc->delivered_death);
        filp->private_data = proc;

        binder_unlock(__func__);

        return 0;
}

binder_open首先构造一个binder_proc数据结构,binder_proc保存了打开/dev/binder设备进程的上下文信息,先来总体看一下binder_proc的结构:

struct binder_proc {
        struct hlist_node proc_node;  //用来链接所有的binder_proc到binder_procs的节点
        struct rb_root threads;       //binder threads红黑树根节点,链接当前进程上所有的binder thread
        struct rb_root nodes;         //nodes红黑树根节点,存放当前进程上所有的binder实体
        struct rb_root refs_by_desc;  //引用binder的红黑树根节点,通过decs id号来索引
        struct rb_root refs_by_node;  //引用binder的红黑树根节点,通过node来索引
        int pid;                      //当前进程的group leader的进程号
        struct vm_area_struct *vma;   //用户空间内存映射地址
        struct mm_struct *vma_vm_mm;  //内核空间内存映射地址
        struct task_struct *tsk;      //保存当前进程的task struck
        struct files_struct *files;   //保存打开的文件
        struct hlist_node deferred_work_node;  
        int deferred_work;
        void *buffer;                 //内核虚拟空间起始地址
        ptrdiff_t user_buffer_offset; //用户映射地址和内核虚拟空间地址之间的偏移

        struct list_head buffers;
        struct rb_root free_buffers;   //free buffer的红黑树根节点
        struct rb_root allocated_buffers;
        size_t free_async_space;

        struct page **pages;         //实际物理内存页面
        size_t buffer_size;          //分配的内存大小
        uint32_t buffer_free;        //剩下的free buffer
        struct list_head todo;      //待完成的事务
        wait_queue_head_t wait;     //等待信号
        struct binder_stats stats;  //当前binder的状态记录
        struct list_head delivered_death;
        int max_threads;
        int requested_threads;
        int requested_threads_started;
        int ready_threads;
        long default_priority;
        struct dentry *debugfs_entry;
};

上面的binder_open方法会去初始化binder_proc中的todo、wait等链表,并把当前binder_proc保存在/dev/binder打开文件filp的private_data中,方便以后访问。接着来看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;
        
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值