ServiceManager源码分析

ServiceManager在Android系统中占有非常重要的地位,它是系统中所有服务的"大管家",我们熟知的AMS,PMS,PKM等都会被注册进ServiceManager,其他进程如果需要用这些系统服务,可以从ServiceManager中查询,ServiceManager运行在一个单独的进程,由init进程启动。

init进程会解析它的启动配置文件,来启动ServiceManager进程。启动配置文件如下:

//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

可以看到如果ServiceManager进程重启了healthd、zygote、audioservermedia、surfaceflinger等进程都会重启。

ServiceManager进程的源文件为service_manager.c。进程创建后就会去执行它的入口函数也就是main方法。

//service_manager.c
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";
    }
    //1、打开binder驱动
    bs = binder_open(driver, 128*1024);
​
    //2、把自己变为binder的管理者
    if (binder_become_context_manager(bs)) {
        return -1;
    }
​
    //3、进入loop循环,等待其他进程的发过来的消息
    binder_loop(bs, svcmgr_handler);
​
    return 0;
}
​

在main方法中一共做了3件事。

1、打开binder驱动,调用了 binder_open

struct binder_state *binder_open(const char* driver, size_t mapsize)
{
    struct binder_state *bs;
    struct binder_version vers;
    
    bs = malloc(sizeof(*bs));
   
    //打开binder驱动,在linux中一切皆文件,驱动也是文件。
    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    if (bs->fd < 0) {
        goto fail_open;
    }
​
    //最终会调用binder_ioctl函数,获取binder的版本,检查版本是否正确
    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;
    }
​
    bs->mapsize = mapsize;
    //映射一块虚拟内存到binder,最终调用的是binder_mmap() 函数
    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;
}

ioctl方法最终会调用binder驱动层的binder_ioctl方法,用来向驱动层发送命令。

2、把自己变为binder的管理者

int binder_become_context_manager(struct binder_state *bs)
{
    //发送BINDER_SET_CONTEXT_MGR给驱动层,把自己注册为binder的管理者
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

这里说一下,为什么ServiceManager进程要把自己注册为为binder驱动的管理者,学习过 SystemServer就会发现,系统的服务在创建后都会把自己注册到ServiceManager中,比如 PackageManagerService ,如下:

PackageManagerService m = new PackageManagerService(context, installer,
                factoryTest, onlyCore);
ServiceManager.addService("package", m);

通过这行代码就可以找到并且调用到ServiceManager进程中,就是因为之前ServiceManager发送BINDER_SET_CONTEXT_MGR给驱动层,把自己注册为binder的管理者,并且它的句柄handle是0,任何进程都可以通过0号句柄来访问ServiceManager ,其他的 Server 的句柄都是大于0的值。

这里提前提一下,把系统服务注册到ServiceManager进程,其实只是在ServiceManager中绑定了服务的名称和binder驱动层给该系统服务分配的handle句柄。真正的binder实体是注册在binder驱动层的。当调用ServiceManager.getService(String name)方法,会通过0号句柄调用到ServiceManager进程,然后找到与该服务名对应的handle句柄,拿到句柄后由驱动层返回对应的binder实体,先有个印象即可。

3、进入loop循环,等待binder驱动层的消息

//binder.c
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;
    //向binder驱动写入命令,表示自己进入了loop循环。
    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(uint32_t));
​
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
        //开始读取消息,如果读取到数据会保存在readbuf
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
​
        //解析读取到的数据
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
    }
}

BINDER_WRITE_READ命令既可以用来读取数据,也可以用来写入数据,具体是读还是写需要看binder_write_read结构体的write_size和read_size,哪个大于0那么这个命令就是干什么的。可以看到上面调用了

bwr.read_size = sizeof(readbuf),因此BINDER_WRITE_READ命令是用来读取数据。读取到数据后会调用binder_parse来进行解析。

//binder.c
int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;
    //如果没有读取到最后就while循环继续读取
    //因为数据中可能包含了多条命令
    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        switch(cmd) {
        ...
        //如果是BR_TRANSACTION命令
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                ALOGE("parse: txn too small!\n");
                return -1;
            }
            binder_dump_txn(txn);
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;
​
                bio_init(&reply, rdata, sizeof(rdata), 4);
                bio_init_from_txn(&msg, txn);
                //调用func函数
                res = func(bs, txn, &msg, &reply);
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    //向binder驱动写入处理的结果reply
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
            }
            ptr += sizeof(*txn);
            break;
        }
        ...
    }
    return r;
}

这里主要看下func函数,这个函数是在service_manager.main中传过来的函数指针,其实现如下:

//service_manager.c
int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    //在service_manager中,所有的系统服务都对应svcinfo结构体
    struct svcinfo *si;
    ...
    switch(txn->code) {
    //如果获取服务,就会进入这个分支,对应ServiceManager中的getService(String name)
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        //获取传过来的数据中的服务名称
        s = bio_get_string16(msg, &len);
        //通过服务名称去查询服务
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        //把handle写入reply
        bio_put_ref(reply, handle);
        return 0;
    //如果是添加服务会进入这个分支,对应ServiceManager中的addService
    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;
    //如果是查询所有的服务会进入这个分支,对应ServiceManager中的listServices
    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;
}

这里主要看下SVC_MGR_GET_SERVICE和SVC_MGR_ADD_SERVICE分支。

查询服务最终调用了do_find_service。

//service_manager.c
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
    //根据名称获取对应的svcinfo结构体
    struct svcinfo *si = find_svc(s, len);
​
    //检查是否有权限获取
    if (!svc_can_find(s, len, spid, uid)) {
        return 0;
    }
    //返回名称对应的服务句柄。
    return si->handle;
}

获取svcinfo结构体是通过find_svc方法,代码如下:

//service_manager.c
struct svcinfo *find_svc(const uint16_t *s16, size_t 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 NULL;
}

那么SVC_MGR_ADD_SERVICE又是如何添加服务的呢?

case SVC_MGR_ADD_SERVICE:
        //获取名称
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //获取handle句柄
        handle = bio_get_ref(msg);
        //调用do_add_service把名称和handle传入,进行服务的添加
        if (do_add_service(bs, s, len, handle, txn->sender_euid,
            allow_isolated, txn->sender_pid))
            return -1;
        break;

do_add_service代码如下:

//service_manager.c
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)
{
    struct svcinfo *si;
​
    //是否有权限注册服务
    if (!svc_can_register(s, len, spid, uid)) {
        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
             str8(s, len), handle, uid);
        return -1;
    }
    //通过服务名称查询,看之前是否注册过了
    si = find_svc(s, len);
    if (si) {
        //如果之前注册过相同名称的服务,就释放,重新设置handle
        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 {
        //如果之前没有注册过
        //给si分配内存,进行一些值的设置,然后把si插入svclist链表的头部
        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;
    }
    ...
    return 0;
}

到这里流程就分析完成了。

总结: ServiceManager 通过记录服务 name 和 handler 的关系,提供服务注册与查询功能,其他进程比如我们的应用进程,如果需要使用AMS,就会通过服务的名称来 ServiceManager 进程查询,找到对应的handle句柄,至于binder驱动层如何通过handle找到真实的binder实体,暂不在本篇的讨论范围。其他进程可以通过服务名称到ServiceManager 查询到对应服务的handle,那么ServiceManager自己又是如何被其他进程获知的呢?这是因为ServiceManager 的handle值为0,这是一个保留的,专门给ServiceManager 用的handle。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值