天天看点

binder 分析(2)_client端程序

注册服务过程:

1. 打开binder设备驱动

2. 发布服务,看代码

int svcmgr_publish(struct binder_state *bs, void *target, const char *name, void *ptr)
{
    unsigned 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;
}      

1) 首先进行了数据封装, msg中放的是发给目标进程的数据,首先放入一个整数0,接着放入SVC_MGR_NAME,要发布的服务名name,和ptr

来看结构体 struct binder_io

struct binder_io
{
    char *data;            /* pointer to read/write from */
    uint32_t *offs;        /* array of offsets */
    uint32_t data_avail;   /* bytes available in data buffer */
    uint32_t offs_avail;   /* entries available in offsets array */

    char *data0;           /* start of data buffer */
    uint32_t *offs0;       /* start of offsets buffer */
    uint32_t flags;
    uint32_t unused;
};      

binder_io管理一段内存,data 指向data buffer的首个可用字节, data0 指向data buffer的起始地址。

offs 指向 offsets array中首个可用的 uint32_t * 类型的地址, offs0 指向offsets array中首个可用的起始地址

data_avail 为 可用的 data buffer 字节数, offs_avail为可用的 offs array中的 字节数/sizeof(uint32_t)

unsigned iodata[512/4];

bio_init(&msg, iodata, sizeof(iodata), 4);      

来看bio_init

void bio_init(struct binder_io *bio, void *data,
              uint32_t maxdata, uint32_t maxoffs)
{
    uint32_t n = maxoffs * sizeof(uint32_t);  // n 为 offsets array占用的字节数

    if (n > maxdata) {   // n 大于 iodata 的总字节
        bio->flags = BIO_F_OVERFLOW;  // 标志设为 OVER_FLOW
        bio->data_avail = 0;
        bio->offs_avail = 0;
        return;
    }

    bio->data = bio->data0 = (char *) data + n;   // data buffer 的起始地址设置
    bio->offs = bio->offs0 = data;   // offs array 的起始地址
    bio->data_avail = maxdata - n;    // 目前可用 data buffer字节数
    bio->offs_avail = maxoffs;   // off array中可用的数目
    bio->flags = 0;
}
      

来看bio_put_uint32

bio_put_uint32(&msg, 0);  // strict mode header      
void bio_put_uint32(struct binder_io *bio, uint32_t n)
{
    uint32_t *ptr = bio_alloc(bio, sizeof(n));
    if (ptr)
        *ptr = n;
}      

来看 bio_alloc

static void *bio_alloc(struct binder_io *bio, uint32_t size)
{
    size = (size + 3) & (~3);
    if (size > bio->data_avail) {
        bio->flags |= BIO_F_OVERFLOW;
        return 0;
    } else {
        void *ptr = bio->data;
        bio->data += size;
        bio->data_avail -= size;
        return ptr;
    }
}      

size = (size + 3) & (~3);// size 校准

作用: 使   4*n < size <= 4*(n+1) 时, size = 4*(n+1); n为整数

例如,  size = 3, 校准后 size 为 4; size = 13, 校准后 16

看起来,bio_alloc 以 4个字节为单位划分data buffer。

bio_alloc 只是在 data buffer 中 准备需要的内存。

接下来看:

bio_put_string16_x(&msg, name);      
void bio_put_string16_x(struct binder_io *bio, const char *_str)
{
    unsigned char *str = (unsigned char*) _str;
    uint32_t len;
    uint16_t *ptr;

    if (!str) {
        bio_put_uint32(bio, 0xffffffff);
        return;
    }

    len = strlen(_str);

    if (len >= (MAX_BIO_SIZE / sizeof(uint16_t))) {
        bio_put_uint32(bio, 0xffffffff);
        return;
    }

    bio_put_uint32(bio, len);   // 首先将 字符串的长度放入 buffer中
    ptr = bio_alloc(bio, (len + 1) * sizeof(uint16_t));  // 准备 空间
    if (!ptr)
        return;

    while (*str)   / / 将字符串的内容复制到 data  buffer 空间中 
       
*ptr++ = *str++;
      
*ptr++ = 0;}

2) 调用binder_call,来看源码

int binder_call(struct binder_state *bs,
                struct binder_io *msg, struct binder_io *reply,
                void *target, uint32_t code)
{
    int res;
    struct binder_write_read bwr;
    struct {
        uint32_t cmd;
        struct binder_txn txn;
    } writebuf;
    unsigned readbuf[32];

    if (msg->flags & BIO_F_OVERFLOW) {
        fprintf(stderr,"binder: txn buffer overflow\n");
        goto fail;
    }

    writebuf.cmd = BC_TRANSACTION;
    writebuf.txn.target = target;
    writebuf.txn.code = code;
    writebuf.txn.flags = 0;
    writebuf.txn.data_size = msg->data - msg->data0;
    writebuf.txn.offs_size = ((char*) msg->offs) - ((char*) msg->offs0);
    writebuf.txn.data = msg->data0;
    writebuf.txn.offs = msg->offs0;

    bwr.write_size = sizeof(writebuf);
    bwr.write_consumed = 0;
    bwr.write_buffer = (unsigned) &writebuf;
    
    hexdump(msg->data0, msg->data - msg->data0);
    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) {
            fprintf(stderr,"binder: ioctl failed (%s)\n", strerror(errno));
            goto fail;
        }

        res = binder_parse(bs, reply, readbuf, bwr.read_consumed, 0);
        if (res == 0) return 0;
        if (res < 0) goto fail;
    }

fail:
    memset(reply, 0, sizeof(*reply));
    reply->flags |= BIO_F_IOERROR;
    return -1;
}      

来看 binder_write_read

struct binder_write_read {
    signed long write_size;      // write_buffer 中的字节数
    signed long write_consumed;
    unsigned long write_buffer;  // write_buffer 的地址
    signed long read_size;       // read_buffer 中的字节数
    signed long read_consumed;
    unsigned long read_buffer;   // read_buffer 的地址
};      

来看 binder_txn 结构体

struct binder_txn
{
    void *target;        // target 指向了目标服务
    void *cookie;
    uint32_t code;       // code 指向了具体该调用的函数
    uint32_t flags;

    uint32_t sender_pid;
    uint32_t sender_euid;

    uint32_t data_size;   // data buffer 已写的字节数   
    uint32_t offs_size;   // offsets array 中已写的字节数
    void *data;           // data buffer 起始地址
    void *offs;           // offsets array 起始地址
};      

来看函数

void bio_init_from_txn(struct binder_io *bio, struct binder_txn *txn)
{
    bio->data = bio->data0 = txn->data;   //data的位置指向了data buffer的开始
    bio->offs = bio->offs0 = txn->offs;
    bio->data_avail = txn->data_size;
    bio->offs_avail = txn->offs_size / 4;  
    bio->flags = BIO_F_SHARED;
}      

调用binder_parse

res = binder_parse(bs, reply, readbuf, bwr.read_consumed, 0);      

正确的话会执行:

case BR_REPLY: {
    struct binder_txn *txn = (void*) ptr;
    if ((end - ptr) * sizeof(uint32_t) < sizeof(struct binder_txn)) {
        ALOGE("parse: reply too small!\n");
        return -1;
    }
    binder_dump_txn(txn);
    if (bio) {
        bio_init_from_txn(bio, txn); // 从txn中
        bio = 0;
    } else {
            /* todo FREE BUFFER */
    }
    ptr += (sizeof(*txn) / sizeof(uint32_t));
    r = 0;
    break;
}      

reply->data 为内核分配的一段内存,存放了被调用者的返回

status = bio_get_uint32(&reply);      

拿到返回值

binder_done(bs, &msg, &reply);      
void binder_done(struct binder_state *bs,
                 struct binder_io *msg,
                 struct binder_io *reply)
{
    if (reply->flags & BIO_F_SHARED) {
        uint32_t cmd[2];
        cmd[0] = BC_FREE_BUFFER;
        cmd[1] = (uint32_t) reply->data0;
        binder_write(bs, cmd, sizeof(cmd));
        reply->flags = 0;
    }
}      

释放掉 reply->data0 指向的内存

接下来来看,注册服务的具体内容:

最终调用了 svcmgr_handler 函数

int svcmgr_handler(struct binder_state *bs,
                          struct binder_txn *txn,
                          struct binder_io *msg,
                          struct binder_io *reply)      

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;      

来看 do_add_service

int do_add_service(struct binder_state *bs,
                   uint16_t *s, unsigned len,
                   void *ptr, unsigned uid, int allow_isolated)
{
    struct svcinfo *si;
    //ALOGI("add_service('%s',%p,%s) uid=%d\n", str8(s), ptr,
    //        allow_isolated ? "allow_isolated" : "!allow_isolated", uid);

    if (!ptr || (len == 0) || (len > 127))
        return -1;
           
// 判读调用者有没有权限
    if (!svc_can_register(uid, s)) {
      
ALOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n", str8(s), ptr, uid); return -1; }

si = find_svc(s, len); if (si) { //找到服务 if (si->ptr) { ALOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED, OVERRIDE\n", str8(s), ptr, uid); svcinfo_death(bs, si); } si->ptr = ptr; } else { si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); // 分配一个svcinfo 结构体和 name 的空间 if (!si) { ALOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n", str8(s), ptr, uid); return -1; } si->ptr = ptr; // service 的函数地址写入 si->len = len; memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); si->name[len] = '\0'; si->death.func = svcinfo_death; si->death.ptr = si; si->allow_isolated = allow_isolated; si->next = svclist; // 将服务添加到 svclist 链表中 svclist = si; } binder_acquire(bs, ptr); binder_link_to_death(bs, ptr, &si->death); return 0;}

来看 find_svc

struct svcinfo *find_svc(uint16_t *s16, unsigned len)
{
    struct svcinfo *si;

    for (si = svclist; si; si = si->next) {
        if ((len == si->len) &&
            !memcmp(s16, si->name, len * sizeof(uint16_t))) {
            return si;
        }
    }
    return 0;
}      

( 未完待续)

继续阅读