美文网首页
AndroidFramework 之启动 ServiceMana

AndroidFramework 之启动 ServiceMana

作者: 你怕是很皮哦 | 来源:发表于2021-04-12 17:05 被阅读0次

    阅读须知

    本文源码基于 Android 10,涉及相关源码如下。

    system/core/
        - init/init.cpp
        - rootdir/init.rc
        
    frameworks/native/cmds/servicemanager/
        - Android.bp
        - binder.c
        - service_manager.c
        - servicemanager.rc
    

    概述

    ServiceManagaerBinder 的守护进程,在 Binder 机制中起着重要的作用。本文将从源码的角度对其进行分析,整体流程如下:

    1. ServiceManager 的启动;
    2. 打开 Binder 驱动;
    3. 设置上下文管理者;
    4. 进入循环。
    image.png

    时序图如下。

    image.png

    1. ServiceManager 的启动

    先来看看 ServiceManager 是如何启动的:

    1. init 进程解析 init.rc,触发 trigger init
    2. 执行 start servicemanager 启动 ServiceManager
    image.png

    1.1 触发 trigger init

    Zygote 一文中说过,init 进程启动的第二阶段会解析 init.rc 文件。

    在这之后会触发 trigger init

    // system/core/init/init.cpp
    
    int SecondStageMain(int argc, char** argv) {
        // 解析 init.rc 文件
        LoadBootScripts(am, sm);
        // 触发 trigger init
        am.QueueEventTrigger("init");
    }
    

    结合 init.rc 看看 action init 做了什么。

    # system/core/rootdir/init.rc
    
    on init
        # 启动 service servicemanager 
        start servicemanager
    

    1.2 启动 ServiceManager

    当触发 trigger init 后,会启动 servicemanager 服务,其声明如下。

    # frameworks/native/cmds/servicemanager/servicemanager.rc
    
    # 对应执行的文件为 /system/bin/servicemanager
    service servicemanager /system/bin/servicemanager
        class core animation
        user system
        group system readproc
        critical
        # 当 servicemanager 重启的时候会重启下列服务
        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
        onrestart restart thermalservice
        writepid /dev/cpuset/system-background/tasks
        shutdown critical
    

    对应的执行文件为 /system/bin/servicemanager,在编译前位于 frameworks/native/cmds/servicemanager 下,来看看 Android.bp

    // frameworks/native/cmds/servicemanager/Android.bp
    
    cc_binary {
        name: "servicemanager",
        srcs: [
            "service_manager.c",
            "binder.c",
        ],
        init_rc: ["servicemanager.rc"],
    }
    

    其对应的源码为 service_manager.cbinder.c,入口函数 main() 位于 servicemanager.c

    2. 打开 Binder 驱动

    启动完 ServiceManager 后会打开 Binder 驱动。

    image.png

    main() 中首先调用 binder_open()

    // frameworks/native/cmds/servicemanager/service_manager.c
    
    int main(int argc, char** argv)
    {
        char *driver;
        driver = "/dev/binder";
        // 调用 binder_open() 打开 binder 驱动,并申请 128 kb 内存
        bs = binder_open(driver, 128*1024);
    }
    

    binder_open() 主要做了如下事情:

    1. 初始化结构体 binder_state
    2. 系统调用 open() 打开 /dev/binder,获得文件描述符 fd
    3. 系统调用 ioctl() 获取 binder 版本并做版本比对;
    4. 系统调用 mmap() 内存映射 128kb 的空间供 ServiceManager 使用。

    2.1 初始化 binder_state

    给结构体 binder_state 分配内存。

    // frameworks/native/cmds/servicemanager/binder.c
    
    struct binder_state
    {
        // 打开 binder 驱动获取的文件描述符
        int fd;
        // 指向 mmap() 内存映射地址
        void *mapped;
        // 映射内存大小
        size_t mapsize;
    };
    
    struct binder_state *binder_open(const char* driver, size_t mapsize)
    {
        struct binder_state *bs;
        // 给 bs 分配内存
        bs = malloc(sizeof(*bs));
        if (!bs) {
            return NULL;
        }
    }
    

    2.2 打开 Binder 驱动

    系统调用 open() 打开 /dev/binder,如果打开驱动失败,则执行 fail_open 释放内存。

    // frameworks/native/cmds/servicemanager/binder.c
    
    struct binder_state *binder_open(const char* driver, size_t mapsize)
    {
        // 调用 open() 打开 binder 驱动
        bs->fd = open(driver, O_RDWR | O_CLOEXEC);
        if (bs->fd < 0) {
            goto fail_open;
        }
        
    fail_open:
        // 释放 bs 内存
        free(bs);
        return NULL;
    }
    

    简单的解释一下什么是系统调用?

    由于需要限制不同的程序之间的访问能力,防止程序获取别的程序的内存数据,CPU 划分出两个权限等级,用户态内核态

    • 用户态 只能受限的访问内存,不允许访问外围设备,占用 CPU 的能力被剥削,CPU 资源可以被其他程序获取
    • 内核态 可以访问内存所有数据,包括外围设备,CPU 可以将自己从一个程序切换到另外一个程序

    所有的用户程序都是运行在用户态,但有时需要做一些内核态的事情,而唯一可以做这些事情的就是操作系统,所以程序需要向操作系统发起请求,以程序的名字来执行这些操作。这时就需要一个从用户态切换到内核态但不能控制内核态中执行的机制,这种机制就是 系统调用

    2.3 检查 Binder 版本

    系统调用 ioctl() 传入 BINDER_VERSION 命令获取 Binder 驱动版本,对比版本是否一致,不一致则执行 fail_open 释放内存。

    // frameworks/native/cmds/servicemanager/binder.c
    
    struct binder_state *binder_open(const char* driver, size_t mapsize)
    {
        struct binder_version vers;
        // 调用 ioctl() 获取 Binder 版本
        if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
            (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
            goto fail_open;
        }
    fail_open:
        // 释放 bs 内存
        free(bs);
        return NULL;
    }
    

    2.4 内存映射

    系统调用 mmap() 映射 128kb 的内存空间,即把 Binder 驱动文件的 128kb 映射到内存空间供 ServiceManager 使用,内存映射失败则执行 fail_map,关闭 fd 并释放内存。

    // frameworks/native/cmds/servicemanager/binder.c
    
    struct binder_state *binder_open(const char* driver, size_t mapsize)
    {
        bs->mapsize = mapsize;
        // 调用 mmap() 做内存映射
        bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
        if (bs->mapped == MAP_FAILED) {
            goto fail_map;
        }
        return bs;
    fail_map:
        // 关闭 fd
        close(bs->fd);
    fail_open:
        // 释放 bs 内存
        free(bs);
        return NULL;
    }
    

    ServiceManager 进程 mmap 的内存大小可以通过 adb shell 命令查看。

    $ ps -eT | grep servicemanager
    $ cat /proc/1653/maps
    
    image.png image.png

    可以看到内存映射地址为 0xf10f8000 ~ 0xf1118000,差为 0x20000 即十进制的 128kb

    3. 设置上下文管理者

    打开 Binder 驱动后会将 ServiceManager 设置为上下文管理者。

    image.png

    调用 binder_become_context_manager()

    // frameworks/native/cmds/servicemanager/service_manager.c
    
    int main(int argc, char** argv)
    {
        // 成为 context manager
        if (binder_become_context_manager(bs)) {
            return -1;
        }
    }
    
    // frameworks/native/cmds/servicemanager/binder.c
    
    int binder_become_context_manager(struct binder_state *bs)
    {
        struct flat_binder_object obj;
        memset(&obj, 0, sizeof(obj));
        obj.flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX;
        // 系统调用 ioctl() 传入 BINDER_SET_CONTEXT_MGR_EXT 设置安全的上下文管理者
        int result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR_EXT, &obj);
    
        if (result != 0) {
            // 失败则传入 BINDER_SET_CONTEXT_MGR 设置上下文管理者
            result = ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
        }
        return result;
    }
    

    android 10 新增 BINDER_SET_CONTEXT_MGR_EXT 命令来设置安全的上下文管理者,如果设置失败,则使用原有的 BINDER_SET_CONTEXT_MGR 命令来设置上下文管理者,两者区别在于是否携带参数。

    4. 进入循环

    最后会进入循环,从 Binder 驱动读取和解析数据。

    image.png

    调用 binder_loop() 进入循环,不断地通过系统调用 ioctl()Binder 驱动读取数据,并通过 binder_parse() 进行数据解析。

    // frameworks/native/cmds/servicemanager/service_manager.c
    
    int main(int argc, char** argv)
    {
        // 调用 binder_loop() 进入循环,注意这里的
        binder_loop(bs, svcmgr_handler);
    }
    
    // frameworks/native/cmds/servicemanager/binder.c
    
    void binder_loop(struct binder_state *bs, binder_handler func)
    {
        int res;
        struct binder_write_read bwr;
        // 128kb 的缓存区
        uint32_t readbuf[32];
        
        // 写入 BC_ENTER_LOOPER 命令通知 binder 驱动即将进入循环
        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;
            // 系统调用 ioctl() 读取 binder 驱动传递的数据放到 readbuf
            res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
            // 调用 binder_parse() 解析数据
            res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        }
    }
    

    注意这里调用 binder_loop() 传入的 svcmgr_handler(),后面会使用到。

    4.1 binder_write()

    binder_write() 会封装 struct binder_write_read,并通过系统调用 ioctl() 将对应的命令传递给 Binder 驱动。

    // frameworks/native/cmds/servicemanager/binder.c
    
    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;
        bwr.write_buffer = (uintptr_t) data;
        // 清除读取数据
        bwr.read_size = 0;
        bwr.read_consumed = 0;
        bwr.read_buffer = 0;
        // 系统调用 ioctl() 传入 BINDER_WRITE_READ 命令表示进行读写操作
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        return res;
    }
    

    4.2 binder_parse()

    binder_parse() 用来解析从 Binder 驱动读取到的数据,然后根据不同的命令执行对应的操作。

    // frameworks/native/cmds/servicemanager/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;
        // whilte 循环读取处理命令,可能存在多个命令
        while (ptr < end) {
            // 读取命令,命令占用 readbuf 的 4 个字节
            uint32_t cmd = *(uint32_t *) ptr;
            ptr += sizeof(uint32_t);
            // 根据命令做对应的操作
            switch(cmd) {
            case BR_NOOP:
                break;
            case BR_TRANSACTION_COMPLETE:
                break;
            case BR_INCREFS:
            case BR_ACQUIRE:
            case BR_RELEASE:
            case BR_DECREFS:
                break;
            case BR_TRANSACTION_SEC_CTX:
            case BR_TRANSACTION:
                break;
            case BR_REPLY: 
                break;
            case BR_DEAD_BINDER:
                break;
            case BR_FAILED_REPLY:
                break;
            case BR_DEAD_REPLY:
                break;
            default:
                return -1;
            }
        }
    
        return r;
    }
    

    因为 cmd 命令可能有多个,所以通过 while 循环每次处理一个 cmd 命令,多 cmd 的结构大致如下图所示。

    image.png

    这里重点看下 BR_TRANSACTION 命令。

    4.2.1 BR_TRANSACTION

    BR_TRANSACTIONBinder 驱动向 Server 端发送请求数据。

    // frameworks/native/cmds/servicemanager/binder.c
    
    int binder_parse(struct binder_state *bs, struct binder_io *bio,
                     uintptr_t ptr, size_t size, binder_handler func)
    {
        switch(cmd) {
        case BR_TRANSACTION_SEC_CTX:
        case BR_TRANSACTION: {
            struct binder_transaction_data_secctx txn;
            // BR_TRANSACTION_SEC_CTX
            if (cmd == BR_TRANSACTION_SEC_CTX) {
                // 拷贝 binder_transaction_data_secctx 到 transaction_data
                memcpy(&txn, (void*) ptr, sizeof(struct binder_transaction_data_secctx));
                ptr += sizeof(struct binder_transaction_data_secctx);
            } else /* BR_TRANSACTION */ {
                // 拷贝 binder_transaction_data 到 transaction_data
                memcpy(&txn.transaction_data, (void*) ptr, sizeof(struct binder_transaction_data));
                ptr += sizeof(struct binder_transaction_data);
                txn.secctx = 0;
            }
    
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;
    
                // reply 初始化
                bio_init(&reply, rdata, sizeof(rdata), 4);
                // 从 txn.transaction_data 解析出 binder_io 的信息,存入 msg
                bio_init_from_txn(&msg, &txn.transaction_data);
                // svcmgr_handler() 处理对应的操作
                res = func(bs, &txn, &msg, &reply);
                if (txn.transaction_data.flags & TF_ONE_WAY) {
                    // 如果是 TF_ONE_WAY 处理,则释放数据
                    binder_free_buffer(bs, txn.transaction_data.data.ptr.buffer);
                } else {
                    // 如果不是 TF_ONE_WAY 处理,给 binder 驱动回复数据
                    binder_send_reply(bs, &reply, txn.transaction_data.data.ptr.buffer, res);
                }
            }
            break;
        }
        }
    }
    

    binder_transaction_data 的结构如下,其表明了 transcation 传输的具体语义,语义码记录在 code 中,不同语义码携带的数据是不同的,这些数据由 data 指定。

    struct binder_transaction_data {
        union {
            // binder_ref 该成员指明发送方的 Binder 实体引用
            __u32 handle;
            // binder_node 的内存地址,当数据到达接收方时,驱动已将该成员修改成 Binder 实体
            binder_uintptr_t ptr;
        } target;
        // BBinder 指针, 发送方忽略该成员;接收方收到数据包时,该成员存放的是创建 Binder 实体时由该接收方自定义的任意数值,做为与 Binder 指针相关的额外信息存放在驱动中
        binder_uintptr_t cookie;
        // RPC 代码,代表 Client 与 Server 双方约定的命令码,比如 ADD_SERVICE_TRANSACTION
        __u32 code;
        // 标志位,比如 TF_ONE_WAY 代表异步,即不等待 Server 端回复
        __u32 flags;
        // 发送端进程的 pid
        pid_t sender_pid;   
        // 发送端进程的 uid
        uid_t sender_euid;  
        // data 数据的总大小
        binder_size_t data_size;    
        // IPC 对象的大小
        binder_size_t offsets_size; 
        // RPC数据
        union {
            struct {
                // 数据区起始地址
                binder_uintptr_t buffer;
                // 数据区 IPC 对象偏移量
                binder_uintptr_t offsets;
            } ptr;
            __u8 buf[8]; 
        } data;
    }
    

    在解析完 binder_transaction_data 的具体语义后,会调用前面传给 binder_loop()svcmgr_handler(),其实就是 switch case 语义码做不同的事情。

    // frameworks/native/cmds/servicemanager/service_manager.c
    
    int svcmgr_handler(struct binder_state *bs,
                       struct binder_transaction_data_secctx *txn_secctx,
                       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;
        uint32_t dumpsys_priority;
        // 获取 transaction_data
        struct binder_transaction_data *txn = &txn_secctx->transaction_data;
    
        strict_policy = bio_get_uint32(msg);
        bio_get_uint32(msg);  // Ignore worksource header.
        s = bio_get_string16(msg, &len);
    
        if ((len != (sizeof(svcmgr_id) / 2)) ||
            memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
            fprintf(stderr,"invalid id %s\n", str8(s, len));
            return -1;
        }
        // 根据不同的 code 做不同的事情
        switch(txn->code) {
        // 查询服务
        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,
                                     (const char*) txn_secctx->secctx);
            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;
            dumpsys_priority = bio_get_uint32(msg);
            if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
                               txn->sender_pid, (const char*) txn_secctx->secctx))
                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, (const char*) txn_secctx->secctx, txn->sender_euid)) {
                ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
                        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:
            ALOGE("unknown code %d\n", txn->code);
            return -1;
        }
    
        bio_put_uint32(reply, 0);
        return 0;
    }
    

    ServiceManager 的功能其实很简单:

    • 接收到 SVC_MGR_GET_SERVICESVC_MGR_CHECK_SERVICE 时调用 do_find_service() 查找服务
    • 接收到 SVC_MGR_ADD_SERVICE 时调用 do_add_service() 注册服务
    • 接收到 SVC_MGR_LIST_SERVICES 时获取所有服务名称

    至此 ServiceManager 就分析完了。

    相关文章

      网友评论

          本文标题:AndroidFramework 之启动 ServiceMana

          本文链接:https://www.haomeiwen.com/subject/kcyxcltx.html