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

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

本文链接:https://blog.csdn.net/lizuobin2/article/details/76228339

在 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 ,以及取回的数据如何使用,下节分析!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值