Android Binder 修炼之道(一)框架分析

    在 Android 系统中含有大量的进程间通讯,Android 系统的开发人员为了进程间通讯使用起来更方便,在Linux内核里搞了一个 Binder 驱动,然后利用这个 Binder 驱动进行一些进程间的数据传输。在 Android 中对如何使用 Binder 驱动进行了封装,有C版本,也有C++和JAVA版本,将它们统称为 Binder 系统。有了这些封装之后,使用者只需要调用固定的接口,便可以达到其想要的目的。那么,本文来分析C语言版本的 Binder 系统内部实现。
    Binder 系统是典型的C/S架构,有点像内核中的总线驱动模型,在内核中将一整个驱动程序可以分割为 device bus driver,在 Binder 中,则有 Client ServiceManager Server。
    首先是 ServiceManager,它负责管理 Server 注册进来的 Service,也就是说 Server 要向 Servermanger 注册服务,那么 Server 如何知道谁是 ServiceManager 呢?在 Binder 系统中用一个整数 handle 来描述这些进程,对于 ServerManager 它的这个 handle 为 0,所以大家就知道谁是 ServerManager 了。
    前面提到了 Server 会向 ServiceManager 注册 Service ,那么 Client 肯定就是向 ServiceManager 查询是否有某一个 Service,如果找到了,ServiceManager 就返回对应 Server 的 handle ,利用这个 handle ,clinet 和 Server 之间就可以直接利用 Binder 驱动进行进程间的通讯。
    写到这里,又有一点领悟,ServiceManager 负责管理 Service,其实对于 Server 来说,ServiceManager 是一个特殊的“Server”,为什么呢?因为它的 handle 为 0,Server 通过 Binder 发送数据给它,调用它的注册 Service 函数。对于 Client 和 ServiceManager 之间的关系也是一样的。总之,他们三者之间两两都是C/S模型。
     对于 Binder 驱动,其实原理很简单,它只不过是一个数据传输的通道,规定了数据格式,把数据发送给你想发送的handle 进程而已。

ServiceManager分析
Service_manager.c (frameworks\native\cmds\servicemanager)
int main(int argc, char **argv)
{
    struct binder_state *bs;

    // open binder 驱动,open("/dev/binder", O_RDWR);
    bs = binder_open(128*1024);

    // 告诉系统,我是 ServiceManager,ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
    binder_become_context_manager(bs)

    svcmgr_handle = BINDER_SERVICE_MANAGER;
    // 陷入循环,接收并处理发送数据
    binder_loop(bs, svcmgr_handle);

    return 0;
}
void binder_loop(struct binder_state *bs, binder_handle func)
{
    int res;
     struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(uint32_t));

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

        // 读数据,获取到的数据会存放在 binder_write_read 结构体中
         res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
         // 解析数据
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
    }
}
在这里,我们看到binder通信,使用的是一个 binder_write_read 结构体进行的数据封装,无论读还是写都用它
int binder_parse(struct binder_state *bs, struct binder_io *bio,  uintptr_t ptr, size_t size, binder_handle  func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;

    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);

        switch(cmd) {
        ...
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            binder_dump_txn(txn);//打印数据
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;

                bio_init(&reply, rdata, sizeof(rdata), 4);

                // 将收到的数据封构造成一个 binder_io
                bio_init_from_txn(&msg, txn);

                // 调用前面传入的  svcmgr_handle  处理,处理结果放到 binder_io reply 中
                res = func(bs, txn, &msg, &reply);

                // 将 reply 在封装成 binder_write_read 用 ioctl 发回去
                 binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
            }
            ptr += sizeof(*txn);
            break;
        }
        ...
    }

    return r;
}
至于 binder_write_read 和 binder_io 之间的转换细节,这里不是我们分析的重点,下面来看一下对于 ServiceManager 它是如何处理“业务”数据的。
int svcmgr_handle(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
     uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;

    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);

    // txn->code 表示调用Server的哪个函数
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        bio_put_ref(reply, handle);
        return 0;

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

    bio_put_uint32(reply, 0);
    return 0;
}
先来看注册服务,   bio_get_string16(msg, &len); 从 binder_io 中取出一个字符串,这里应该就是服务的名字,然后不知道从那里搞到一个对应的 handle ( uint32_t ),最后把这个 service 注册进去。
获取服务的过程与之相反....

在 Client 和 Server 中,既然要利用 binder 进行通讯,那么,它们必然也是去 Open binder 驱动,然后构造 bind_write_read 结构体发送数据,然而对于构造这些数据我们可以简单的使用 bind_call 函数,下面来参考一个例子:
Bctest.c (native\cmds\servicemanager)
int svcmgr_publish(struct binder_state *bs, uint32_t target, const char *name, void *ptr)
{
    int status;
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, SVC_MGR_NAME);
    bio_put_string16_x(&msg, name);
    bio_put_obj(&msg, ptr);

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_ADD_SERVICE))
        return -1;

    status = bio_get_uint32(&reply);

    binder_done(bs, &msg, &reply);

    return status;
}
uint32_t svcmgr_lookup(struct binder_state *bs, uint32_t target, const char *name)
{
    uint32_t handle;
    unsigned iodata[512/4];
    struct binder_io msg, reply;

    bio_init(&msg, iodata, sizeof(iodata), 4);
    bio_put_uint32(&msg, 0);  // strict mode header
    bio_put_string16_x(&msg, SVC_MGR_NAME);
    bio_put_string16_x(&msg, name);

    if (binder_call(bs, &msg, &reply, target, SVC_MGR_CHECK_SERVICE))
        return 0;

    handle = bio_get_ref(&reply);

    if (handle)
        binder_acquire(bs, handle);

    binder_done(bs, &msg, &reply);

    return handle;
}
这里可以看到,无论是注册服务还是查询服务,均是构造了一个 binder_io 然后调用 binder_call 来发送数据,binder_call 的实质还是 bind_write_read 结构体通过 ioctl 发送
int binder_call(
               struct binder_state *bs,     // binder fd
               struct binder_io *msg,       // 调用远程函数时的参数,比如注册服务,服务名字就是一个参数
               struct binder_io *reply,     // 回复的数据存放在 reply
               uint32_t target,             // 哪个进程?也就是 handle ,如果是 ServiceManager 的话为 0
               uint32_t code                // 远程进程的函数编号,也就是要调用它的哪个函数,比如注册服务函数,查询服务函数
)
至于如何填充 binder_io ,以及取回的数据如何使用,下节分析!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值