阅读须知
本文源码基于 Android 10
,涉及相关源码如下。
system/core/
- init/init.cpp
- rootdir/init.rc
frameworks/native/cmds/servicemanager/
- Android.bp
- binder.c
- service_manager.c
- servicemanager.rc
概述
ServiceManagaer
是 Binder
的守护进程,在 Binder
机制中起着重要的作用。本文将从源码的角度对其进行分析,整体流程如下:
-
ServiceManager
的启动; - 打开
Binder
驱动; - 设置上下文管理者;
- 进入循环。
时序图如下。
image.png1. ServiceManager 的启动
先来看看 ServiceManager
是如何启动的:
-
init
进程解析init.rc
,触发trigger init
; - 执行
start servicemanager
启动ServiceManager
。
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.c
和 binder.c
,入口函数 main()
位于 servicemanager.c
。
2. 打开 Binder 驱动
启动完 ServiceManager
后会打开 Binder
驱动。
在 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()
主要做了如下事情:
- 初始化结构体
binder_state
; - 系统调用
open()
打开/dev/binder
,获得文件描述符fd
; - 系统调用
ioctl()
获取binder
版本并做版本比对; - 系统调用
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
设置为上下文管理者。
调用 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
驱动读取和解析数据。
调用 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
的结构大致如下图所示。
这里重点看下 BR_TRANSACTION
命令。
4.2.1 BR_TRANSACTION
BR_TRANSACTION
是 Binder
驱动向 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_SERVICE
或SVC_MGR_CHECK_SERVICE
时调用do_find_service()
查找服务 - 接收到
SVC_MGR_ADD_SERVICE
时调用do_add_service()
注册服务 - 接收到
SVC_MGR_LIST_SERVICES
时获取所有服务名称
至此 ServiceManager
就分析完了。
网友评论