Android Binder机制的ServiceManager

    对于Android 来说,Binder进程间的通信机制几乎无处不在,可以说是整个Android系统中各个组件之间交互的灵魂。所以,想要深入的理解Android 中进程间通信的机制,还是需要对Binder机制有一个深入的研究的。

    Binder机制很复杂,设计到的东西特别多,很难一下将这些东西说清楚,到期该从何说起呢?不防就从Binder服务的管理者ServiceManger开始说起吧。

    servicemanager是一个独立的进程,在Android系统启动的时候有init.rc脚本,启动脚本如下:

service servicemanager /system/bin/servicemanager    class core    user system    group system    critical    onerestart zygote    onerestart media    onerestart surfaceflinger    ...

   有必要对上面的启动脚本进行解释一下子:

service servicemanager 表示该进程是以服务的形式运行的

class core 表示这个是核心服务

critical 表示很重要

onerestart zygote 表示该服务重启,需要重启zygote进程(后面的含义是一样的)。

Android 系统启动servicemanager之后,是让它不停地干活的,具体干什么活呢?既然是名字叫做ServiceManager,那么它既是用来管理系统service的,具体来说有两个功能1. addService ,即注册一个服务到系统中 2. getService,即返回服务的代理对象。对于这个两个功能的实现,且看servicemanager的main函数

代码路径为:frameworks/base/cmds/servicemanager/service_manager.c

int main(int argc, char **argv){    struct binder_state *bs; //ServiceManager的描述    bs = binder_open(128*1024);  //关键点1    if (!bs) {        ALOGE("failed to open binder driver\n");        return -1;    }    if (binder_become_context_manager(bs)) { //关键点2        ALOGE("cannot become context manager (%s)\n", strerror(errno));        return -1;    }
    ...  //中间为selinux相关代码, 和主题无关    //进入Binder 的loop中    binder_loop(bs, svcmgr_handler); //关键点3    return 0;}

对于main函数中标记的关键点做出解释:

1. binder_open:

    总的来说binder_open 干了三件事情:1. 打开/dev/binder 获得句柄值 2. 通过ioctl 查询Binder版本 3.映射地址空间

且看源码:

struct binder_state *binder_open(size_t mapsize){    struct binder_state *bs;    struct binder_version vers;    bs = malloc(sizeof(*bs));    if (!bs) {        errno = ENOMEM;        return NULL;    }    //1. 打开驱动    bs->fd = open("/dev/binder", O_RDWR);    if (bs->fd < 0) {        fprintf(stderr,"binder: cannot open device (%s)\n",                strerror(errno));        goto fail_open;    }    //2. ioctl    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {        fprintf(stderr,                "binder: kernel driver version (%d) differs from user space version (%d)\n",                vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);        goto fail_open;    }    //通过mmap将空间映射到用户空间    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;    }    return bs;fail_map:    close(bs->fd);fail_open:    free(bs);    return NULL;}

2. binder_become_context_manager

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

上面代码比较明显,即是通过ioctl来让servicemanger成为服务管理中心,并设置handle为0(这个0很重要,后续分析)

3. binder_loop

servicemanager将在这里完成系统交给它的使命:对service进行注册和返回其代理对象。

binder_loop(bs, svcmgr_handler); //bs携带者servicemanager的信息,svcmgr_handler则是一个回调函数
void binder_loop(struct binder_state *bs, binder_handler 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));  //告知binder驱动,servicemanager进入loop循环    for (;;) {        bwr.read_size = sizeof(readbuf);        bwr.read_consumed = 0;        bwr.read_buffer = (uintptr_t) readbuf;        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); //从binder驱动中读取数据        if (res < 0) {            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));            break;        }        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func); //解析数据,并传递func回调函数        if (res == 0) {            ALOGE("binder_loop: unexpected reply?!\n");            break;        }        if (res < 0) {            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));            break;        }    }}

上面的binder_loop循环会不断的通过ioctl从binder驱动中读取数据,并解析执行。在binder_parse中会解析出从binder驱动中读取的命令,然后通过servicemanager中注册的回调函数svcmgr_handler来执行具体的指令

int svcmgr_handler(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;    //一些条件判定的逻辑操作,这里省略    switch(txn->code) {    case SVC_MGR_GET_SERVICE:    case SVC_MGR_CHECK_SERVICE: //Client组件请求获取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); //执行getService操作        if (!handle)            break;        bio_put_ref(reply, handle); //将handle写入驱动        return 0;    case SVC_MGR_ADD_SERVICE: //Service请求注册到ServiceManager中        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,  //执行addService的操作            allow_isolated, txn->sender_pid))            return -1;        break;    case SVC_MGR_LIST_SERVICES: {   //查询所有的service操作        uint32_t n = bio_get_uint32(msg);        if (!svc_can_list(txn->sender_pid)) {            ALOGE("list_service() uid=%d - PERMISSION DENIED\n",                    txn->sender_euid);            return -1;        }        si = svclist;        while ((n-- > 0) && si)            si = si->next;        if (si) {            bio_put_string16(reply, si->name);            return 0;        }        return -1;    }    default:        ALOGE("unknown code %d\n", txn->code);        return -1;    }    bio_put_uint32(reply, 0);    return 0;}

首先看addService的请求操作

int do_add_service(struct binder_state *bs,                   const uint16_t *s, size_t len,                   uint32_t handle, uid_t uid, int allow_isolated,                   pid_t spid){//servicemanager中通过一个链表来维护所有注册进来的service组件    struct svcinfo *si; //svcinfo 是service链表的一个节点    //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,    //        allow_isolated ? "allow_isolated" : "!allow_isolated", uid);    if (!handle || (len == 0) || (len > 127))        return -1;    if (!svc_can_register(s, len, spid, uid)) {  //检测该service是否可以进行注册到ServiceManager        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",             str8(s, len), handle, uid);        return -1;    }    si = find_svc(s, len);    if (si) { //如果已经注册了,将不再注册        if (si->handle) {            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",                 str8(s, len), handle, uid);            svcinfo_death(bs, si);        }        si->handle = handle;    } else { //开始将service注册到ServiceManager中        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));        if (!si) {            ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",                 str8(s, len), handle, uid);            return -1;        }        si->handle = handle;        si->len = len;        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));        si->name[len] = '\0';        si->death.func = (void*) svcinfo_death;        si->death.ptr = si;        si->allow_isolated = allow_isolated;        si->next = svclist;        svclist = si;    }    binder_acquire(bs, handle);  //将service注册到binder驱动中, 通过binder_write 将命令写入binder驱动    binder_link_to_death(bs, handle, &si->death);    return 0;}

getService和addService很相似,这里就不再贴代码了。 getService时也是通过查询ServiceManager维护的链表,然后返回其handle。好像getService时没有和binder驱动进行交互(但是binder驱动的引用计数和这个也关系的)。

到这里ServiceManager进行的启动大的大致过程讲完了,但是这里还有很多细节问题的问题是没有说到的。亲爱的读者,你有没有发现,ServiceManager进程确实是实现了对service组件的管理,ServiceManager进程现在还没有提供任何进行addService和getService的接口。在Native层要注册addService或者getSerivce是通过IServiceManager接口进行的,IServiceManager接口到底是怎么和servicemanager进程之间建立联系的。以及,当前仅仅介绍了servicemanager进程启动,还没有真正的进入binder的世界。 

未完,待续。。。

更多相关文章

  1. C语言函数以及函数的使用
  2. 《Android开发艺术探索》第十章Android的消息机制+第十一章Andro
  3. 理解Android回调函数
  4. 《Android Dev Guide》系列教程5:Android进程和线程
  5. Android 消息处理机制(Looper、Handler、MessageQueue,Message)
  6. Android 消息机制
  7. Android结束进程的方法
  8. Android触摸事件分发机制详解

随机推荐

  1. TextView 属性详解
  2. android布局layout中的一些属性
  3. Android(安卓)设置控件是否可见
  4. android开发之设置Edittext密码的方法
  5. Android布局文件中命名空间的解析
  6. Android布局文件中命名空间的解析
  7. Android(安卓)线程优先级设置方法
  8. android 滚动条 相关属性
  9. Android分享文稿 ( by quqi99 )
  10. Android,UI主线程与子线程