ServiceManager 的作用、启动流程和工作原理

  • 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对象,最后走到上面写的 # 查询服务 中。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值