servicemanager的启动简介

Android  源码分析  2023年8月18日 am8:08发布1年前 (2023)更新 城堡大人
109 0 0

前言

Android源码分析《mediaserver的启动》时涉及到mediaserver服务的添加和获取(之前没有细说),而管理这些服务的就是servicemanager这个类,也就是今天介绍的主角。

涉及文件

frameworks\native\cmds\servicemanager\service_manager.c
frameworks\native\cmds\servicemanager\servicemanager.rc
frameworks\native\cmds\servicemanager\binder.c
frameworks\native\cmds\servicemanager\Android.bp

正文

这里只是简单的走一下流程,知道servicemanager是一个服务管理者,提供服务的注册和查询功能。

servicemanager的启动

根据之前源码分析,知道大部分服务都是在init中解析rc文件启动的。

servicemanager的启动rc文件是servicemanager.rc。

# servicemanager.rc
# 源码中()
frameworks\native\cmds\servicemanager\servicemanager.rc
# Android设备中
/system/etc/init

跟mediaserver一样,也是在init中解析/system/etc/init时启动的。

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
    onrestart restart keystore
    onrestart restart gatekeeperd
    writepid /dev/cpuset/system-background/tasks
    shutdown critical
注意

service_manager.c代码会走两次,因为有两个服务公用一套代码。

#@站长
frameworks\native\cmds\servicemanager\Android.bp

会发现

# Android.bp中部分
//略
cc_binary {
    name: "servicemanager",
    defaults: ["servicemanager_flags"],
    srcs: [
        "service_manager.c",
        "binder.c",
    ],
    shared_libs: ["libcutils", "libselinux"],
    init_rc: ["servicemanager.rc"],
}

cc_binary {
    name: "vndservicemanager",
    defaults: ["servicemanager_flags"],
    vendor: true,
    srcs: [
        "service_manager.c",
        "binder.c",
    ],
    cflags: [
        "-DVENDORSERVICEMANAGER=1",
    ],
    shared_libs: ["libcutils", "libselinux"],
    init_rc: ["vndservicemanager.rc"],
}

从上面会发现servicemanager和vndservicemanager公用service_manager.c一套代码,只是参数不一样。

vndservicemanager的.rc文件是vndservicemanager.rc启动的。

service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder
    class core
    user system
    group system readproc
    writepid /dev/cpuset/system-background/tasks
    shutdown critical

PS:后续只关注servicemanager哈

service_manager.c

程序的入口都是main()。

主要做了如下几个工作:

  1. 打开binder驱动

  2. 成为上下文管理者

  3. 进入binder循环,处理客户端发送的请求

int main(int argc, char** argv){
    struct binder_state *bs;
    union selinux_callback cb;
    char *driver;
   //vndservicemanager的启动带参数的(argc > 1),servicemanager的启动不带参数(argc == 1)
    if (argc > 1) {
        driver = argv[1]; //是/dev/vndbinder
    } else {
        driver = "/dev/binder";
    }
    //打开binder驱动,申请128k字节大小的内存空间
    bs = binder_open(driver, 128*1024);
    if (!bs) {
#ifdef VENDORSERVICEMANAGER
        while (true) {
            sleep(UINT_MAX);
        }
#else
        ALOGE("failed to open binder driver %s\n", driver);
#endif
        return -1;
    }
    //成为上下文管理者
    if (binder_become_context_manager(bs)) {
        return -1;
    }
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
    cb.func_log = selinux_log_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);
    //获取sehandle,这里分vndservicemanager和servicemanager
#ifdef VENDORSERVICEMANAGER
    sehandle = selinux_android_vendor_service_context_handle();
#else
    sehandle = selinux_android_service_context_handle();
#endif
    selinux_status_open(true);
    //无法获取sehandle
    if (sehandle == NULL) {
        abort();
    }
    //无法获取service_manager上下文就退出
    if (getcon(&service_manager_context) != 0) {
        abort();
    }
    //进入无限循环,处理client端发来的请求
    binder_loop(bs, svcmgr_handler);
    return 0;
}
打开binder驱动
//125啦站长
//打开binder驱动,申请128k字节大小的内存空间
//driver="/dev/binder"
bs = binder_open(driver, 128*1024);
binder_open()

这里主要工作

  1. 给bs分配内存

  2. 通过open打开设备驱动,返回文件描述符并赋值给bs->fd

  3. 内核空间和用户空间的binder版本比较

  4. mmap内存映射

涉及kernel层代码的方法,推荐看末尾参考文章,我这略过

struct binder_state *binder_open(const char* driver, size_t mapsize){
    struct binder_state *bs;
    struct binder_version vers;
    //申请内存
    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return NULL;
    }
    //打开Binder设备驱动,返回文件描述符并赋值给bs->fd
    bs->fd = open(driver, O_RDWR | O_CLOEXEC);
    if (bs->fd < 0) {
        //打开失败就进入fail_open
        goto fail_open;
    }
    //获取binder版本信息并对比
    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        //内核空间与用户空间的binder不是同一版本
        goto fail_open;
    }
    //传入的值=128k
    bs->mapsize = mapsize;
    //mmap内存映射
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    if (bs->mapped == MAP_FAILED) {
        //binder设备内存无法映射
        goto fail_map;
    }
    return bs;
fail_map:
    close(bs->fd);
fail_open:
    free(bs);
    return NULL;
}
成为上下文管理者
//成为上下文管理者
if (binder_become_context_manager(bs)) {
    return -1;
}
binder_become_context_manager()

成为上下文的管理者,整个系统中只有一个这样的管理者。

int binder_become_context_manager(struct binder_state *bs){
    //通过ioctl,传递BINDER_SET_CONTEXT_MGR指令
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
进入binder循环
//进入无限循环,处理client端发来的请求
binder_loop(bs, svcmgr_handler);

这里传入的是svcmgr_handler指针函数。

先看binder_loop()

binder_loop()

这里主要如下工作

  1. 通过binder_write通知binder驱动要进入循环

  2. 通过ioctl读取binder中的数据

  3. 通过binder_parse解析数据

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;
    //将BC_ENTER_LOOPER命令发送给binder驱动,让Service Manager进入循环
    binder_write(bs, readbuf, sizeof(uint32_t));
    //进入循环
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
        //不断地binder读写过程
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        if (res < 0) {
            break;
        }
        //解析binder信息,这里传入了func哈
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            break;
        }
        if (res < 0) {
            break;
        }
    }
}
binder_write()

对data数据进行封装成binder_write_read,然后通过ioctl()发送给binder

int binder_write(struct binder_state *bs, void *data, size_t len){
    struct binder_write_read bwr;
    int res;
    bwr.write_size = len;
    bwr.write_consumed = 0;
    //传入的是BC_ENTER_LOOPER
    bwr.write_buffer = (uintptr_t) data; 
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    return res;
}
binder_parse()

这里传入了svcmgr_handler,也就是func

这里主要功能

  1. 获取cmd码,根据cmd进行处理对应功能

  2. 处理BR_TRANSACTION事务,主要通过func处理(也就是svcmgr_handler)

这里部分不太懂,后续学习。请看参考文吧。多谢、

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) {
        //获取cmd码
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        //处理解析到的cmd码
        switch(cmd) {
        case BR_NOOP://无操作,退出循环
            break;
        case BR_TRANSACTION_COMPLETE:
            break;
        case BR_INCREFS:
        case BR_ACQUIRE:
        case BR_RELEASE:
        case BR_DECREFS:
            ptr += sizeof(struct binder_ptr_cookie);
            break;
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                return -1;
            }
            binder_dump_txn(txn);
            //binder_handler函数不为null
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;
                bio_init(&reply, rdata, sizeof(rdata), 4);
                //从txn解析出binder_io信息
                bio_init_from_txn(&msg, txn);
                //通过binder_handler函数进行处理
                res = func(bs, txn, &msg, &reply);
                if (txn->flags & TF_ONE_WAY) {
                    //不需要回复,释放buffer
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    //需要回复,添加恢复信息并释放buffer
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
            }
            ptr += sizeof(*txn);
            break;
        }
        case BR_REPLY: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                return -1;
            }
            binder_dump_txn(txn);
            if (bio) {
                //从txn解析出binder_io信息
                bio_init_from_txn(bio, txn);
                bio = 0;
            } else {
                /* todo FREE BUFFER */
            }
            ptr += sizeof(*txn);
            r = 0;
            break;
        }
        case BR_DEAD_BINDER: {
            // 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;
        }
        case BR_FAILED_REPLY:
            r = -1;
            break;
        case BR_DEAD_REPLY:
            r = -1;
            break;
        default:
            ALOGE("parse: OOPS %d\n", cmd);
            return -1;
        }
    }
    return r;
}
svcmgr_handler()

servicemanager是个服务管理者,用于保存启动过的服务,并提供查询服务等功能。

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;
        }
         //根据名称查找相应handle
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        //调用bio_put_ref(reply, handle),将handle封装到reply.
        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;
        dumpsys_priority = bio_get_uint32(msg);
        //添加服务到svclist
        if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,txn->sender_pid))
            return -1;
        break;
    case SVC_MGR_LIST_SERVICES: {
        uint32_t n = bio_get_uint32(msg);
        uint32_t req_dumpsys_priority = bio_get_uint32(msg);
        if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
            return -1;
        }
        si = svclist;
        //遍历
        while (si) {
            if (si->dumpsys_priority & req_dumpsys_priority) {
                if (n == 0) break;
                n--;
            }
            si = si->next;
        }
        if (si) {
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
    default:
        return -1;
    }
    bio_put_uint32(reply, 0);
    return 0;
}
do_find_service()
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid){
    //查询相应的服务。当名字完全一致,则返回查询到的结果
    struct svcinfo *si = find_svc(s, len);
    if (!si || !si->handle) {
        return 0;
    }
    if (!si->allow_isolated) {
        uid_t appid = uid % AID_USER;
        //检查该服务是否允许孤立于进程而单独存在
        if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
            return 0;
        }
    }
    //服务是否满足查询条件
    if (!svc_can_find(s, len, spid, uid)) {
        return 0;
    }
    //返回该服务所对应的handle
    return si->handle;
}
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, uint32_t dumpsys_priority, pid_t spid) {
    struct svcinfo *si;
    if (!handle || (len == 0) || (len > 127))
        return -1;
    //权限检查
    if (!svc_can_register(s, len, spid, uid)) {
        return -1;
    }
     //服务检索 判断是否有存在的服务
    si = find_svc(s, len);
    if (si) {
        if (si->handle) {
            //服务已注册时,释放之前的服务
            svcinfo_death(bs, si);
        }
        //更新handle
        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;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->dumpsys_priority = dumpsys_priority;
        si->next = svclist;
        //svclist保存所有已注册的服务
        svclist = si;
    }
    //以BC_ACQUIRE命令,handle为目标的信息,通过ioctl发送给binder驱动
    binder_acquire(bs, handle);
    //以BC_REQUEST_DEATH_NOTIFICATION命令的信息,通过ioctl发送给binder驱动
    //主要用于清理内存等收尾工作。
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

参考文章

  1. Binder系列3—启动ServiceManager

  2. ServiceManager与binder驱动的交互

 历史上的今天

  1. 2020: 设计模式:装饰模式或包装模式(0条评论)
  2. 2019: ubuntu 安装apache2, php5, mysql, phpmyadmin后无法访问phpmyadmin问题的解决(0条评论)
  3. 2019: 史铁生:合欢树(0条评论)
版权声明 1、 本站名称: 笔友城堡
2、 本站网址: https://www.biumall.com/
3、 本站部分文章来源于网络,仅供学习与参考,如有侵权,请留言

暂无评论

暂无评论...

随机推荐

Java Consumer的使用

前言今天有空整理一下Consumer<T> 接口的使用,一般用于回调中。这里简单记录一下。正文Consumer<T>接口是java 1.8才有的,定义如下://java.util.function.Consumer@FunctionalInterfacepu...

Android汉字转拼音以及按照[字母][数字][特殊字符]排序

前言多媒体开发时需要对音频文件进行排序,由于媒体文件的命名多样,需要对文件名字进行统一的转换,然后进行排序。排序规则:【字母】-【数字】-【特殊字符】PS: 也存在外国文字(比如韩语,俄语,日语),为了省事,这个默认当成特殊字符隐藏内容!付费阅读后才能查看!¥3 ¥6多个隐藏块只需支付一次...

拜伦 · 韦恩的10条人生经验

紧密联的人际网络。运气在生活中扮演着重要的角色,没有比认识尽可能多的人更好的增加运气的方法了。 通过向人们发送文章、书籍和电子邮件来培养你的人际关系网,以表明你在思考这些问题。 为主要出版物撰写专栏和思想文章。 组织讨论小组,把你有想法的朋友聚集在一起。 当你遇到一个新的人时,把他当作朋友。 ...

Android画中画简介

前言Android 8.0 Oreo(API Level 26)允许活动启动画中画 Picture-in-picture(PIP)模式。PIP 是一种特殊类型的多窗口模式,主要用于视频播放。要将画中画添加到您的应用中,您需要注册支持画中画的 Activity、根据需要将 Activity 切换为...

再谈Android日夜模式

前言之前介绍过Android日夜模式的使用,日夜模式是Android高版本自带的一种模式,很方便也很使用。如果换肤只有2种皮肤,这个是最佳选择,因为Android日夜模式只要按照规则即可实现。虽然介绍过,但很多细节还是没有说明白,因此由写一篇流水文,方便自己回顾。正文日夜模式就是我们常说的...

我常用的Monkey命令

Monkey的概念“猴子测试”是指没有测试经验的人甚至对计算机根本不了解的人(就像猴子一样)不需要知道程序的任何用户交互方面的知识,如果给他一个程序,他就会针对他看到的界面进行操作,其操作是无目的的、乱点乱按的。这种测试方式在产品周期中的早期阶段会找到很多很好的bug,为用户节省不少的时间。...