图解ServiceManager的启动过程

概述

笔者阅读了很多博客和相关书籍,自己也浏览了Android8.1系统源代码中关于ServiceManager的部分,有些书中称ServiceManagerBinder机制中DNS服务器,负责某Binder服务在ServiceManager注册时提供的名称底层Binder驱动分配的值的解析,我觉得这么理解倒也很贴切,在笔者整理关于ServiceManager的这篇博客时,发现想绕过Binder机制来单独来分析ServiceManager不太现实,而将BinderServiceManager合并一起来分析,篇幅过长,因此,笔者还是觉得先从最基本的开始,由简入深,逐个击破。

ServiceManager的启动

之前的博客已经大致分析了Android系统的启动过长,也大致了解了启动过程,今天的主角是ServiceManagerServiceManager分为framework层native层,我们这里要说的native层ServiceManager,它在system/core/rootdir/init.rc脚本中描述并由init进程启动。

下面是关于init.rc脚本中,关于servicemanager启动的描述:

on post-fs
	......
    load_system_props
    # start essential services
    start logd
    //启动servicemanager
    start servicemanager
    start hwservicemanager
    start vndservicemanager

这里对应frameworks/native/cmds/servicemanager.rc描述脚本

service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    writepid /dev/cpuset/system-background/tasks
    shutdown critical

在学习源码的过程中,笔者强烈建议大家用画图的形式来理解这些模块的实现机制,这里笔者综合一些优秀的博文和一些书籍(文章结尾参考)以及笔者阅读Android8.1系统源代码相关的模块整理出的一张启动流程图

你一定很疑惑,上面那张图里面为什么会有两个binder.c的源代码,这里要说明的是native层的那个binder.c源代码frameworks/native/cmds/servicemanager这个目录

它的实现如下:

struct binder_state *binder_open(const char* driver, size_t mapsize)
{
    ......
    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    ......
    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        ......
    }
    bs->mapsize = mapsize;
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    ......
    return NULL;
}

binder_open为例,它实际是对用户空间open,mmap,ioctl等操作的封装,用户态的程序调用内核层驱动需要陷入内核态,进行系统调用Syscall,比如打开Binder驱动方法的调用链为:open-> __open() -> binder_open()。 open()为用户空间的方法,__open()便是系统调用中相应的处理方法,通过查找,对应调用到内核binder驱动的binder_open()方法,其他的从用户态陷入内核态的流程也基本一致,而内核层的那个binder.c源代码则对应goldfish/drivers/staging/android/binder.c,它会通过copy_from_user和copy_to_user函数和用户空间以共享内存的方式进行数据交换

启动过程分析

下面是native层的源代码frameworks/native/cmds/servicemanager/service_manager.c中比较关键的几个函数,servicemanager进程启动之后会从main函数执行:

int main(int argc, char** argv)
{
    struct binder_state *bs;
    union selinux_callback cb;
    char *driver;

    if (argc > 1) {
        driver = argv[1];
    } else {
        driver = "/dev/binder";
    }
    //打开/dev/binder驱动,映射区块大小为128K
    bs = binder_open(driver, 128*1024);

    ......

    //有些书上说是将自己注册成`Binder机制`的管家,当然你也可以这么理解
    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    ......

    //进入循环等待客户进程的请求
    binder_loop(bs, svcmgr_handler);

    return 0;
}

基于事件驱动的消息循环模型:

void binder_loop(struct binder_state *bs, binder_handler func)
{
    ......

    binder_write(bs, readbuf, sizeof(uint32_t));

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

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

        ......
    }
}

下面这个函数,是我们在binder_loop循环里,经过binder_parse处理后,最终回调的一个函数:

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    ......
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //遍历内部链表,获取目标Server对象的句柄
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        bio_put_ref(reply, handle);
        return 0;

    case SVC_MGR_ADD_SERVICE:
        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,
            allow_isolated, txn->sender_pid))
            return -1;
        break;

    case SVC_MGR_LIST_SERVICES: {
        uint32_t n = bio_get_uint32(msg);

        if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
            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;
}

struct svcinfo
{
    struct svcinfo *next;
    uint32_t handle;
    struct binder_death death;
    int allow_isolated;
    size_t len;
    uint16_t name[0];
};

struct svcinfo *svclist = NULL;

有了上述的代码块,看到了do_add_servicedo_find_servicesvcinfo等相关关键字,这些是干什么的呢?你可以按照你对进程间通信等的理解,猜猜看,这些操作实现的具体作用?

其实在servicemanager内部维护着一个svclist链表,用于存储所有Server相关信息,查询和注册都是基于这个数据结构展开的
当函数svcmgr_handler处理完成之后,binder_parse会进一步通过binder_send_reply来将执行结果返回给底层的Binder驱动,进而传递给客户端进程
接着binder_parse会进入下一轮的循环

由上面的过程我们基本可以归纳出,servicemanager的启动过程由三个步骤组成:

1. 通过binder_open()打开设备文件/dev/binder,以及将它映射到本进程的地址空间;
2. 通过binder_become_context_manager()将自己注册为Binder进程间通信机制的上下文管理者;
3. 通过binder_loop()来循环等待并通过binder_parse()处理Client进程的通信请求。

小结

当然了,关于ServiceManagerBinder通信机制远比想象的要复杂,后续笔者会基于进程间通信有更详细的博客来逐步分析。

参考

https://blog.csdn.net/freekiteyu/article/details/70082302
《Android系统源代码情景分析》
《深入理解android内核设计思想 第2版》

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值