Binder中的Service Manager也太简单了吧

866 阅读10分钟

ServiceManager 分为三部分:framework 中的 java 层和 c++层和系统服务 c 层。我们可以认为这是 service manager 的服务端和客户端。这个设计也是一个典型的 binder C/S 结构。

Java(framework)层

ServiceManager
ServiceManager

这张类图,我们从左往右看。

  • ServiceManager.java是 framework 可以直接拿到的对象,目前对于 app 层是不能拿到的(但也是使用到了的,例如:Context.getSystemService(),是通过 ContextImpl -> SystemServiceRegistry -> 在注册方法中 new 出各种 Service 的 Java 端对象,或者说引用。然后在使用这个些对象中的方法时,就会调用到 ServiceManager)。

    ServiceManager.java 的主要职责是:提供获取服务、检查服务、发布服务等方法(不包含具体的获取等 action 的实现,但保存了一份副本 sCache,缓存常用的服务。)给 framework 使用。

  • IServiceManager.java是 ServiceManager.java 持有的引用。它提供了 ServiceManager.java 所需要的功能的具体实现的抽象。

  • ServiceManagerNative.java继承于 Binder.java,同时实现了 IServiceManager。源码中,它与 aidl 生成的类非常相似。所以它的职责是服务端的代理。这个类中的mRemote对象就是ServiceManager.java#getIServiceManager()中的 BinderInternal#getContextObject()对象。可以认为,ServiceManagerNative.java 就是为了和系统的 service manager 进程通信而构建的代理。

Native - C++层

源码路径:frameworks/native/libs/binder/

主要包含:IServiceManager.h、IServiceManager.cpp、ProcessState.cpp

  • IServiceManager.h 继承与 IInterface.h,因此具有 asInterface 和 onAsBinder 等方法,另外还有一些模板类,例如:

    template<typename INTERFACE>
    inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
    {
        return INTERFACE::asInterface(obj);
    }
    

IServiceManager.h 还定义了**defaultServiceManager()**和 getService 等方法。

  • IServiceManager.cpp 实现了 defaultServiceManager(),并从 ProcessState 中获取到 gDefaultServiceManager 的引用,是一个 BpBinder 对象,然后通过interface_cast 转换为 IServiceManager.cpp 中定义的 BpServiceManager 对象。而 BpServiceManager 是继承 BpInterface,其中包含了一个 remote 对象(目前可以理解为 c 层的 service_manager),因而 BpServiceManager 具有了远程通信的能力。进而去调用 getService 等方法。

  • ProcessState.cpp 是 Binder C++层重要的内容,对于 Service Manager 而言,它是注册 C++ 层 context object 的入口和实现的位置。它还是 IPCThreadState 的持有者,负责开启线程池等操作。由于这里主要是 Service Manager 的内容,就不对 Binder 实现进行展开。

Native - C 层

service manager 系统服务更简单了。关键类只有两个:service_manager.c 和 binder.c。它们的源码路径为:frameworks/native/cmds/servicemanager/

service_manager.c 在系统启动时由 rc 脚本拉起。进而在 c 文件的main()方法中(通过 ioctl 下沉到内核空间)注册自己为 context object 到 binder 驱动中。同时 service_manager.c 中维护了一个 svc_list 的链表,用于保存 service 的信息。


我话讲完。

等等,上面只讲了 service manager 的结构,并没有讲它是怎么工作的呀!

好的,我们来视察一下 service manager 的工作内容吧。

Service Manager 的工作过程

故事不长,请听我慢慢道来。

说在高三《四》班,数学老师叫小元,刚开学的时候他想选一个课代表。于是小俊同学就举手了,说我想做这个课代表。然后数学老师就问了,你为什么想做课代表啊?你能做些什么事呢?小俊说,我可以帮老师检查作业呀。我有一个专门的小本本(svclist)可以记住每个同学的名字(svcinfo),另外,我有个小弟(Java 层 sm)每天和同学们混在一起,可以很方便的收集同学们的意见(cmd),然后他会把意见(通过 binder 机制)放到我座位上[这个过程后续在 binder 驱动中详细分析],然后我可以一直(binder_loop)帮老师分类处理这些内容(svcmgr_handler)。


闲话少说,RTFSC!

我们从系统服务 service_manager.c 开始,看看这个狗腿子背着我们都干了些啥。

  1. 主函数
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";
    }

    bs = binder_open(driver, 128*1024); // 1. 打开驱动设备
    if (!bs) {
//...
    if (binder_become_context_manager(bs)) { // 2. 将自己注册成 context manager object(就是课代表)
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

//...

    binder_loop(bs, svcmgr_handler); // 只要干不死,就往死里干。注意:第二个参数svcmgr_handler传递的是一个函数。

    return 0;
}

service_manager 在启动后就开启了无限循环,读取消息。这一步有点类似于 ActivityThread 在启动后就开启了 Looper.loop()。

  1. svcmgr_handler
int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data_secctx *txn_secctx,
                   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;

    struct binder_transaction_data *txn = &txn_secctx->transaction_data;

    //ALOGI("target=%p code=%d pid=%d uid=%d\n",
    //      (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);

    if (txn->target.ptr != BINDER_SERVICE_MANAGER)
        return -1;

    if (txn->code == PING_TRANSACTION)
        return 0;
//...

    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,
                                 (const char*) txn_secctx->secctx);
        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, (const char*) txn_secctx->secctx))
            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, (const char*) txn_secctx->secctx, 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 == 0break;
                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;
}

主要是 case 分发,我们看一个具体的 case:SVC_MGR_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, uint32_t dumpsys_priority, pid_t spid, const char* sid) {
    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;

    if (!svc_can_register(s, len, spid, sid, 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) {
        if (si->handle) {
            ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
                 str8(s, len), handle, uid);
            svcinfo_death(bs, si);
        }
        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_acquire(bs, handle);
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

看吧,没什么难的。主要就是先查找一次,是不是已经添加过了。然后没有添加过把服务信息登记到小本本(svclist)上。

总结

本次的 service manager 主要是做一个整体性的理解。有很多细节可以展开讨论的。如 Java 层的 service manager 是怎么与 native 建立关系的(其实很明显是通过 Binder 机制)。从 c++层利用 context object 进行关联,传递到 c 层。

欢迎大家在此基础上展开讨论~