ServiceManager如何成为Binder进程通信的守护进程

在上一篇博客《Android源码分析之Binder进程间通信一》中,我详细的讲述了Android进程间通信为什么会选择Binder进行通信,而且在文章末尾,我还提议从4个方面来理解整个Binder进程间通信机制。当然这篇博客的重点就是介绍ServiceManager组件的,它是整个Binder机制的守护进程,用来管理开发创建的各种Server,并且向Client提供查询Server的远程接口的功能。

那该如何阅读ServiceManager的源代码呢?我们都知道ServiceManager处于用户空间,所以其源代码必然是在frameworks/base/cmds/servicemanager中的:主要由3个文件(binder.h,binder.c和service_manager.c)组成,service_manager.c是ServiceManager的入口函数的:

位于:frameworks\base\cmds\servicemanager\service_manager.c

int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;
	//打开binder设备
    <span style="color:#ff0000;">bs = binder_open(128*1024);</span>
	//成为manager
    if (<span style="color:#ff0000;">binder_become_context_manager(bs)</span>) {
        LOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
	//处理客户端发过来的请求
    <span style="color:#ff0000;">binder_loop(bs, svcmgr_handler);</span>
    return 0;
}
该主函数主要完成三个功能:

1)调用binder_open(int)打开Binder驱动设备;
2)调用binder_become_context_manager通知Binder驱动程序自己是Binder的上下文管理者;

3)调用binder_loop进入休眠,充当Server,等待Client请求;

可能大家对住函数中的struct binder_state和宏BINDER_SERVICE_MANAGER不太了解,下面我简要的从定义讲解下它们:

结构体binder_state定义:在frameworks/base/cmds/servicemanager/binder.c文件中

struct binder_state
{
    //文件描述符
    int fd;
    void *mapped;
    unsigned mapsize;
};
成员变量:

1)fd:文件描述符,表示要打开的binder设备文件描述符;
2)mapped:把设备文件binder映射到进程空间的起始地址;

3)mapSize:内存空间映射的大小;

宏BINDER_SERVICE_MANAGER定义:frameworks/base/cmds/servicemanager/binder.h文件中

/* the one magic object*/
#define BINDER_SERVICE_MANAGER ((void*) 0)
1)它表示ServiceManager的句柄为0; Binder通信机制使用句柄来代表远程接口。
2)ServiceManager充当守护进程的同时,它还是Server角色,当它作为远程接口使用时,它的句柄值为0;其他的Server远程接口的句柄值都是一个大于0而且是Binder驱动自动分配的。

上面介绍完了主函数一些代码情况,下面详细的从上面所说的3步来描述ServiceManager如何成为Binder进程通信的守护进程:

第一步:binder_open打开Binder设备操作

位于frameworks/base/cmds/servicemanager/binder.c文件中

//打开binder设备
struct binder_state *binder_open(unsigned mapsize)
{
    struct binder_state *bs;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return 0;
    }

    bs->fd = open("/dev/binder", O_RDWR);
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }

    bs->mapsize = mapsize;
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

        /* TODO: check version */

    return bs;

fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return 0;
}
1) 通过文件操作函数open来打开/dev/binder设备文件。 设备文件/dev/binder是在Binder驱动程序模块初始化时候创建的。
 2)对打开的Binder设备文件 进行内存映射操作mmap:
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
该操作对应Binder驱动程序binder_mmap函数: 为什么同时使用进程虚拟地址空间和内核虚拟地址空间来映射同一个物理页面?
    答:同一个物理页面,一方映射到进程虚拟地址空间,一方面映射到内核虚拟地址空间,这样进程和内核之间就可以减少一次内存拷贝,提高了进程间的通信效率。

第二步:通知Binder驱动程序ServiceManager是Binder机制的上下文管理者
通过binder_become_context_manager函数来完成,该函数位于 frameworks/base/cmds/servicemanager/binder.c文件中,
//成为manager
int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
通过调用ioctl文件操作函数来通知Binder驱动程序自己是守护进程,命令号是BINDER_SET_CONTEXT_MGR。

第三步:调用binder_loop函数进入循环,等待client的请求
binder_loop定义在 frameworks/base/cmds/servicemanager/binder.c文件中
/*
注意binder_handler参数,它是一个函数指针,binder_loop读取请求后将解析这些请求
最后,调用bind_handler完成最终的处理
*/
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    unsigned readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;
    
    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(unsigned));

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (unsigned) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }
		//接收请求,交给binder_parse,最终会调用func来处理这些请求
        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
        if (res == 0) {
            LOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            LOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}

ServiceManager称为Android进程通信机制Binder守护进程整个过程如下:
1)打开/dev/binder文件:open("/dev/binder", O_RDWR);
2)建立128K内存映射:mmap;
3)通知Binder驱动程序它是守护进程:binder_become_context_manager;
4)进入循环等待请求的到来:binder_loop。
上面是我在阅读《Android系统情景源码分析》所得的读书笔记,可能中间没有讲的很详细,但是如果你认真阅读了,一定能够理解ServiceManager成为Binder进程通信的守护进程的过程。



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值