AndroidFramework 之启动 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);
}

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 就分析完了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,425评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,058评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,186评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,848评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,249评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,554评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,830评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,536评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,239评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,505评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,004评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,346评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,999评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,060评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,821评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,574评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,480评论 2 267

推荐阅读更多精彩内容

  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    迷月闪星情阅读 10,498评论 0 11
  • 彩排完,天已黑
    刘凯书法阅读 4,146评论 1 3
  • 没事就多看看书,因为腹有诗书气自华,读书万卷始通神。没事就多出去旅游,别因为没钱而找借口,因为只要你省吃俭用,来...
    向阳之心阅读 4,745评论 3 11
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 120,500评论 2 7