前言
在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;
}
它主要是负责在两个进程间进行收发数据