前言
本章主要围绕 ServiceManager 进行讲解,通过注册、启动等流程,玩转 ServiceManager;
ServiceManager 是什么?
客户端想要调用系统的 AMS 或者 PMS,但是客户端直接调用不到,只能获取到 AMS-IBinder 对象,AMS 在启动的时候就会把 AMS-IBinder 对象注册到 ServiceManager 中,客户端只要找到 ServiceManager 之后,就可以把 AMS-IBinder 对象返回给客户端,客户端就可以通过 AMS-IBinder 同 AMS 进行通信;
ServiceManager 它也是一个服务,但是它的句柄是确认的,也就是 handle = 0,而我们客户端在调用系统服务的时候,只需要调用这个已知道的 handle = 0 的服务就可以获取到 ServiceManager 的代理对象,然后就可以 同其他系统服务通信了;
ServiceManager 服务是如何注册的?
那么 ServiceManager 是怎么注册的呢?我们进入源码看一下,它的注册就在 init.rc 中:
// 打开 ServiceManager 这个程序,就会 调用 ServiceManager 的 main 方法
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
打开 ServiceManager 这个程序,就会 调用 servicemanager.c 的 main 方法,我们进入 main 方法看下:
int main(int argc, char **argv)
{
struct binder_state *bs;
// 这个方法做了两件事情,一是 open 方法,打开 binder 驱动,二是 mmap 方法,建立映射关系
bs = binder_open(128*1024);
if (!bs) {
ALOGE("failed to open binder driver\n");
return -1;
}
// 把 ServiceManager 设置成服务大管家
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
selinux_enabled = is_selinux_enabled();
sehandle = selinux_android_service_context_handle();
selinux_status_open(true);
if (selinux_enabled > 0) {
if (sehandle == NULL) {
ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
abort();
}
if (getcon(&service_manager_context) != 0) {
ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
abort();
}
}
union selinux_callback cb;
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
// 循环监听有没有其他服务访问
binder_loop(bs, svcmgr_handler);
return 0;
}
binder_open 这个方法做了两件事情,一是 open(128*1024) 方法,打开 binder 驱动,二是 mmap 方法,建立映射关系;
binder_become_context_manager 把 ServiceManager 设置成服务大管家;
binder_loop 循环监听有没有其他服务访问;
我们进入 binder_become_context_manager 这个方法看下,它是如何成为大管家的
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
直接调用的 ioctl 方法,传入的参数是 BINDER_SET_CONTEXT_MGR,而 这个方法最终调用到 binder_ioctl 中,我们进入 BINDER_SET_CONTEXT_MGR 这个 case 看下:
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
if (ret)
goto err;
break;
这个 case 中调用的是 binder_ioctl_set_ctx_mgr,我们进入这个方法看下:
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
struct binder_context *context = proc->context;
kuid_t curr_euid = current_euid();
// 先判断是不是已经存在了,存在则直接返回
if (context->binder_context_mgr_node) {
pr_err("BINDER_SET_CONTEXT_MGR already set\n");
ret = -EBUSY;
goto out;
}
ret = security_binder_set_context_mgr(proc->tsk);
if (ret < 0)
goto out;
// 判断 sm 的 uid 是否是有效的,第一次肯定是无效的,所以直接进入 else
if (uid_valid(context->binder_context_mgr_uid)) {
if (!uid_eq(context->binder_context_mgr_uid, curr_euid)) {
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
from_kuid(&init_user_ns, curr_euid),
from_kuid(&init_user_ns,
context->binder_context_mgr_uid));
ret = -EPERM;
goto out;
}
} else {
// 设置 uid
context->binder_context_mgr_uid = curr_euid;
}
// 通过 binder_new_node 创建 SM 的 binder_context_mgr_node 结构体
context->binder_context_mgr_node = binder_new_node(proc, 0, 0);
if (!context->binder_context_mgr_node) {
ret = -ENOMEM;
goto out;
}
context->binder_cont