前言
在Linunx进程中使用的通信方式有:socket(套接字通信),named(命令管道),pipe(管道),message queque(报文队列),signal(信号),share memory(共享内存)。
在Java进程中使用的通信方式有:socket,named,pipe等。
在Android进程中使用的通信方式主要是Binder通信,下面就来看看Binder通信机制
Binder通信机制
Binder是由Client,Server,ServiceManager,Binder驱动程序组成。
ServiceManager
其中ServiceManager是Binder机制的守护进程,同时也是一个特殊的Service。它在init.rc里面就开始启动了,其中Android7.0把servicemanager的启动代码拆分到servicemanager.rc里面,代码如下:
//frameworks/native/master/./cmds/servicemanager/servicemanager.rc
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart audioserver
onrestart restart media
onrestart restart surfaceflinger
onrestart restart inputflinger
onrestart restart drm
onrestart restart cameraserver
onrestart restart keystore
onrestart restart gatekeeperd
writepid /dev/cpuset/system-background/tasks
shutdown critical
从上面代码可知启动了servicemanager进程,从而执行service_manager.c的main函数,同时重启了下面几个模块
-
healthd监听电池的状态和信息,同时传递给BatteryService,从而展示电池相关的信息。 -
zygote当zygote被kill的时候,servicemanager会在这里尝试重新唤醒它 -
audioserver,media音视频相关的服务 -
surfaceflinger绘制应用程序的用户界面的服务 -
inputflinger系统输入事件服务 -
drm数字版权管理服务 -
cameraserver相机服务 -
keystore应用签名文件 -
gatekeeperd系统的图案/密码认证
接下来在init.rc里面调用启动servicemanager
//init.rc
//....
class_start core
//....
通过class_start core就启动了servicemanager。
接下里就来看看service_manager.c的main函数
//frameworks/native/master/./cmds/servicemanager/service_manager.c
int main()
{
struct binder_state *bs;
bs = binder_open(128*1024);
//....
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
//....
binder_loop(bs, svcmgr_handler);
return 0;
}
主要做了下面几种
-
binder_open打开Binder设备 -
binder_become_context_manager通知Binder驱动程序自己是Binder上下文管理者 -
binder_loop进入一个无穷循环,充当Server的角色,等待Client的请求
Binder驱动程序初始化
Binder驱动程序源码位于/drivers/staging/android/binder.c,在源码中可以看到这行代码
device_initcall(binder_init);
binder_init()
在Linux加载完内核的时候,init函数会执行device_initcall。从而执行binder_init函数,初始化binder驱动程序。再来看看binder_init()函数
//android/kernel/msm/android-7.1.2_r0.33/./drivers/staging/android/ binder.c
static int __init binder_init(void)
{
int ret;
binder_deferred_workqueue = create_singlethread_workqueue("binder");
if (!binder_deferred_workqueue)
return -ENOMEM;
binder_debugfs_dir_entry_root = debugfs_create_dir("binder", NULL);
if (binder_debugfs_dir_entry_root)
binder_debugfs_dir_entry_proc = debugfs_create_dir("proc",
binder_debugfs_dir_entry_root);
ret = misc_register(&binder_miscdev);
if (binder_debugfs_dir_entry_root) {
debugfs_create_file("state",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_state_fops);
debugfs_create_file("stats",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_stats_fops);
debugfs_create_file("transactions",
S_IRUGO,
binder_debugfs_dir_entry_root,
NULL,
&binder_transactions_fops);
debugfs_create_file("transaction_log",
S_IRUGO,
binder_debugfs_dir_entry_root,
&binder_transaction_log,
&binder_transaction_log_fops);
debugfs_create_file("failed_transaction_log",
S_IRUGO,
binder_debugfs_dir_entry_root,
&binder_transaction_log_failed,
&binder_transaction_log_fops);
}
return ret;
}
create_singlethread_workqueue 创建了一个binder的worker_thread单一内核进程
debugfs_create_dir debugfs是一种内核调试的虚拟文件系统,内核开发者通过debugfs和用户空间交换数据,它是在Linux运行的时候建立。这里就是创建debugfs相应的文件
misc_register 它传的参数是一个结构体如下
static struct miscdevice binder_miscdev = {
.minor = MISC_DYNAMIC_MINOR, //次设备号动态分配
.name = "binder",//设备号
.fops = &binder_fops// 设备的文件操作系统
};
通过misc_register函数为binder驱动注册一个misc设备
接下来就是创建proc和state目录下的一些文件
binder_open()
binder_init初始化之后,接下来service_manager.c的main函数会调用binder_open。先来看看binder_open()函数。
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);
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__);
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,
binder_debugfs_dir_entry_proc, proc, &binder_proc_fops);
}
return 0;
}
binder_proc 它是保存打开/dev/binder设备的进程的结构体,保存的信息如下
struct binder_proc {
//...
struct rb_root threads;
struct rb_root nodes;
struct rb_root refs_by_desc;
struct rb_root refs_by_node;
struct task_struct *tsk;
struct list_head todo;
wait_queue_head_t wait;
int max_threads;
long default_priority;
//...
};
-
threads保存binder_proc进程内的用来用户请求处理的线程,线程最大数由max_threads决定 -
nodes保存binder_proc进程内的binder的实体 -
refs_by_desc和refs_by_node保存binder_proc进程内的binder的引用 -
tsk保存binder_proc进程的地址 -
todo待处理的事务链表 -
wait等待处理的链表 -
default_priority默认处理的事务优先级
get_task_struct Linux内核方法,源码如下
#define get_task_struct(tsk) do{ atomic_inc&((tsk) ->[usage] } while(0)
最终调用atomic_add函数,通过原子加的形式实现当前进程引用的计数
接下来就是对binder_proc链表的初始化以及其他进程相关信息进行初始化赋值。
binder_mmap()
在binder_open里面有一句代码是
static int binder_open(struct inode *nodp, struct file *filp)
{
//....
filp->private_data = proc;
//....
}
前面说到binder_init里面会把binder驱动注册一个misc设备。进去misc.c会看到
//kernel/common/drivers/char/misc.c
/ * The structure passed is linked into the kernel and may not be
* destroyed until it has been unregistered. By default, an open()
* syscall to the device sets file->private_data to point to the
* structure. Drivers don't need open in fops for this.
*/
int misc_register(struct miscdevice * misc)
{
//....
list_add(&misc->list, &misc_list);
out:
mutex_unlock(&misc_mtx);
return err;
}
把设备保存在misc_list里面,在上面的注释可知,它是在file->private_data具有指针指向的时候系统会自动调用misc_open函数,而在misc_open函数,会遍历file->private_data里面所有保存的设备的fops。
static int misc_open(struct inode * inode, struct file * file)
{
//...
list_for_each_entry(c, &misc_list, list) {
if (c->minor == minor) {
new_fops = fops_get(c->fops);
break;
}
}
//...
}
这里fops是传入的binder_miscdev结构体里面的fops,fops对应的是binder_fops结构体
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,
};
从这里可以找出初始化binder_mmap函数。再来看看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;
struct binder_buffer *buffer;
//....
}
通过filp->private_data得到在打开设备文件 /dev/binder创建的struct binder_proc结构,内存映射信息放在vma参数中。其中vma是vm_area_struct结构体,它是给进程使用的一块连续的虚拟地址空间,而vm_struct是个内核使用的一块连续的虚拟地址空间。在同一个物理页面中,一方映射到进程虚拟地址空间,一方面映射到内核虚拟地址空间,这样,进程和内核之间就可以减少一次内存拷贝了。接下来该函数就是处理内存映射和管理的详细步骤。
binder_ioctl()
再来看看binder_ioctl函数
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:
ret = binder_ioctl_write_read(filp, cmd, arg, thread);
if (ret)
goto err;
break;
case BINDER_SET_MAX_THREADS:
if (copy_from_user_preempt_disabled(&proc->max_threads, ubuf, sizeof(proc->max_threads))) {
ret = -EINVAL;
goto err;
}
break;
case BINDER_SET_CONTEXT_MGR:
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_preempt_disabled(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;
}
它主要是负责在两个进程间进行收发数据