Android Framework 之启动 ServiceManager

Posted 小陈乱敲代码

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Framework 之启动 ServiceManager相关的知识,希望对你有一定的参考价值。

阅读须知

本文源码基于 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);


```java

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

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

2.1 初始化 binder\\_state
---------------------

给结构体 `binder_state` 分配内存。

```java
// 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) 
                Android 进阶——系统启动之Framework 核心ActivitityManagerService服务启动

Android笔记 - Android启动之Android Framework启动

Android Framework 之启动 ServiceManager

Android framework重要服务之InputManagerService的启动流程

framework之Activity启动流程(基于Android11源码)

framework之Activity启动流程(基于Android11源码)