android 系统核心机制binder(05)servicemanager详解

198 篇文章 98 订阅

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

这里主要对service_manager进程进行了分析,关注 进程的流程和 两个处理流程(添加服务和 获取服务)。

通过分析service_manager,进而对add_service请求的处理流程进行分析。通过这样的分析,后面 getservice的流程也是类似的。

1 service_manager的主函数main的分析

说明:在源码分析时,由于Binder中SELinux的东西比较多,起初的分析容易影响我们对Binder主干的影响,因此在分析前期,将所有SELinux相关的函数均直接无视

这里service_manager起到的作用实际上是BnServiceManager的作用,即处理请求。ServiceManager的入口函数为:

int main(int argc, char **argv)
{
    struct binder_state *bs;    
    bs = binder_open(128*1024);    //1:open & mmap binder
    ...
    if (binder_become_context_manager(bs)) {//2:become ctx Manager
        ...
    }
    svcmgr_handle = BINDER_SERVICE_MANAGER;//
    binder_loop(bs, svcmgr_handler);//3:binder loop,处理客户端发送来的请求
 
    return 0;
}

从main函数中可以看出,它主要做了4件事情:

  1. 打开/dev/binder设备,并在内存中映射128K的空间。
  2. 通知Binder设备,把自己变成context_manager
  3. 设置SELinux相关(这里忽略)
  4. 进入循环,不停的去读Binder设备,查询请求,若有则会调用svcmgr_handler函数回调处理请求。

    这里对binder_open和binder_become_context_manager分别进行简要分析

1.1 binder_open的代码实现如下:

struct binder_state *binder_open(size_t mapsize)
{
    struct binder_state *bs;
    struct binder_version vers;
 
    bs = malloc(sizeof(*bs));
    ...
    bs->fd = open("/dev/binder", O_RDWR);
    ...
    bs->mapsize = mapsize;
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    if (bs->mapped == MAP_FAILED) {
        ...
    }
    return bs;
    ...
}

    这里主要负责打开设备,并进行内存映射

1.2 binder_become_context_manager的代码实现如下所示:

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

    这里表示成为handle为0的manager,在驱动层就是建立了第一个binder_node红黑树节点。

1.3 binder_loop的代码实现如下所示:

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));
 
    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_parse,最后会调用func来处理 */
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        ...
    }
}

1.4 这里关键代码为binder_parse,继续分析,代码如下所示:

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 (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        switch(cmd) {
            ...
        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);
                res = func(bs, txn, &msg, &reply);
                binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
            }
            ptr += sizeof(*txn);
            break;
        }
        case BR_REPLY: 
            ...
        case BR_DEAD_BINDER: {
            struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;
            ptr += sizeof(binder_uintptr_t);
            death->func(bs, death->ptr);
            break;
        }
        ...
        default:
            ALOGE("parse: OOPS %d\n", cmd);
            return -1;
        }
    }
 
    return r;
}

    这里,当cmd为BR_TRANSACTION或者BR_DEAD_BINDER时,会使用func来处理,func的值为svcmgr_handler

1.5 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;
    
    /* 这里再判断一下target.handle 是不是0,即请求是不是发给自己的*/
    if (txn->target.handle != svcmgr_handle)
        return -1;
    if (txn->code == PING_TRANSACTION)
        return 0;
 
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);
    if (s == NULL) {
        return -1;
    }
    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s, len));
        return -1;
    }
    if (sehandle && selinux_status_updated() > 0) {
        struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
        if (tmp_sehandle) {
            selabel_close(sehandle);
            sehandle = tmp_sehandle;
        }
    }
    switch(txn->code) {
    /* 获得某个服务的信息 */
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_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);
        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)) {
            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;
}

从handler这里开始 我们来分析 获取服务和添加服务的两大流程

2 添加服务 流程分析 

继续分析do_add_service的实现,代码如下所示:

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 (!handle || (len == 0) || (len > 127))
        return -1;
    /* 比较注册进程的uid和名字,看是否有权限注册,这里采用MAC模式检测 */ 
    if (!svc_can_register(s, len, spid)) {
        return -1;
    }
 
    si = find_svc(s, len); //这个主要是查询服务是否注册过,注册过就不会再注册
    if (si) {
        if (si->handle) {
            svcinfo_death(bs, si);
        }
        si->handle = handle;
    } else {
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {
            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;  /* service退出的通知函数 */
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        /* svclist是一个list,保存了当前注册到ServiceManager中的信息 */
        si->next = svclist;
        svclist = si;
    }
 
    binder_acquire(bs, handle);
    /* 当服务进程退出后,SM可以做些清理工作,例如释放前面malloc出来的si */
    /* binder_link_to_death会做这项工作,每当服务进程退出时,SM都会得到来自binder设备的通知 */
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

添加服务的逻辑即:将驱动层收到的消息【“服务名”和对应分配的handle】添加到 svcinfo服务链表中,插入一个新节点

同时,下面是一些额外的说明,主要针对 注册权限相关的问题进行分析

2.1 svc_can_register在android5.0之前的实现与分析

    svc_can_register主要用来判断注册服务的进程是否有权限,代码如下所示:

int svc_can_register(unsigned uid, uint16_t *name)
{
    unsigned n;    
    //如果用户是root或者system,则权限够高,允许注册
    if ((uid == 0) || (uid == AID_SYSTEM))
        return 1;
    for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++)
        if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name))
            return 1;
 
    return 0;
}

   allowed数组控制那些权限达不到root和system的进程,定义如下所示:

/* TODO: 
 * These should come from a config file or perhaps be
 * based on some namespace rules of some sort (media
 * uid can register media.*, etc)
 */
static struct {
    unsigned uid;
    const char *name;
} allowed[] = {
    { AID_MEDIA, "media.audio_flinger" },
    { AID_MEDIA, "media.log" },
    { AID_MEDIA, "media.player" },
    { AID_MEDIA, "media.camera" },
    { AID_MEDIA, "media.audio_policy" },
    { AID_DRM,   "drm.drmManager" },
    { AID_NFC,   "nfc" },
    { AID_BLUETOOTH, "bluetooth" },
    { AID_RADIO, "radio.phone" },
    { AID_RADIO, "radio.sms" },
    { AID_RADIO, "radio.phonesubinfo" },
    { AID_RADIO, "radio.simphonebook" },
/* TODO: remove after phone services are updated: */
    { AID_RADIO, "phone" },
    { AID_RADIO, "sip" },
    { AID_RADIO, "isms" },
    { AID_RADIO, "iphonesubinfo" },
    { AID_RADIO, "simphonebook" },
    { AID_RADIO, "phone_msim" },
    { AID_RADIO, "isms_msim" },
    { AID_RADIO, "iphonesubinfo_msim" },
    { AID_RADIO, "simphonebook_msim" },
    { AID_MEDIA, "common_time.clock" },
    { AID_MEDIA, "common_time.config" },
    { AID_KEYSTORE, "android.security.keystore" },
    { AID_MEDIA, "listen.service" }
};

   这样就可以查询对应的uid是否可以有注册服务name的权限了

   如果Server进程权限不够root和system,那么要在allowed中添加相应的项

2.2 svc_can_register在android5.0之后的实现与分析

    在android5.0之后,注册检查的方式放生了改变,使用了MAC机制检测,从svc_can_register开始分析,代码如下:

static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid)
{
    const char *perm = "add";
    return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0;
}

    继续分析,check_mac_perms_from_lookup的具体实现如下:

static bool check_mac_perms_from_lookup(pid_t spid, const char *perm, const char *name)
{
    bool allowed;
    char *tctx = NULL;
 
    if (selinux_enabled <= 0) {
        return true;
    }
 
    if (!sehandle) {
        ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
        abort();
    }
 
    if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {
        ALOGE("SELinux: No match for %s in service_contexts.\n", name);
        return false;
    }
 
    allowed = check_mac_perms(spid, tctx, perm, name);
    freecon(tctx);
    return allowed;
}

   接下来就是使用MAC检测机制了,check_mac_perms就是调用sepolicy机制中的函数。

3 获取服务 流程分析

继续分析do_find_service的实现,代码如下所示:


uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
    struct svcinfo *si;

    if (!svc_can_find(s, len, spid)) {//这里也是权限相关检查
        ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n",
             str8(s, len), uid);
        return 0;
    }
    si = find_svc(s, len); //这里查询服务,遍历链表
    //ALOGI("check_service('%s') handle = %x\n", str8(s, len), si ? si->handle : 0);
    if (si && si->handle) {
        if (!si->allow_isolated) {
            // If this service doesn't allow access from isolated processes,
            // then check the uid to see if it is isolated.
            uid_t appid = uid % AID_USER;
            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
                return 0;
            }
        }
        return si->handle;
    } else {
        return 0;
    }
}

在这里,继续分析find_svc函数,代码实现如下:

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

在这里遍历整个svcinfo 的链表,从而完成对服务的查找,找到后流程上返回 handle。

4 总结

    服务的注册流程本质上就是将服务信息放到系统维护的一个链表上,获取服务时,只需要查这个链表就可以了。

    service_manager存在的意义:集中管理系统内所有服务,施加权限控制,保证并非任何进程都能注册服务。

    系统中因为各种原因,Server进程生死无常,ServiceManager将其统一管理。Client只需要查询service_manager就可以获得最新动向,得到最新信息,就算是服务端挂了,也会受到对应的通知。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

图王大胜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值