该系列文章总纲链接:专题总纲目录 Android Framework 总纲
本章关键点总结 & 说明:
这里主要对service_manager进程进行了分析,关注 进程的流程和 两个处理流程(添加服务和 获取服务)。
通过分析service_manager,进而对add_service请求的处理流程进行分析。通过这样的分析,后面 getservice的流程也是类似的。
1 service_manager的主函数main的分析
说明:在源码分析时,由于Binder中SELinux的东西比较多,起初的分析容易影响我们对Binder主干的影响,因此在分析前期,将所有SELinux相关的函数均直接无视
这里service_manager起到的作用实际上是BnServiceManager的作用,即处理请求。ServiceManager的入口函数为:
int main(int argc, char **argv)
{
struct binder_state *bs;
bs = binder_open(128*1024); //1:open & mmap binder
...
if (binder_become_context_manager(bs)) {//2:become ctx Manager
...
}
svcmgr_handle = BINDER_SERVICE_MANAGER;//
binder_loop(bs, svcmgr_handler);//3:binder loop,处理客户端发送来的请求
return 0;
}
从main函数中可以看出,它主要做了4件事情:
- 打开/dev/binder设备,并在内存中映射128K的空间。
- 通知Binder设备,把自己变成context_manager
- 设置SELinux相关(这里忽略)
- 进入循环,不停的去读Binder设备,查询请求,若有则会调用svcmgr_handler函数回调处理请求。
这里对binder_open和binder_become_context_manager分别进行简要分析
1.1 binder_open的代码实现如下:
struct binder_state *binder_open(size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
...
bs->fd = open("/dev/binder", O_RDWR);
...
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
...
}
return bs;
...
}
这里主要负责打开设备,并进行内存映射
1.2 binder_become_context_manager的代码实现如下所示:
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
这里表示成为handle为0的manager,在驱动层就是建立了第一个binder_node红黑树节点。
1.3 binder_loop的代码实现如下所示:
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
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;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
...
/* 接收到请求,交给binder_parse,最后会调用func来处理 */
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
...
}
}
1.4 这里关键代码为binder_parse,继续分析,代码如下所示:
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) {
uint32_t cmd = *(uint32_t *) ptr;
ptr += sizeof(uint32_t);
switch(cmd) {
...
case BR_TRANSACTION: {
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
if ((end - ptr) < sizeof(*txn)) {
ALOGE("parse: txn too small!\n");
return -1;
}
binder_dump_txn(txn);
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
int res;
bio_init(&reply, rdata, sizeof(rdata), 4);
bio_init_from_txn(&msg, txn);
res = func(bs, txn, &msg, &reply);
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
}
ptr += sizeof(*txn);
break;
}
case BR_REPLY:
...
case BR_DEAD_BINDER: {
struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;
ptr += sizeof(binder_uintptr_t);
death->func(bs, death->ptr);
break;
}
...
default:
ALOGE("parse: OOPS %d\n", cmd);
return -1;
}
}
return r;
}
这里,当cmd为BR_TRANSACTION或者BR_DEAD_BINDER时,会使用func来处理,func的值为svcmgr_handler
1.5 svcmgr_handler的实现如下所示:
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;
/* 这里再判断一下target.handle 是不是0,即请求是不是发给自己的*/
if (txn->target.handle != svcmgr_handle)
return -1;
if (txn->code == PING_TRANSACTION)
return 0;
strict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
if ((len != (sizeof(svcmgr_id) / 2)) ||
memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
fprintf(stderr,"invalid id %s\n", str8(s, len));
return -1;
}
if (sehandle && selinux_status_updated() > 0) {
struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
if (tmp_sehandle) {
selabel_close(sehandle);
sehandle = tmp_sehandle;
}
}
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(bs, s, len, txn->sender_euid, txn->sender_pid);
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;
//添加服务的 分析入口
if (do_add_service(bs, s, len, handle, txn->sender_euid,allow_isolated, txn->sender_pid))
return -1;
break;
//得到系统当前已经注册的所有服务
case SVC_MGR_LIST_SERVICES: {
uint32_t n = bio_get_uint32(msg);
if (!svc_can_list(txn->sender_pid)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
txn->sender_euid);
return -1;
}
si = svclist;
while ((n-- > 0) && si)
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;
}
从handler这里开始 我们来分析 获取服务和添加服务的两大流程
2 添加服务 流程分析
继续分析do_add_service的实现,代码如下所示:
int do_add_service(struct binder_state *bs,const uint16_t *s, size_t len,
uint32_t handle, uid_t uid, int allow_isolated,pid_t spid)
{
struct svcinfo *si;
if (!handle || (len == 0) || (len > 127))
return -1;
/* 比较注册进程的uid和名字,看是否有权限注册,这里采用MAC模式检测 */
if (!svc_can_register(s, len, spid)) {
return -1;
}
si = find_svc(s, len); //这个主要是查询服务是否注册过,注册过就不会再注册
if (si) {
if (si->handle) {
svcinfo_death(bs, si);
}
si->handle = handle;
} else {
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
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; /* service退出的通知函数 */
si->death.ptr = si;
si->allow_isolated = allow_isolated;
/* svclist是一个list,保存了当前注册到ServiceManager中的信息 */
si->next = svclist;
svclist = si;
}
binder_acquire(bs, handle);
/* 当服务进程退出后,SM可以做些清理工作,例如释放前面malloc出来的si */
/* binder_link_to_death会做这项工作,每当服务进程退出时,SM都会得到来自binder设备的通知 */
binder_link_to_death(bs, handle, &si->death);
return 0;
}
添加服务的逻辑即:将驱动层收到的消息【“服务名”和对应分配的handle】添加到 svcinfo服务链表中,插入一个新节点
同时,下面是一些额外的说明,主要针对 注册权限相关的问题进行分析
2.1 svc_can_register在android5.0之前的实现与分析
svc_can_register主要用来判断注册服务的进程是否有权限,代码如下所示:
int svc_can_register(unsigned uid, uint16_t *name)
{
unsigned n;
//如果用户是root或者system,则权限够高,允许注册
if ((uid == 0) || (uid == AID_SYSTEM))
return 1;
for (n = 0; n < sizeof(allowed) / sizeof(allowed[0]); n++)
if ((uid == allowed[n].uid) && str16eq(name, allowed[n].name))
return 1;
return 0;
}
allowed数组控制那些权限达不到root和system的进程,定义如下所示:
/* TODO:
* These should come from a config file or perhaps be
* based on some namespace rules of some sort (media
* uid can register media.*, etc)
*/
static struct {
unsigned uid;
const char *name;
} allowed[] = {
{ AID_MEDIA, "media.audio_flinger" },
{ AID_MEDIA, "media.log" },
{ AID_MEDIA, "media.player" },
{ AID_MEDIA, "media.camera" },
{ AID_MEDIA, "media.audio_policy" },
{ AID_DRM, "drm.drmManager" },
{ AID_NFC, "nfc" },
{ AID_BLUETOOTH, "bluetooth" },
{ AID_RADIO, "radio.phone" },
{ AID_RADIO, "radio.sms" },
{ AID_RADIO, "radio.phonesubinfo" },
{ AID_RADIO, "radio.simphonebook" },
/* TODO: remove after phone services are updated: */
{ AID_RADIO, "phone" },
{ AID_RADIO, "sip" },
{ AID_RADIO, "isms" },
{ AID_RADIO, "iphonesubinfo" },
{ AID_RADIO, "simphonebook" },
{ AID_RADIO, "phone_msim" },
{ AID_RADIO, "isms_msim" },
{ AID_RADIO, "iphonesubinfo_msim" },
{ AID_RADIO, "simphonebook_msim" },
{ AID_MEDIA, "common_time.clock" },
{ AID_MEDIA, "common_time.config" },
{ AID_KEYSTORE, "android.security.keystore" },
{ AID_MEDIA, "listen.service" }
};
这样就可以查询对应的uid是否可以有注册服务name的权限了
如果Server进程权限不够root和system,那么要在allowed中添加相应的项
2.2 svc_can_register在android5.0之后的实现与分析
在android5.0之后,注册检查的方式放生了改变,使用了MAC机制检测,从svc_can_register开始分析,代码如下:
static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid)
{
const char *perm = "add";
return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0;
}
继续分析,check_mac_perms_from_lookup的具体实现如下:
static bool check_mac_perms_from_lookup(pid_t spid, const char *perm, const char *name)
{
bool allowed;
char *tctx = NULL;
if (selinux_enabled <= 0) {
return true;
}
if (!sehandle) {
ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
abort();
}
if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {
ALOGE("SELinux: No match for %s in service_contexts.\n", name);
return false;
}
allowed = check_mac_perms(spid, tctx, perm, name);
freecon(tctx);
return allowed;
}
接下来就是使用MAC检测机制了,check_mac_perms就是调用sepolicy机制中的函数。
3 获取服务 流程分析
继续分析do_find_service的实现,代码如下所示:
uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
struct svcinfo *si;
if (!svc_can_find(s, len, spid)) {//这里也是权限相关检查
ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n",
str8(s, len), uid);
return 0;
}
si = find_svc(s, len); //这里查询服务,遍历链表
//ALOGI("check_service('%s') handle = %x\n", str8(s, len), si ? si->handle : 0);
if (si && si->handle) {
if (!si->allow_isolated) {
// If this service doesn't allow access from isolated processes,
// then check the uid to see if it is isolated.
uid_t appid = uid % AID_USER;
if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
return 0;
}
}
return si->handle;
} else {
return 0;
}
}
在这里,继续分析find_svc函数,代码实现如下:
struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
struct svcinfo *si;
for (si = svclist; si; si = si->next) {
if ((len == si->len) &&
!memcmp(s16, si->name, len * sizeof(uint16_t))) {
return si;
}
}
return NULL;
}
在这里遍历整个svcinfo 的链表,从而完成对服务的查找,找到后流程上返回 handle。
4 总结
服务的注册流程本质上就是将服务信息放到系统维护的一个链表上,获取服务时,只需要查这个链表就可以了。
service_manager存在的意义:集中管理系统内所有服务,施加权限控制,保证并非任何进程都能注册服务。
系统中因为各种原因,Server进程生死无常,ServiceManager将其统一管理。Client只需要查询service_manager就可以获得最新动向,得到最新信息,就算是服务端挂了,也会受到对应的通知。