binder 分析(2)_client端程序

来源:互联网 发布:windows激活密匙在哪 编辑:程序博客网 时间:2024/06/11 06:18

注册服务过程:

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;}

( 未完待续)








0 0
原创粉丝点击