关于Binder的作用和历史来源此处就不讲了,大家可以百度到更详细的文章。
本文此处主要是讲一下 Binder 通信的原理。
一、Android Binder 原理
Android Binder 主要是分为IPC 和 RPC 两个:
IPC:进程内的通信(比如:管道,FIFO命名管道,消息队列,信号量,共享内存)。
比如 在进程内的A 要发送给进程 内的B ,使用IPC 发送就可以了。
(ps: 关于IPC详细的实现方法,此处就不讲了,我刚刚在网上找到一篇写的不错的博文:https://www.cnblogs.com/CheeseZH/p/5264465.html)
RPC:进程间的通信,远程过程调用,RPC是在IPC 的基础上进行封装的(IPC是基础)。
比如进程A 要发送数据 给进程B控制其中的LED,主要目的是控制LED,因为进程A是没有办法直接调用B种的LED控制函数,
因此通信过程就是: 进程A 讲要发送的数据进行封装,然后通过RPC发送给进程B,由进程B来解析数据,并相应的控制LED。
IPC是基础,用于负责数据传输
我们知道数据传输存在三大基础: 源、目的、数据本身
拿前面的例子举例:
源就:就是 进程A
目的:就是 进程B
数据:就是一个buffer,数据格式由双方共同约定好
但问题来了,
Question 1、进程A 如何知道应该像那个进程B 进行访问,比如A像控制声音又应该向哪个进程B访问呢?
Answer :
因此,要解决这个问题,就需要如下的流程:
首先,进程 B 就要向Servicemanager 注册服务 ,
接下来,进程A 向Servicemanager 查询相应的服务,得到一个handler,这个handler 就是指向进程 B
此时进程A就获取到了 进程B 的handler。
但问题来了,
Question 2、进程A应该调用 Handler (进程B) 中的哪个函数呢?如何实现传参和接受返回值?
Answer :
调用哪个函数: 在进程A中,对进程B 中的函数进行编号
传递参数,及返回值:通过 IPC的 buff 来传输,格式由双方约定好
通过前面两个问题,我们实际上就已经将一个简单的Android Binder 模型给构建出来了。
我们用图将前面所有的文字描述形象的画出来:
结合前面的分析,我们可以来猜想下Client、ServiceManger、Binder驱动、Server 的各自的工作事什么,
针对上面的图,我们再来做一个放大版的:
二、 代码具体调用过程:
Android 源码 在目录 Frameworks/native/cmds/servicemanager/
里面包含了: service_manager.c、bctest.c、binder.c(binder.c是封装好的C库,后续可以通过它来写client和service程序)
1. service_manager 处理过程
// frameworks/native/cmds/servicemanager/service_manager.c
// Android.bp文件内容如下
cc_binary {
name: "servicemanager",
defaults: ["servicemanager_flags"],
srcs: [
"service_manager.c",
"binder.c",
],
shared_libs: ["libcutils", "libselinux"],
init_rc: ["servicemanager.rc"],
}
cc_binary {
name: "vndservicemanager",
defaults: ["servicemanager_flags"],
vendor: true,
srcs: [
"service_manager.c",
"binder.c",
],
cflags: [
"-DVENDORSERVICEMANAGER=1",
],
shared_libs: ["libcutils", "libselinux_vendor"],
init_rc: ["vndservicemanager.rc"],
}
//可以看出,基于同一份代码,分别编译出了 servicemanager 和 vndservicemanager 两个可执行程序。
//ServiceManger 是被 Init 启动的:
# frameworks/native/cmds/servicemanager/servicemanager.rc
service servicemanager /system/bin/servicemanager
class core animation
user system
group system readproc
critical
# frameworks/native/cmds/servicemanager/servicemanager.rc
service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder
class core
user system
group system readproc
在service_manager.c 中
// frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char** argv)
{
struct binder_state *bs;
char *driver;
if (argc > 1) {
driver = argv[1]; // /dev/vndbinder
} else {
driver = "/dev/binder";
}
//1. Binder Open 打开Binder 驱动程序
bs = binder_open(driver, 128*1024);
//2. 注册为 context manger,告诉驱动它是 Service_Manager
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
//3. 进入 binder_loop 循环,等待请求,该循环的作用为读取binder数据,解析数据,处理数据
binder_loop(bs, svcmgr_handler);
// ====>
a. 解析数据,处理数据
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
====>
ret = binder_wait_for_work(thread, wait_for_proc_work);
// 在while 死循环中,通过 binder_has_work_ilocked 定时检查是否由任务需要处理
for (;;) {
prepare_to_wait(&thread->wait, &wait, TASK_INTERRUPTIBLE);
if (binder_has_work_ilocked(thread, do_proc_work))
break;
if (do_proc_work)
list_add(&thread->waiting_thread_node,
&proc->waiting_threads);
binder_inner_proc_unlock(proc);
schedule();
binder_inner_proc_lock(proc);
list_del_init(&thread->waiting_thread_node);
}
b. 处理 svcmgr_handler ,在该函数中,通过判断code 来执行
SVC_MGR_GET_SERVICE/SVC_MGR_CHECK_SERVICE 获取或者检查服务是否存在,存在则返回code
SVC_MGR_ADD_SERVICE: 注册服务器
return 0;
}
2. 注册服务的过程
// frameworks/native/cmds/servicemanager/bctest.c
int main(int argc, char** argv)
{
//1. Binder Open 打开Binder 驱动程序
bs = binder_open(128*1024);
//2. 注册服务
svcmgr_publish(bs, svcmgr, argv[1], &token);
====>
// target = BINDER_SERVICE_MANAGER = 0 0: 表示是service manager
// msg: 含有服务的名字
// reply: servicemanager 的回复的数据
binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE)
}
3. 获取服务的过程
// frameworks/native/cmds/servicemanager/bctest.c
int main(int argc, char** argv)
{
//1. Binder Open 打开Binder 驱动程序
bs = binder_open(128*1024);
//2. 查找服务
handle = svcmgr_lookup(bs , svcmgr, "alt_svc_mgr");
====>
bio_init(&msg, iodata, sizeof(iodata), 4);
bio_put_uint32(&msg, 0); //格式化数据
bio_put_string16_x(&msg, SVC_MGR_NAME); // 传入服务的Code
bio_put_string16_x(&msg, name); // 传入服务的名字
if ( binder_call( bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE ) )
return 0;
handle = bio_get_reg(&reply)
if(handle)
binder_aquire(handle)
}