android servicemanager与binder源码分析一 ------ native层的ServiceManager

前一阵子在忙项目,没什么更新,这次开始写点android源码内部的东西分析下。以6.0.1_r10版本android源码为例。
servicemanager是android服务管理,非常基础的组件之一,分析他的目的是能够深入看到binder的一些处理方式。在开始前先说下阅读源码或者非常复杂代码的方式,我的方式是层级进入,一层掌握脉络之后如果感兴趣再对具体的点深入分析了解,并且每层进行总结,这样我认为会比较好理解,也不容易产生一个点一直走下去,最后迷失在复杂繁琐的代码里的情况。当然我只代表我个人的体验。东西是写给自己的,如果能帮到他人我会非常高兴。

然后这里推荐下罗升阳先生的博客文章,确实非常不错,可以作为阅读参考。

servicemanager源码位于/frameworks/native/cmds/servicemanager/service_manager.c下:

347int main(int argc, char  argv)348{349    struct binder_state *bs;350351    bs = binder_open(128*1024);352    if (!bs) {353        ALOGE("failed to open binder driver\n");354        return -1;355    }356357    if (binder_become_context_manager(bs)) {358        ALOGE("cannot become context manager (%s)\n", strerror(errno));359        return -1;360    }361362    selinux_enabled = is_selinux_enabled();363    sehandle = selinux_android_service_context_handle();364    selinux_status_open(true);365366    if (selinux_enabled > 0) {367        if (sehandle == NULL) {368            ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");369            abort();370        }371372        if (getcon(&service_manager_context) != 0) {373            ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");374            abort();375        }376    }377378    union selinux_callback cb;379    cb.func_audit = audit_callback;380    selinux_set_callback(SELINUX_CB_AUDIT, cb);381    cb.func_log = selinux_log_callback;382    selinux_set_callback(SELINUX_CB_LOG, cb);383384    binder_loop(bs, svcmgr_handler);385386    return 0;387}

1.binder_open打开binder驱动设备;
2.binder_become_context_manager(bs),将自己作为binder的管理者;
3.binder_loop(bs, svcmgr_handler),进入循环,作为server等待client的请求;

binder_open

位于/frameworks/native/cmds/servicemanager/binder.c:

96struct binder_state *binder_open(size_t mapsize)97{98    struct binder_state *bs;99    struct binder_version vers;100101    bs = malloc(sizeof(*bs));102    if (!bs) {103        errno = ENOMEM;104        return NULL;105    }106107    bs->fd = open("/dev/binder", O_RDWR);108    if (bs->fd fd, BINDER_VERSION, &vers) == -1) ||115        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {116        fprintf(stderr,117                "binder: kernel driver version (%d) differs from user space version (%d)\n",118                vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);119        goto fail_open;120    }121122    bs->mapsize = mapsize;123    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);124    if (bs->mapped == MAP_FAILED) {125        fprintf(stderr,"binder: cannot map device (%s)\n",126                strerror(errno));127        goto fail_map;128    }129130    return bs;131132fail_map:133    close(bs->fd);134fail_open:135    free(bs);136    return NULL;137}

首先,建立一个结构体binder_state,然后剩下的就是给这个结构体的成员赋值。bs->fd给打开的驱动设备文件描述符;bs->mapped给内存映射地址;
插一句,这里对goto的应用很规范,可见任何语句并非有好与不好,而在于怎么用。
看到这里其实可以猜测,binder的机制就是内存映射,或者可以说是文件映射,因为在linux上任何的设备都可以看做是文件。
现在不要深入,往回看,之前的service_manager.c的main函数里,后面就要走binder_become_context_manager这个将自己设为binder管理者。

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

这里就做了一件事儿,就是下发控制字,告诉驱动设置context管理者为0,这里也可以猜测,这个0代表一定含义,应该就是servicemanager自己,后面再继续解释这个问题。

binder_looper

372void binder_loop(struct binder_state *bs, binder_handler func)373{374    int res;375    struct binder_write_read bwr;376    uint32_t readbuf[32];377378    bwr.write_size = 0;379    bwr.write_consumed = 0;380    bwr.write_buffer = 0;381382    readbuf[0] = BC_ENTER_LOOPER;383    binder_write(bs, readbuf, sizeof(uint32_t));384385    for (;;) {386        bwr.read_size = sizeof(readbuf);387        bwr.read_consumed = 0;388        bwr.read_buffer = (uintptr_t) readbuf;389390        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);391392        if (res data.ptr.buffer, res);247            }248            ptr += sizeof(*txn);249            break;250        }251        case BR_REPLY: {252            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;253            if ((end - ptr) func(bs, death->ptr);272            break;273        }274        case BR_FAILED_REPLY:275            r = -1;276            break;277        case BR_DEAD_REPLY:278            r = -1;279            break;280        default:281            ALOGE("parse: OOPS %d\n", cmd);282            return -1;283        }284    }285286    return r;287}

刚才从驱动设备读取的buffer的前32位取出来作为cmd进行switch判断处理。BR_代表从设备驱动反馈的命令,BR_TRANSACTION字面看是交易,那么可以猜测是对接受到的发送方(client)的内容进行处理。往下看,BR_TRANSACTION流程里,先把收到的数据转成binder_transaction_data结构,然后走了binder_dump_txn,这里基本上就是输出一些信息,不太关注。之后是关键的部分,调用了func,这个东西是个binder_handler,其实看看定义就知道,是个回调函数,回到servicemanager里面的main,可以看到是个svcmgr_handler,具体内容也在servicemanager里面,如下:

244int svcmgr_handler(struct binder_state *bs,245                   struct binder_transaction_data *txn,246                   struct binder_io *msg,247                   struct binder_io *reply)248{249    struct svcinfo *si;250    uint16_t *s;251    size_t len;252    uint32_t handle;253    uint32_t strict_policy;254    int allow_isolated;255256    //ALOGI("target=%p code=%d pid=%d uid=%d\n",257    //      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);258259    if (txn->target.ptr != BINDER_SERVICE_MANAGER)260        return -1;261262    if (txn->code == PING_TRANSACTION)263        return 0;264265    // Equivalent to Parcel::enforceInterface(), reading the RPC266    // header with the strict mode policy mask and the interface name.267    // Note that we ignore the strict_policy and don't propagate it268    // further (since we do no outbound RPCs anyway).269    strict_policy = bio_get_uint32(msg);270    s = bio_get_string16(msg, &len);271    if (s == NULL) {272        return -1;273    }274275    if ((len != (sizeof(svcmgr_id) / 2)) ||276        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {277        fprintf(stderr,"invalid id %s\n", str8(s, len));278        return -1;279    }280281    if (sehandle && selinux_status_updated() > 0) {282        struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();283        if (tmp_sehandle) {284            selabel_close(sehandle);285            sehandle = tmp_sehandle;286        }287    }288289    switch(txn->code) {290    case SVC_MGR_GET_SERVICE:291    case SVC_MGR_CHECK_SERVICE:292        s = bio_get_string16(msg, &len);293        if (s == NULL) {294            return -1;295        }296        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);297        if (!handle)298            break;299        bio_put_ref(reply, handle);300        return 0;301302    case SVC_MGR_ADD_SERVICE:303        s = bio_get_string16(msg, &len);304        if (s == NULL) {305            return -1;306        }307        handle = bio_get_ref(msg);308        allow_isolated = bio_get_uint32(msg) ? 1 : 0;309        if (do_add_service(bs, s, len, handle, txn->sender_euid,310            allow_isolated, txn->sender_pid))311            return -1;312        break;313314    case SVC_MGR_LIST_SERVICES: {315        uint32_t n = bio_get_uint32(msg);316317        if (!svc_can_list(txn->sender_pid)) {318            ALOGE("list_service() uid=%d - PERMISSION DENIED\n",319                    txn->sender_euid);320            return -1;321        }322        si = svclist;323        while ((n-- > 0) && si)324            si = si->next;325        if (si) {326            bio_put_string16(reply, si->name);327            return 0;328        }329        return -1;330    }331    default:332        ALOGE("unknown code %d\n", txn->code);333        return -1;334    }335336    bio_put_uint32(reply, 0);337    return 0;338}

简单看下,就是对传递的数据的具体处理,包括了addservice等具体的过程处理。暂时先不深究。

至此我们可以看出来,servicemanager->binder.c这层基本上就是servicemanager提供系统的服务管理,binder.c提供对驱动设备的操作api。整个过程再梳理下:
1.打开binder驱动设备;
2.将自己作为binder上下文的管理者,通过binder.c传递0给设备驱动(ioctrl);
3.进入binder_looper循环,不停从binder设备驱动读取内容,并解析,然后根据cmd判断后抛给servicemanager进行真正处理;
4.servicemanager里再根据读取到的数据内容来决定进行各种cmd动作的处理,包括addservice等;
这么看这一层的脉络基本上比较清晰了。这么写把binder独立了出来作为一个api层,可以搭载任何的生成调用,也就是说binder.c这一层只管与binder设备驱动通讯,其余的抛给调用者,很标准聪明的解耦。

关键字:java, #c++# c


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部