在servicemanager之启动过程中,有看到servicemanager在一切准备工作就绪后,就进入binder_loop()开始不停的处理事件,这篇笔记重点分析下这些核心事件时如何处理的。
命令解析: binder_parse()
首先要解析命令,根据不同的命令进行不同的动作。从下面的代码看,servicemanager支持的命令并不太多,这里只关注BR_TRANSACTION。
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) {
// 命令(4字节)
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
switch(cmd) {
case BR_NOOP:
case BR_TRANSACTION_COMPLETE:
case BR_INCREFS:
case BR_ACQUIRE:
case BR_RELEASE:
case BR_DECREFS:
case BR_TRANSACTION:
// 来自client的IPC调用,调用信息都在binder_transaction_data中
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
if ((end - ptr) < sizeof(*txn)) {
ALOGE("parse: txn too small!\n");
return -1;
}
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
int res;
// 初始化reply(将reply.data指向rdata),后面可能需要向调用者发送响应
bio_init(&reply, rdata, sizeof(rdata), 4);
// 根据txn初始化msg,后面用msg来解析驱动传递的数据
bio_init_from_txn(&msg, txn);
// func就是svcmgr_handler(),处理IPC调用
res = func(bs, txn, &msg, &reply);
// 对于oneway类型的IPC调用,不需要发送响应
if (txn->flags & TF_ONE_WAY) {
binder_free_buffer(bs, txn->data.ptr.buffer);
} else {
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
}
// 继续处理下一个
ptr += sizeof(*txn);
break;
case BR_REPLY:
case BR_DEAD_BINDER:
case BR_FAILED_REPLY:
case BR_DEAD_REPLY:
default:
}
}
return r;
}
初始化消息解析
void bio_init_from_txn(struct binder_io *bio, struct binder_transaction_data *txn)
{
bio->data = bio->data0 = (char *)(intptr_t)txn->data.ptr.buffer;
bio->offs = bio->offs0 = (binder_size_t *)(intptr_t)txn->data.ptr.offsets;
bio->data_avail = txn->data_size;
bio->offs_avail = txn->offsets_size / sizeof(size_t);
bio->flags = BIO_F_SHARED;
}
事务类型的命令携带的消息的首部是struct binder_transaction_data,该首部指明了是什么事务:
struct binder_transaction_data {
// target表示应该由谁来处理该IPC调用,特别的,当target.handle=0的时候,表示应该由servicemanager来处理
union {
__u32 handle;
binder_uintptr_t ptr;
} target;
binder_uintptr_t cookie;
// 操作码,代表要做什么
__u32 code;
__u32 flags;
// 调用方的身份信息
pid_t sender_pid;
uid_t sender_euid;
// 根据操作码解释的数据部分
binder_size_t data_size;
binder_size_t offsets_size;
// 指向事务携带的数据区,使用下面的struct binder_io来操作该数据区
union {
struct {
binder_uintptr_t buffer;
binder_uintptr_t offsets;
} ptr;
__u8 buf[8];
} data;
};
此外,为了方便缓冲区参数的解析的填充,servicemanager还定义了struct binder_io。
struct binder_io
{
// 在处理过程中,data会逐渐移动,但是data0永远指向消息的开头
char *data; /* pointer to read/write from */
binder_size_t *offs; /* array of offsets */
size_t data_avail; /* bytes available in data buffer */
size_t offs_avail; /* entries available in offsets array */
char *data0; /* start of data buffer */
binder_size_t *offs0; /* start of offsets buffer */
uint32_t flags;
uint32_t unused;
};
事务命令处理: BR_TRANSACTION
int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data *txn,
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;
// 判断下是否就是发送给自己的消息(ptr为0,即handle为0)
if (txn->target.ptr != BINDER_SERVICE_MANAGER)
return -1;
// PING操作用于保活,直接返回成功
if (txn->code == PING_TRANSACTION)
return 0;
// Equivalent to Parcel::enforceInterface(), reading the RPC
// header with the strict mode policy mask and the interface name.
// Note that we ignore the strict_policy and don't propagate it
// further (since we do no outbound RPCs anyway).
strict_policy = bio_get_uint32(msg);
// 解析servicemanager的名字,格式:字符串中字符个数(4字节)+字符串(每个字符2字节)
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
// 校验binder接口名字,调用者必须指定为"android.os.IServiceManger"
if ((len != (sizeof(svcmgr_id) / 2)) || memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
fprintf(stderr,"invalid id %s\n", str8(s, len));
return -1;
}
// SELinux相关,忽略
...
// 根据操作码确定client需要servicemanager做什么,可以看出,
// 实际上servicemanager能干的核心事务只有查询和添加Service
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 = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
// 将找到的服务句柄记录到reply中返回
bio_put_ref(reply, handle);
return 0;
case SVC_MGR_ADD_SERVICE:// 添加服务,即注册服务
// 获取要添加的服务的名字
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
// 获取服务句柄(binder驱动已经分配好了,这里只是读取)
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))
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)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n", txn->sender_euid);
return -1;
}
si = svclist;
// walk through the list of services n times skipping services that
// do not support the requested priority
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有调用do_add_service()进行服务的添加操作,至于为服务分配句柄,实际上是binder驱动做的,servicemanager这里仅仅是从驱动传递过来的数据中获取该句柄而已。
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;
// 服务句柄不能为0,并且服务名字必须提供,并且长度不能超过127个字符
if (!handle || (len == 0) || (len > 127))
return -1;
// 检查调用者是否有权限注册服务
if (!svc_can_register(s, len, spid, uid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n", str8(s, len), handle, uid);
return -1;
}
// 以服务名字为key检查是否已经有相同名字的服务
si = find_svc(s, len);
if (si) {
// 对于重复注册的服务,会更新其服务句柄
if (si->handle) {
ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n", str8(s, len), handle, uid);
svcinfo_death(bs, si);
}
si->handle = handle;
} else {
// 分配svcinfo对象用于保存注册的服务信息(包括末尾的服务名字)
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n", str8(s, len), handle, uid);
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 = si;
}
// 通过binder驱动增加对该服务的引用计数
binder_acquire(bs, handle);
binder_link_to_death(bs, handle, &si->death);
return 0;
}
如上,servicemanager对每个注册的服务对应一个struct svcinfo结构,其中保存了servicemanager需要保存的信息,并且servicemanager将所有已注册的服务组织到全局的单链表svclist中。
// 每个注册的服务在servicemanger中抽象成一个svcinfo对象
struct svcinfo
{
struct svcinfo *next;
// 服务句柄,每个服务提供者都应该提供一个该句柄,并且该句柄在服务提供者进程中是唯一的
uint32_t handle;
// 服务销毁信息
struct binder_death death;
int allow_isolated;
// 每个服务可以指定一个dumpsys优先级,用于控制dumpsys是否可以dump到该服务
uint32_t dumpsys_priority;
// 服务名字信息
size_t len;
uint16_t name[0];
};
剩下的查找服务和列举服务实现不再赘述。