ServiceManager中的binder使用没有上层逻辑的影响,对分析binder比较直观
binder驱动注册和初始化
// 驱动函数映射
static const struct file_operations binder_fops = {
.owner = THIS_MODULE,
.poll = binder_poll,
.unlocked_ioctl = binder_ioctl,
.compat_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
};
static int binder_open(struct inode *nodp, struct file *filp){......}
static int binder_mmap(struct file *filp, struct vm_area_struct *vma){......}
static int __init binder_init(void)
{
int ret;
// 创建名为binder的单线程的工作队列
binder_deferred_workqueue = create_singlethread_workqueue("binder");
if (!binder_deferred_workqueue)
return -ENOMEM;
......
// 注册驱动,misc设备其实也就是特殊的字符设备
ret = misc_register(&binder_miscdev);
......
return ret;
}
// 驱动注册函数
device_initcall(binder_init);
主要流程:
- 通过驱动注册函数初始化binder
- 为binder创建单线程工作队列
- 注册驱动,misc设备其实也就是特殊的字符设备
驱动注册和初始化完成后,等待servicesmanager与他通信
ServiceManager启动
主要完成三个任务:
- 打开驱动,创建和初始化servicemanager对应的Binder_proc进程对象,添加到全局链表中;并申请了128k字节大小的内存空间
- 通过iotcl-binder_iotcl将自己注册为Binder机制的管理者
- 启动循环,等待并处理Client端发来的请求
rc定义
所有的系统服务都是需要在ServiceManager中进行注册的,而ServiceManager作为一个起始的服务,是通过解析init.rc,/system/bin/servicemanager来启动的调用来启动的。
#/system/core/rootdir/init.rc
import /init.environ.rc
...
# Start essential services.
start servicemanager
#\frameworks\native\cmds\servicemanager\servicemanager.rc
service servicemanager /system/bin/servicemanager
class core
user system
group system readproc
onrestart restart healthd
...
init通过解析rc文件,fork出servicemanger进程,然后执行/system/bin/servicemanager,进入入口函数:
入口程序
Binder对应的目录是/dev/binder,注册驱动时将open release mmap等系统调用注册到Binder自己的函数,这样的话在用户空间就可以通过系统调用以访问文件的方式使用Binder。下面来粗略看一下相关代码。
#\frameworks\native\cmds\servicemanager\service_manager.c
struct binder_state
{
int fd;
void *mapped;
size_t mapsize;
};
int main()
{
struct binder_state *bs;
#打开binder
bs = binder_open(128*1024);
...
//将自己注册为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);
....
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;
}
binder_open
运行在servicemanager进程
- 调用系统调用打开binder设备驱动
- iotcl判断binder版本
- 内存共享将binder设备文件映射到进程的地址空间
//frameworks\native\cmds\servicemanager\binder.c
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
//申请对应的内存空间
bs = malloc(sizeof(*bs));
//打开binder设备文件,这种属于设备驱动的操作方法
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
//通过ioctl获取binder的版本号,会调用驱动的binder_ioctl方法
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;
}
bs->mapsize = mapsize;
//mmap进行内存映射,将Binder设备文件映射到进程的对应地址空间,地址空间大小为128k
//映射之后,会将地址空间的起始地址和大小保存到结构体中,
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
return bs;
}
open(driver, O_RDWR | O_CLOEXEC)
最终会调用驱动binder.c中的binder_open方法。主要作用是是创建当前调用进程的binder_proc,赋值给打开/dev/binder获取的文件描述符的private_data
static int binder_open(struct inode *nodp, struct file *filp)
{
struct binder_proc *proc;
binder_debug(BINDER_DEBUG_OPEN_CLOSE, "binder_open: %d:%d\n",
current->group_leader->pid, current->pid);
proc = kzalloc(sizeof(*proc), GFP_KERNEL);//1、创建并分配一个binder_proc空间来保存Binder数据。
if (proc == NULL)
return -ENOMEM;
get_task_struct(current);
proc->tsk = current;//2、增加当前线程/进程的引用计数,给binder_proc的tsk字段赋current值。
//3、实现binder_proc队列的初始化。
INIT_LIST_HEAD(&proc->todo);//使用INIT_LIST_HEAD初始化链表头todo
init_waitqueue_head(&proc->wait);//初始化等待队列wait
proc->default_priority = task_nice(current);//设置默认优先级(default_priority)为当前进程的nice值
mutex_lock(&binder_lock);//加锁
binder_stats_created(BINDER_STAT_PROC);//4、增加BINDER_STAT_PROC的对象计数,
hlist_add_head(&proc->proc_node, &binder_procs);//通过hlist_add_head把创建的binder_proc对象添加到全局的binder_proc哈希表中,这样任何一个进程就都可以访问到其他进程的binder_proc对象了
proc->pid = current->group_leader->pid;//5、把当前进程(或线程)的线程组的pid(pid指向线程id)赋值给proc的pid字段,。
INIT_LIST_HEAD(&proc->delivered_death);
filp->private_data = proc;//同时把创建的binder_proc对象指针赋值给filp的private_data对象并保存
mutex_unlock(&binder_lock);//解锁
if (binder_debugfs_dir_entry_proc) {
char strbuf[11];
snprintf(strbuf, sizeof(strbuf), "%u", proc->pid);
proc->debugfs_entry = debugfs_create_file(strbuf, S_IRUGO,//6、在binder_proc 目录中创建只读文件/proc/binder/proc/$pid,其功能是输出当前binder proc对象的状态。
binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);//文件名以pid命名,但该pid字段并不是当前进程或线程的id,而是线程组的pid,表示是线程组中第一个线程的pid(current->group_leader->pid)
} //并且在创建该文件时也指定了操作该文件的函数接口为binder_read_proc_proc,此函数的参数表示创建的binder_proc对象proc
return 0;
}
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);
}
ioctl会调用Binder驱动的binder_ioctl函数,去注册成为管理者。
binder_loop
将servicemanger注册为Binder的上下文管理者后,它就是Binder机制的管理者了,它会在系统运行期间处理Client端的请求,因为请求的时间不确定性,这里采用了无限循环来实现。也就是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];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
//当前线程注册为Binder的指令, 写入到binder的数据
readbuf[0] = BC_ENTER_LOOPER;
//将BC_ENTER_LOOPER指令写入到Binder驱动,
//将当前的ServiceManager线程注册为了一个Binder线程(注意ServiceManager本身也是一个Binder线程)。
//注册为Binder线程之后,就可以处理进程间的请求了
binder_write(bs, readbuf, sizeof(uint32_t));
//不断的循环遍历
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
//使用BINDER_WRITE_READ指令查询Binder驱动中是否有请求。
//如果有请求,就走到下面的binder_parse部分处理,如果没有,当前的ServiceManager线程就会在Binder驱动中水命,等待新的进程间请求
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
//走到这里说明有请求信息。将请求的信息用binder_parse来处理,处理方法是func
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
}
}
binder_write
//frameworks\native\cmds\servicemanager\binder.c
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;
bwr.write_buffer = (uintptr_t) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
//BINDER_WRITE_READ既可以读也可以写。关键在于read_size和write_size。
//如果write_size>0。则是写。如果read_size>0则是读。
//如果都大于0,则先写,再读
//这里很明显write_buffer>0, 而read_buffer==0
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
驱动侧:
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);
//用户空间数据bwr的地址
void __user *ubuf = (void __user *)arg;
binder_selftest_alloc(&proc->alloc);
trace_binder_ioctl(cmd, arg);
ret = wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error < 2);
thread = binder_get_thread(proc);
switch (cmd) {
case BINDER_WRITE_READ:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
...
}
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
int ret = 0;
//当前调用方进程的binder_proc信息
struct binder_proc *proc = filp->private_data;
unsigned int size = _IOC_SIZE(cmd);
//(void __user *)arg 指的是arg值是一个用户空间的地址,
//不能直接进行拷贝等,要使用例如copy_from_user,copy_to_user等函数
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
...
//将用户空间的bwr的ubuf数据copy到内核空间bwr中
if (copy_from_user(&bwr, ubuf, sizeof(bwr))) {
ret = -EFAULT;
goto out;
}
...
//表示往binder写数据
if (bwr.write_size > 0) {
//设置进入looper BC_ENTER_LOOPER
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);
binder_inner_proc_lock(proc);
if (!binder_worklist_empty_ilocked(&proc->todo))
binder_wakeup_proc_ilocked(proc);
binder_inner_proc_unlock(proc);
if (ret < 0) {
if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
ret = -EFAULT;
goto out;
}
}
binder_thread_write
{
case BC_ENTER_LOOPER:
...
thread->looper |= BINDER_LOOPER_STATE_ENTERED;
break;
}
将BC_ENTER_LOOPER指令写入到Binder驱动,之后将当前的ServiceManager线程注册为了一个Binder线程(注意ServiceManager本身也是一个Binder线程)。 注册为Binder线程之后,ServiceManager就可以不断的往binder驱动请求数据,binder驱动通过binder_loop循环不断的查询是否有请求。