文章目录
- ServiceManage 是 Binder 架构中用来解析 Binder 名称的模块。ServiceManager 本身就是一个 Binder 服务,但是 ServiceManager 并没有用 libbinder来构建 Binder 服务,而是自己实现了一个简单的框架来直接和驱动通信。
- ServiceManager 源码位于 frameworks/native/cmds/servicemanager/ 下,主要有 binder.c 来实现简单的通信功能,service_manager 用来实现上层的逻辑。
ServiceManager 的架构
- ServiceManager 的 main() 函数如下:
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
driver = "/dev/binder";
}
// 打开 /dev/binder 初始化系统 其内部通过 mmap() 函数创建一块内存空间
// 参数 mapsize = 128*1024 就是空间的大小 128k
bs = binder_open(driver, 128*1024);
if (!bs) {
return -1;
}
// 调用了 binder.c 中的 binder_become_context_manager(bs) 函数
// 作用:把本进程设置为 Binder 框架的管理进程
// 其内部非常简单 就是通过 ioctl 将 BINDER_SET_CONTEXT_MGR 发送到了驱动
// 调用了 binder_become_context_manager 后就代表我已经准备就绪了
if (binder_become_context_manager(bs)) {
return -1;
}
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);
#ifdef VENDORSERVICEMANAGER
sehandle = selinufx_android_vendor_service_context_handle();
#else
sehandle = selinux_android_service_context_handle();
#endif
selinux_status_open(true);
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();
}
// 最后调用 binder_loop 开启消息循环。将 svcmgr_handler 函数指针传入。
// binder_loop() 函数的主要作用就是从驱动读取命令解析后再 用svcmgr_handler 处理
binder_loop(bs, svcmgr_handler);
return 0;
}
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;
uint32_t dumpsys_priority;
//ALOGI("target=%p code=%d pid=%d uid=%d\n",
// (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
// 判断传入的 handler 类型
if (txn->target.ptr != BINDER_SERVICE_MANAGER)
return -1;
if (txn->code == PING_TRANSACTION)
return 0;
// 检查收到的 id 串
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;
}
// 检查 selinux 权限
if (sehandle && selinux_status_updated() > 0) {
#ifdef VENDORSERVICEMANAGER
struct selabel_handle *tmp_sehandle = selinux_android_vendor_service_context_handle();
#else
struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
#endif
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(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;
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;
}
- binder_loop 函数中调用了第一个阶段 binder_write
调用了 binder_write 前 readbuf[0] = BC_ENTER_LOOPER; 将线程变为 binder 线程
int binder_write(struct binder_state *bs, void *data, size_t len)
{
struct binder_write_read bwr;
int res;
// 设置了 write_size 则可以进行写操作
bwr.write_size = len;
bwr.write_consumed = 0;
bwr.write_buffer = (uintptr_t) data;
// read_size= 0 则代表不进行读操作
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
// ioctl 既可以写也可以读 最终看 write_size 和 read_size 是否>0 如果都 > 0 则先写后读
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n",
strerror(errno));
}
return res;
}
- binder_loop 第二个阶段开启循环等待处理请求
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
// 将write_size 设置为 0 ;代表不再写
// ioctl 传入的 bwr.write_size > 0 则进行写操作 如果 bwr.read_size > 0 则进行读操作,如果都 > 0 则先写后读
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
// 将当前线程注册为 binder 线程
readbuf[0] = BC_ENTER_LOOPER;
// 第一个阶段
binder_write(bs, readbuf, sizeof(uint32_t));
// 第二个阶段
for (;;) {
// 设置 read_size 代表 for(;;) 中不断进行读取操作
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
// 然后解析数据 通过 func 回调回去
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
ALOGE("binder_loop: unexpected reply?!\n");
break;
}
if (res < 0) {
ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
break;
}
}
}
ServiceManager 的架构非常简单,只有一个循环来处理消息。没有像 libbinder 中需要多线程去处理配合整个流程。
ServiceManager 提供的服务
从上面的代码来看 ServiceManager 主要提供 注册 binder 服务、查询 binder 服务 和 获取 binder 服务。
注册 binder 服务
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;
//ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
// allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
if (!handle || (len == 0) || (len > 127))
return -1;
// svc_can_register() 是检查用户权限的函数
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;
}
// 检查注册服务是否已经存在
si = find_svc(s, len);
if (si) {
// 如果存在先把之前 Binder 对象引用计数 -1
if (si->handle) {
ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
str8(s, len), handle, uid);
svcinfo_death(bs, si);
}
// 把节点中的 ptr 换成新值
si->handle = handle;
} else {
// 如果不存在则生成新的列表项,初始化加入列表
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;
}
do_add_service() 的流程主要是先检查进程是否有权限注册,接着查看是否已经注册过服务,如果已经存在则在驱动中引动计数器-1,不存在则创建一个svcinfo 的结构,把服务的名称存入结构中,并把结构存入到列表 svclist 中。最后 通知Binder引用计数起+1,并且接收Binder死亡通知。
- 检查进程是否有权限的方法 svc_can_register()
static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{
const char *perm = "add";
if (multiuser_get_app_id(uid) >= AID_APP) {
return 0; /* Don't allow apps to register services */
}
return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
检查权限的逻辑在 5.0 以前是root 或者 System 应用可以任意注册,否责只能在 allowed 列表中定义的进程注册表中规定的服务,目的是希望能控制这些服务。Android 5.0 以后取消了这张表,用 SELinux 的权限控制来代替这张表。函数 check_mac_perms_from_lookup() 如下:
static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
{
bool allowed;
char *tctx = NULL;
if (!sehandle) { // 如果 sehandle 为null 退出 service_manager
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;
}
// 调用 check_mac_perms 来判断权限
allowed = check_mac_perms(spid, uid, tctx, perm, name);
freecon(tctx);
return allowed;
}
check_mac_perms_from_lookup() 对 SELinux 环境 和 name进行检查后调用了 check_mac_perms() 函数来检查权限。
static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
{
char *sctx = NULL;
const char *class = "service_manager";
bool allowed;
struct audit_data ad;
if (getpidcon(spid, &sctx) < 0) { // 获取进程上下文
ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
return false;
}
ad.pid = spid;
ad.uid = uid;
ad.name = name;
// 检查进程是否有权限进行操作
int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);
allowed = (result == 0);
freecon(sctx);
return allowed;
}
查询服务
- 查询服务调用的函数为 do_find_service(s, len, txn->sender_euid, txn->sender_pid);
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
struct svcinfo *si = find_svc(s, len);
if (!si || !si->handle) {
return 0;
}
if (!si->allow_isolated) {
// 如果 Binder 服务不允许从沙箱中访问,执行下面检查。
// If this service doesn't allow access from isolated processes,
// then check the uid to see if it is isolated.
// 先对 AID_USER 取模,然后在判断是否在 AID_ISOLATED_START AID_ISOLATED_END 区间
uid_t appid = uid % AID_USER;
if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
return 0;
}
}
if (!svc_can_find(s, len, spid, uid)) {
return 0;
}
return si->handle;
}
do_find_service() 函数主要是搜索列表,返回查找的服务。这里面有一段关于 uid 的代码。在调用 addBinder() 服务时有个参数是 allowed_isolated ,用来指定服务是否允许从隔离的进程中访问。这里的代码就是判断进程是否是隔离进程。方法在上面代码中有介绍。
ServiceManager 启动流程
- 启动进程
ServiceManager 和一般的系统服务不一样,一般的系统服务是在 SystemServer 中启动的比如 AMS,PMS 等,ServiceManager 是第一个单独进程启动的
- 启动 binder 服务
无论是和系统服务通信,还是和应用服务通信,都涉及到跨进程通信,所以需要 binder 机制
- 发布自己的服务
其他服务的发布都需要通过 ServiceManager 来注册,所以它需要在其他服务注册之前注册到 binder 驱动
- 等待并响应请求
它注册好之后,就可以等待其他服务的请求并响应了。binder_loop,上面有代码介绍
怎样获取 ServiceManager 的 binder 对象
- 以 SurfaceFlinger 为例,它是以单独进程启动的服务,启动文件如下:
service surfaceflinger /system/bin/surfaceflinger
class core
user system
group graphics drmrpc readproc
onrestart restart zygote
writepid /dev/stune/foreground/tasks
disabled
surfaceflinger 的启动入口函数在 main_surfaceflinger.cpp,看他内部注册的时候是如何获取 ServiceManager 的
int main(int, char**) {
// start the thread pool
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
// instantiate surfaceflinger
sp<SurfaceFlinger> flinger = new SurfaceFlinger();
flinger->init();
// publish surface flinger
sp<IServiceManager> sm(defaultServiceManager());
sm->addService(String16(SurfaceFlinger::getServiceName()), flinger, false,
IServiceManager::DUMP_FLAG_PRIORITY_CRITICAL | IServiceManager::DUMP_FLAG_PROTO);
// publish GpuService
sp<GpuService> gpuservice = new GpuService();
sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
}
可以看到它通过调用 defaultServiceManager 获取到的 sm 在调用其 addService()
- defaultServiceManager()
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
// 通过调用 getContextObject() 获取 IServiceManager 接口对象
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
// 为什么有可能获取不到 因为 ServiceManager 和 surfaceflinger 都是被 init进程拉起来的有可能 ServiceManager 还没启动
sleep(1);
}
}
return gDefaultServiceManager;
}
- getContextObject()
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
- getStrongProxyForHandle()
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
实际上返回的 BinderProxy对象就是 BpBinder对象对应的 handle 是 0
怎样向 ServiceManager 添加服务?
- 还是上面的 main_surfaceflinger.cpp,中获取到了 ServiceManager 的接口对象后,调用了
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated, int dumpsysPriority) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
data.writeInt32(dumpsysPriority);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
主要看上面代码的 remote()->transac 函数,先通过 函数 拿到 bpbinder对象,然后调用了 transac 函数
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
transac 又把请求交给了 IPCThreadState::self()->transact 函数,IPCThreadState 是直接和 binder 交互的对象,传入的 mHandle 值就能让驱动知道对应的实体是谁
- 最后会发送到最开始描述架构中 注册 binder 服务 中的 do_add_service() 函数,然后注册服务就完了
怎样向 ServiceManager 注册服务?
获取 ServiceManager 注册过的服务,大体差不多,也是先和添加服务一样,获取到 ServiceManager对象,最后走到上面写的 # 查询服务 中。