目录
2.通过binder_become_context_manager()告诉Binder驱动程序该进程为ServiceManager进程
3.通过binder_loop()开启循环,等待Client进程和Server进程发来请求
前言
通过源码的角度来看下到底Binder机制是一个什么东西。如果不喜欢看源码,可以直接看每个章节的小结。
一 ServiceManager
在前面一篇Android 跨进程通信-(一)Binder概念引入中也总结过:Android在系统启动的时候,用户空间启动的第一个进程是init进程,ServiceManager是由init进程通过解析init.rc文件而创建的,其所对应的可执行程序/system/bin/servicemanager,所对应的源文件是framework/base/services/java/com/android/server/service_manager.c,进程名为/system/bin/servicemanager。
这样当该进程创建成功之后,后面在启动的Service都会通过ServiceManager来进程管理。ServiceManager位于frameworks/base/core/java/android/os/ServiceManager.java。
前面也提到了在Binder机制中的四大组件:Client、Server、ServiceManager以及Binder驱动,所以将这些Service的时候启动之前,其实首先要启动ServiceManager进程
该ServiceManager进程启动的时候,其实就是执行framework/native/cmds/servicemanager/servicemanager.c下对应的内容,这是Native层对ServiceManager这个功能的封装,是ServiceManager在Native层功能的体现,最终不同的方法的功能实现都包括两部分:第一部分就是Native层对Kernel层相关方法的封装;第二部分就是Kernel层具体功能实现。也就是说最终在Native层的这些方法都会调用到Kernel层的对应的方法。
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
// 1.打开Binder驱动,映射内存为128k
bs = binder_open(driver, 128*1024);
//........
//2.成为上下文的管理者,告诉Binder驱动该进程为ServiceManager进程
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
//........
//3.开启循环处理消息
binder_loop(bs, svcmgr_handler);
return 0;
}
在整个ServiceManager进程在启动的过程中,就会完成下面的三个功能:
1.通过builder_open()打开Binder驱动
builder_open()具体实现对应framework/native/cmds/servicemanager/builder.c中的builder_open():该方法的作用不难理解,主要有这两部分的作用:
- (1)打开设备文件"/dev/binder"获取一个文件描述bs,通过该文件描述才可以与Binder驱动进行交互;
- (2)将该文件映射到ServiceManager进程的虚拟地址空间
进入到builder.c的builder_open()中看下里面的几个关键流程:
struct binder_state *binder_open(const char* driver, size_t mapsize)
{
struct binder_state *bs;
//......
//1.调用内核空间的binder驱动来打开设备文件"/dev/binder"
bs->fd = open(driver, O_RDWR | O_CLOEXEC);
//......
//2.检查kernel的binder版本是否一致
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;
}
//3.根据传入的内存大小,为该设备文件创建对应大小的虚拟空间
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
//......
return bs;
//......
}
(1)通过open()打开设备文件
该方法就是去打开binder的设备文件"/dev/binder",并且返回一个binder_state来记录这个设备文件的状态。其中binder_state的参数如下:
struct binder_state
{
int fd;
void *mapped;
size_t mapsize;
};
- 参数fd: 打开"/dev/binder"的返回的文件描述符,用来和Binder驱动进行交互;
- 参数mapped:为当前的ServiceManage进程与BInder驱动进行交互分配的地址空间,用来Binder驱动为它分配内核缓冲区来保存进程间通信的数据。
- 参数mapsize:地址空间,大小
此时open()方法会通过系统调用到Binder驱动中的binder_open()方法。具体的Binder驱动的binder_open()会在后面二 Binder驱动有介绍。
这样就从用户空间通过系统调用到了内核空间,通过Binder驱动的binder_open()打开了设备文件"/dev/binder",并且获得了一个该文件的描述符,然后通过该文件描述符与Binder驱动进行通信。

最低0.47元/天 解锁文章
5664

被折叠的 条评论
为什么被折叠?



