Android IPC通信之Binder通信

来源:互联网 发布:风险矩阵法优缺点 编辑:程序博客网 时间:2024/05/19 00:36

        从四年多的数通开发方向转到Android系统开发方向,的确是一个华丽而艰辛的转身。初识Android时,先从Android的整个系统框架梳理了一遍,让之了然于胸,鉴于对kernel的了解,先从Android新增的Binder驱动相关来入手,尽管Binder理解起来十分生涩,但是如果你认真去分析源码后,会发现其中的奥秘,会惊叹于他设计的巧妙,感叹Google工程师的神奇,所以从这篇开始我要分几篇文章来详细介绍Binder通信。

      我们知道,Android系统基于Linux, 而传统的Linux 有消息队列,Pipe, System V , Socket等,Socket传输效率低,开销大,主要用在跨网络的进程间通信和本机上进程间的低速通信, 而消息队列和管道采用存储-转发方式,即数据先从发送方缓存区拷贝到内核开辟的缓存区,然后再从内核缓存区拷贝到接收方缓存区,至少两次拷贝。而共享内存呢虽然0次拷贝,但安全性不好控制。Binder属于C/S架构,使用了Proxy代理设计模式,整个BInder通信框架可以分为四个角色;Server, Client, Service Manager和Binder驱动,前三个位于User Space, Binder驱动位于kernel Space:客户端通过服务端进程代理对象,发送请求到代理对象,代理对象通过Binder驱动将请求转发给服务端进程处理,处理完成以后server再通过Binder驱动reply代理对象。对于面向对象的BInder IPC, Server必须有确定的访问接入点地址来接手client的请求,以及command-reply协议传输数据。本章我们主要来讲讲Service Manager,这个总管家的内部机制吧。

      Service  Manager为服务管理着,他负责的任务就是管理提供服务者的列表,比如service的新增、查询、删除等,它存在的意义在于统一管理系统的服务,Android系统某服务的客户端必须通过Service Manager来查询服务信息,再与之交互,我们开始从Service Manager进程的启动开始来分析它的作用。Service Manager是C语言实现的,在Init进程加载Init.rc文件时创建出来的,Init.rc脚本里这么写道:

        service servicemanager /system/bin/servicemanager

       class core

       user system

       group system

       critical

      onrestart restart healthd

     onrestart restart zygote

     onrestart restart media

     onrestart restart surfaceflinger

     onrestart restart drm

这段脚本表示servicemanager是一个服务,执行/system/bin/servicemanager下的可执行文件,那我们再看看servicemanager的main函数吧;service_manager.c中:

    int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
    binder_loop(bs, svcmgr_handler);
    return 0;
}

首先定义BINDER_SERVICE_MANAGER是(void*)0,这个是service manager的特定handler,任何发往service manager的targer必须是它,而后binder_open源码如下:

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. 给binder_state分配空间,记录binder相关信息

2. 通过系统调用open打开/dev/binder文件,记录文件句柄

3.为活得的binder文件句柄映射128k的内存,

而后binder_become_context_manager就是通知binder驱动,我就是守护进程,最后进入循环等待接受请求的到来。我们注意到这个细节,在binder_loop函数中,要先binder_write一个buffer头为BC_ENTER_LOOPER的buffer后才开始无限循环状态,因为这个BC_ENTER_LOOPER为设置service manager binder thread的looper状态BINDER_LOOPER_STATE_ENTERED的。我们这里注册了一个回调函数svcmgr_handler,代码如下:

int svcmgr_handler(struct binder_state *bs,
                   struct binder_txn *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    unsigned len;
    void *ptr;
    uint32_t strict_policy;
    int allow_isolated;

    if (txn->target != svcmgr_handle)
        return -1;

    // Equivalent to Parcel::enforceInterface(), reading the RPC
    // header with the strict mode policy mask and the interface name.
    // Note that we ignore the strict_policy and don't propagate it
    // further (since we do no outbound RPCs anyway).
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s));
        return -1;
    }

    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = do_find_service(bs, s, len, txn->sender_euid);
        if (!ptr)
            break;
        bio_put_ref(reply, ptr);
        return 0;

    case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
            return -1;
        break;

    case SVC_MGR_LIST_SERVICES: {
        unsigned n = bio_get_uint32(msg);

        si = svclist;
        while ((n-- > 0) && si)
            si = si->next;
        if (si) {
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
    default:
        ALOGE("unknown code %d\n", txn->code);
        return -1;
    }

    bio_put_uint32(reply, 0);
    return 0;
}

很显然,这个就是service manager的主要任务处理,    SVC_MGR_GET_SERVICE, SVC_MGR_CHECK_SERVICE,    SVC_MGR_ADD_SERVICE, SVC_MGR_LIST_SERVICES。

     

   

0 0
原创粉丝点击