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 =