优秀的编程知识分享平台

网站首页 > 技术文章 正文

Android 系统核心机制binder(05)servicemanager详解

nanyue 2025-08-05 20:14:13 技术文章 2 ℃

本章关键点总结 & 说明:

这里主要对service_manager进程进行了分析,关注 进程的流程和 两个处理流程(添加服务和 获取服务)。

通过分析service_manager,进而对add_service请求的处理流程进行分析。通过这样的分析,后面 getservice的流程也是类似的。

1 service_manager的主函数main的分析

说明:在源码分析时,由于Binder中SELinux的东西比较多,起初的分析容易影响我们对Binder主干的影响,因此在分析前期,将所有SELinux相关的函数均直接无视

这里service_manager起到的作用实际上是BnServiceManager的作用,即处理请求。ServiceManager的入口函数为:

C++
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的代码实现如下:

C++
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的代码实现如下所示:

C++
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的代码实现如下所示:

C++
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,继续分析,代码如下所示:

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;

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的实现如下所示:

C++
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的实现,代码如下所示:

C++
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主要用来判断注册服务的进程是否有权限,代码如下所示:

C++
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的进程,定义如下所示:

C++
/* 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开始分析,代码如下:

C++
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的具体实现如下:

C++
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的实现,代码如下所示:

C++
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函数,代码实现如下:

C++
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就可以获得最新动向,得到最新信息,就算是服务端挂了,也会受到对应的通知。

Tags:

最近发表
标签列表