前言
在Linunx
進程中使用的通信方式有:socket
(套接字通信),named
(命令管道),pipe
(管道),message queque
(報文隊列),signal
(信號),share memory
(共享內(nèi)存)域庇。
在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
進程冤荆,從而執(zhí)行service_manager.c
的main
函數(shù)朴则,同時重啟了下面幾個模塊
-
healthd
監(jiān)聽電池的狀態(tài)和信息,同時傳遞給BatteryService
匙赞,從而展示電池相關的信息佛掖。 -
zygote
當zygote
被kill
的時候,servicemanager
會在這里嘗試重新喚醒它 -
audioserver
涌庭,media
音視頻相關的服務 -
surfaceflinger
繪制應用程序的用戶界面的服務 -
inputflinger
系統(tǒng)輸入事件服務 -
drm
數(shù)字版權管理服務 -
cameraserver
相機服務 -
keystore
應用簽名文件 -
gatekeeperd
系統(tǒng)的圖案/密碼認證
接下來在init.rc
里面調(diào)用啟動servicemanager
//init.rc
//....
class_start core
//....
通過class_start core
就啟動了servicemanager
芥被。
接下里就來看看service_manager.c
的main
函數(shù)
//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
進入一個無窮循環(huán),充當Server的角色坐榆,等待Client的請求
Binder驅動程序初始化
Binder
驅動程序源碼位于/drivers/staging/android/binder.c
拴魄,在源碼中可以看到這行代碼
device_initcall(binder_init);
binder_init()
在Linux
加載完內(nèi)核的時候,init
函數(shù)會執(zhí)行device_initcall
席镀。從而執(zhí)行binder_init
函數(shù)匹中,初始化binder
驅動程序。再來看看binder_init()
函數(shù)
//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
創(chuàng)建了一個binder
的worker_thread
單一內(nèi)核進程
debugfs_create_dir
debugfs
是一種內(nèi)核調(diào)試的虛擬文件系統(tǒng)豪诲,內(nèi)核開發(fā)者通過debugfs
和用戶空間交換數(shù)據(jù)顶捷,它是在Linux
運行的時候建立。這里就是創(chuàng)建debugfs
相應的文件
misc_register
它傳的參數(shù)是一個結構體如下
static struct miscdevice binder_miscdev = {
.minor = MISC_DYNAMIC_MINOR, //次設備號動態(tài)分配
.name = "binder",//設備號
.fops = &binder_fops// 設備的文件操作系統(tǒng)
};
通過misc_register
函數(shù)為binder
驅動注冊一個misc
設備
接下來就是創(chuàng)建proc
和state
目錄下的一些文件
binder_open()
binder_init
初始化之后屎篱,接下來service_manager.c
的main
函數(shù)會調(diào)用binder_open
服赎。先來看看binder_open()
函數(shù)。
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
進程內(nèi)的用來用戶請求處理的線程重虑,線程最大數(shù)由max_threads
決定 -
nodes
保存binder_proc
進程內(nèi)的binder
的實體 -
refs_by_desc
和refs_by_node
保存binder_proc
進程內(nèi)的binder
的引用 -
tsk
保存binder_proc
進程的地址 -
todo
待處理的事務鏈表 -
wait
等待處理的鏈表 -
default_priority
默認處理的事務優(yōu)先級
get_task_struct
Linux
內(nèi)核方法,源碼如下
#define get_task_struct(tsk) do{ atomic_inc&((tsk) ->[usage] } while(0)
最終調(diào)用atomic_add
函數(shù)秦士,通過原子加的形式實現(xiàn)當前進程引用的計數(shù)
接下來就是對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
具有指針指向的時候系統(tǒng)會自動調(diào)用misc_open
函數(shù),而在misc_open
函數(shù)曹傀,會遍歷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
函數(shù)卖毁。再來看看binder_mmap
函數(shù)
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
創(chuàng)建的struct binder_proc
結構揖曾,內(nèi)存映射信息放在vma參數(shù)中落萎。其中vma
是vm_area_struct
結構體,它是給進程使用的一塊連續(xù)的虛擬地址空間炭剪,而vm_struct
是個內(nèi)核使用的一塊連續(xù)的虛擬地址空間练链。在同一個物理頁面中,一方映射到進程虛擬地址空間奴拦,一方面映射到內(nèi)核虛擬地址空間媒鼓,這樣,進程和內(nèi)核之間就可以減少一次內(nèi)存拷貝了错妖。接下來該函數(shù)就是處理內(nèi)存映射和管理的詳細步驟绿鸣。
binder_ioctl()
再來看看binder_ioctl
函數(shù)
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;
}
它主要是負責在兩個進程間進行收發(fā)數(shù)據(jù)