Android Binder - Service Manager

来源:互联网 发布:知乎 大鹏 装修 编辑:程序博客网 时间:2024/06/06 01:36

Service Manager是所有服务的管理器,因此,所有Server(System Server)都要向它注册,应用程序则向Service Manager查询相应的服务。其实现位于"frameworks/base/cmds/servicemanager\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)) {        LOGE("cannot become context manager (%s)\n", strerror(errno));        return -1;    }    svcmgr_handle = svcmgr;    binder_loop(bs, svcmgr_handler);    return 0;}

首先调用binder_open打开binder设备/dev/binder,参数mapsize指定了需要映射的内存大小,为什么要进行映射呢,什么地方会用到映射地址bs->mapped呢?

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

然后调用binder_become_context_manager使得它称为context manager,也就是Service manager,这个特殊的服务用来管理其他的所有服务。

int binder_become_context_manager(struct binder_state *bs){           return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);}

Service Manager监听请求

Service Manager通过ioctl BINDER_SET_CONTEXT_MGR向Binder驱动声明自己是服务管理器,作为服务管理器有两个最重要的工作,接收其他server的服务注册; 为客户端提供查询和获取服务。因此Service最后会进入一个监听循环,等待用户的请求,并使用srcmgr_handler回调函数处理用户请求。

void binder_loop(struct binder_state *bs, binder_handler func){           int res;    struct binder_write_read bwr;    unsigned readbuf[32];         bwr.write_size = 0;    bwr.write_consumed = 0;    bwr.write_buffer = 0;     readbuf[0] = BC_ENTER_LOOPER;    binder_write(bs, readbuf, sizeof(unsigned));    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) {            LOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));            break;        }        res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);        if (res == 0) {            LOGE("binder_loop: unexpected reply?!\n");            break;        }        if (res < 0) {            LOGE("binder_loop: io error %d %s\n", res, strerror(errno));            break;        }    }}

在Service Manager能够服务Server和client的请求之前,要设置bind proc为 LOOPER_ENTER状态,然后调用ioctl BINDER_WRITE_READ等待来自Server和Client的请求,这个ioctl是个阻塞的操作,直到有请求进入,才会返回

binder_parse分析@readbuf中的请求,bwr.read_consumed是请求的长度,@func是请求处理函数


ServiceManager数据结构

 90 struct svcinfo 91 { 92     struct svcinfo *next; 93     void *ptr; 94     struct binder_death death; 95     unsigned len; 96     uint16_t name[0]; 97 };

每一个svcinfo代表一个注册的service

@next,所有的service通过next链接到全局变量svclist

@ptr,虽然从命名上是一个pointer,但是存储的是一个handle,一般来说从0x01开始,0x00保留给service manager自身。

@len,name的长度

@name,是service名字,client端要通过这个名字找到匹配的服务。


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是用来生成binder message的辅助结构

@data 是当前可用buffer位置,这个地址随着加入数据,而改变

@offs 是当前可用的offset buffer位置,可以用来存放obj相对于@data0的偏移地址,4bytes

@data_avail 当前可用的data空间大小

@offs_avail 当前空用的offsets大小

@data0 data buffer的起始位置,data0记录着binder_io数据buffer的起始位置

@offs0 offset buffer的起始位置,offs0记录着binder_io offset buffer的起始位置

从@data0 ~ @data保存着对象,@offs0 ~ @offs保存着obj的偏移位置,这个偏移位置是obj地址相对于@data0的偏移位置




原创粉丝点击