【android】binder机制-servicemanager

servicemanager的源码在/frameworks/base/cmds/servicemanager目录下由binder.c,binder.h,service_manager.c构成

生成servicemanager文件放在/system/bin/目录下

servicemanager的入口是在service_manager.c中的main函数

int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;	//binder service manager 句柄0

    bs = binder_open(128*1024);	//打开/dev/binder ,映射128*1024字节内存

    if (binder_become_context_manager(bs)) {	//设置本进程为binder上下文管理者
        LOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
    binder_loop(bs, svcmgr_handler);	//binder循环
    return 0;
}

一.打开/dev/binder,映射内存

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

    bs = malloc(sizeof(*bs));	//分配bs内存
    if (!bs) {
        errno = ENOMEM;
        return 0;
    }

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

    bs->mapsize = mapsize;	//设置要映射的内存大小 128*1024
    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;	//bs的fd保存了设备描述符,返回bs以便其他ioctl等操作

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return 0;
}

1.1 打开/dev/binder设备文件,会触发设备文件的open方法

static int binder_open(struct inode *nodp, struct file *filp)	//打开/dev/binder
{
	struct binder_proc *proc;

	binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",current->group_leader->pid, current->pid);//打印组领导id和进程id

	proc = kzalloc(sizeof(*proc), GFP_KERNEL);	//分配binder_proc结构体内存	
	if (proc == NULL)
		return -ENOMEM;
	get_task_struct(current);	//增加当前进程的task_struct的引用计数	
	proc->tsk = current;	//proc->tsk指向当前进程的task_struct
	INIT_LIST_HEAD(&proc->todo);	//初始化proc->todo链表头
	init_waitqueue_head(&proc->wait);	//初始化proc->wait等待队列头
	proc->default_priority = task_nice(current);	//获取当前进程的优先级 proc->default_priority
	mutex_lock(&binder_lock);		//锁定互斥锁binder_lock
	binder_stats_created(BINDER_STAT_PROC);	//binder_proc创建计数+1
	hlist_add_head(&proc->proc_node, &binder_procs);//添加proc->proc_node节点到全局binder_procs哈希链表中
	proc->pid = current->group_leader->pid;	//proc->pid等于当前进程的组领导id			
	INIT_LIST_HEAD(&proc->delivered_death);	//初始化proc->delivered_death等待队列头
	filp->private_data = proc;		//文件的私有数据指针指向proc
	mutex_unlock(&binder_lock);		//解锁互斥锁binder_lock				//解互斥锁binder_lock

	if (binder_debugfs_dir_entry_proc) {
		char strbuf[11];
		snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);	//格式化proc->pid字串到strbuf
		proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
		//创建/binder/proc/id值 文件
	}

	return 0;
}

当每次打开/dev/binder都会分配一个binder_proc结构体,并设置proc的多个成员,

初始化binder_proc->todo list链表

初始化binder_proc->wait 等待队列

添加binder_proc->proc_node到全局binder_proc哈希链表中

初始化binder_proc->delivered_death 等待队列

将filp->private_data文件的私有数据指针 指向binder_proc(以后的ioctl等操作可以使用该指针获取binder_proc)

然后根据进程id创建debugfs中/binder/proc/$pid文件

二.设置本进程为binder上下文管理者

int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);	//ioctl命令BINDER_SET_CONTEXT_MGR
}

2.1 BINDER_SET_CONTEXT_MGR命令告知设备驱动/dev/binder设置binder服务管理者

调用了/dev/binder的ioctl方法,摘录部分执行到的代码

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)	
{
	int ret;
	struct binder_proc *proc = filp->private_data;//获取binder_proc
	struct binder_thread *thread;
	unsigned int size = _IOC_SIZE(cmd);	//获取命令数据大小
	void __user *ubuf = (void __user *)arg;	//获取arg参数指针

	//等待队列binder_user_error_wait唤醒,条件是binder_stop_on_user_error错误值小于2
	ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);	
	if (ret)
		return ret;

	mutex_lock(&binder_lock);	//锁定互斥量 binder_lock
	thread = binder_get_thread(proc);	//获取binder线程
	if (thread == NULL) {
		ret = -ENOMEM;
		goto err;
	}

	switch (cmd) {
	...
	case BINDER_SET_CONTEXT_MGR:	//设置上下文管理者
		if (binder_context_mgr_node != NULL) {	//判断是否已经设置管理者
			printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR already set\n");
			ret = -EBUSY;
			goto err;
		}
		if (binder_context_mgr_uid != -1) {	//还没有设置管理者
			if (binder_context_mgr_uid != current->cred->euid) {	//不等于当前进程的有效id
				printk(KERN_ERR "binder: BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",current->cred->euid,binder_context_mgr_uid);
				ret = -EPERM;
				goto err;
			}
		} 
		else
			binder_context_mgr_uid = current->cred->euid;	//将当前进程的有效id给到全局binder_context_mgr_uid
		binder_context_mgr_node = binder_new_node(proc, NULL, NULL);	//创建上下文管理者实体
		if (binder_context_mgr_node == NULL) {
			ret = -ENOMEM;
			goto err;
		}
		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;	//有弱指针
		break;
	...
	}
	ret = 0;
err:
	if (thread)
		thread->looper &= ~BINDER_LOOPER_STATE_NEED_RETURN;
	mutex_unlock(&binder_lock);	//解锁互斥量 binder_lock
	wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);	//等待队列binder_user_error_wait唤醒
	if (ret && ret != -ERESTARTSYS)
		printk(KERN_INFO "binder: %d:%d ioctl %x %lx returned %d\n", proc->pid, current->pid, cmd, arg, ret);
	return ret;
}

先通过filp->private_data私有数据获取binder_proc结构体
2.2 接着调用binder_get_thread函数

static struct binder_thread *binder_get_thread(struct binder_proc *proc)
{
	struct binder_thread *thread = NULL;
	struct rb_node *parent = NULL;
	struct rb_node **p =
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值