Binder - 2、servicemanager的初始化

一、前言

两个进程之间想要通信,就必须要知道对方的地址才行,这样的话,就必须要有一个"中间人"来做注册才行,servicemanager正是做这个事的,那又涉及到一个问题,应用进程怎么知道servicemanager的地址?看起来是一个"先有鸡还是先有蛋"的问题。我们知道,一般这种情况,我们可以将中间人设置一个大家都知道的公用地址,这样就都可以进行访问了。

二、servicemanager进程

既然是中间人,那么servicemanager就应该有一个"中立的"进程。

2.1 进程启动

servicemanager是通过.rc初始化的,在系统初始化的时候,.rc文件会被解析:

frameworks/native/cmds/servicemanager/servicemanager.rc

sql 复制代码
service servicemanager /system/bin/servicemanager

    class core animation

    user system

    group system readproc

    critical

    onrestart restart apexd

    onrestart restart audioserver

    onrestart restart gatekeeperd

    onrestart class_restart main

    onrestart class_restart hal

    onrestart class_restart early_hal

    writepid /dev/cpuset/system-background/tasks

    shutdown critical

关于.rc的语法,我们不需要过多了解,等解析完之后,系统会将/system/bin/servicemanager文件启动为servicemanager进程,通过ps也可以看到该进程:

perl 复制代码
$ adb shell "ps -A | grep servicemanager"

system         216     1 10865356  4284 0                   0 S servicemanager

2.2 入口

servicemanager的入口是main.cpp,位置是frameworks\native\cmds\servicemanager\main.cppmain函数我们再熟悉不过了,看下代码:

c++ 复制代码
int main(int argc, char** argv) {

    //获取binder驱动名

    const char* driver = argc == 2 ? argv[1] : "/dev/binder";

    //初始化Binder驱动

    sp<ProcessState> ps = ProcessState::initWithDriver(driver);

    //设置最大线程数量

    ps->setThreadPoolMaxThreadCount(0);

    ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

    //新建ServiceManager对象

    sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());

    if (!manager->addService("manager", manager, false /*allowIsolated*/)

    //将ServiceManager设置到IPCThreadState

    IPCThreadState::self()->setTheContextObject(manager);

    // !!成为ContextManager

    ps->becomeContextManager();

    sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);

    //开启事件循环

    BinderCallback::setupTo(looper);

    ClientCallbackCallback::setupTo(looper, manager);

    while(true) {

        looper->pollAll(-1);

    }

    return EXIT_FAILURE;

}

进程启动之后,做这几件事情:

  • 1、初始化Binder驱动

  • 2、新建ServiceManager对象,并执行addService方法

  • 3、将ServiceManager设置到IPCThreadState

  • 4、成为ContextManager

  • 5、开启事件循环

2.2.1 initWithDriver

initWithDriver与我们上一次分析的init方法实际上区别不大

2.2.2 ServiceManager初始化

c++ 复制代码
ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access))

平平无奇,下一个

2.2.3 addService

c++ 复制代码
  


Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {

    auto ctx = mAccess->getCallingContext();

    //异常逻辑,省略

    // Overwrite the old service if it exists

    mNameToService[name] = Service {

        .binder = binder,

        .allowIsolated = allowIsolated,

        .dumpPriority = dumpPriority,

        .debugPid = ctx.debugPid,

    };

}

异常逻辑省略,主要是存到mNameToService中,方面后面获取

2.2.4 becomeContextManager

c++ 复制代码
bool ProcessState::becomeContextManager()

{

    AutoMutex _l(mLock);

  


    flat_binder_object obj {

        .flags = FLAT_BINDER_FLAG_TXN_SECURITY_CTX,

    };

    //只看这个

    int result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR_EXT, &obj);

    // fallback to original method

    if (result != 0) {

        android_errorWriteLog(0x534e4554, "121035042");

        int unused = 0;

        result = ioctl(mDriverFD, BINDER_SET_CONTEXT_MGR, &unused);

    }

    return result == 0;

}

我们只关注第一个ioctl,这里调用到Binder驱动中,关键字为BINDER_SET_CONTEXT_MGR_EXT

c++ 复制代码
case BINDER_SET_CONTEXT_MGR_EXT:

{

    struct flat_binder_object fbo;

  


    if (copy_from_user(&fbo, ubuf, sizeof(fbo))) {

        ret = -EINVAL;

        goto err;

    }

    ret = binder_ioctl_set_ctx_mgr(filp, &fbo);

    if (ret)

        goto err;

    break;

}

看一下binder_ioctl_set_ctx_mgr

c++ 复制代码
static int binder_ioctl_set_ctx_mgr(struct file *filp,

                    struct flat_binder_object *fbo)

{

    int ret = 0;

    struct binder_proc *proc = filp->private_data;

    struct binder_context *context = proc->context;

    struct binder_node *new_node;

    kuid_t curr_euid = current_euid();

    //创建Binder节点

    new_node = binder_new_node(proc, fbo);

    //修改引用计数

    new_node->local_weak_refs++;

    new_node->local_strong_refs++;

    new_node->has_strong_ref = 1;

    new_node->has_weak_ref = 1;

    //将new_node设置为binder_context_mgr_node

    context->binder_context_mgr_node = new_node;

    binder_put_node(new_node);

    return ret;

}
  • 1、创建Binder节点

  • 2、修改节点的引用计数

  • 3、设置该节点为binder_context_mgr_node,后续其他进程正是用这个来访问servicemanager

在这里我们又看到两个数据结构binder_nodebinder_context

图2.1 - binder_node的结构

c++ 复制代码
struct binder_context {

    struct binder_node *binder_context_mgr_node;

    struct mutex context_mgr_node_lock;

    kuid_t binder_context_mgr_uid;

    const char *name;

};

binder_context结构相对比较简单。主要是保存binder_context_mgr_node的地址,也就是servicemanager

至此,我们将servicemanager设置给了驱动层,后面的操作就可以通过引用binder_context_mgr_node来完成了。

2.2.5 BinderCallback::setupTo

说完了becomeContextManager,我们回头看下最后一段逻辑,首先是创建一个LooperLooper我们知道是消息循环机制,然后看BinderCallback::setupTo:

c++ 复制代码
static sp<BinderCallback> setupTo(const sp<Looper>& looper) {

    sp<BinderCallback> cb = sp<BinderCallback>::make();

    int binder_fd = -1;

    //获取Binder驱动的fd

    IPCThreadState::self()->setupPolling(&binder_fd);

    //添加对Binder驱动fd的监听

    int ret = looper->addFd(binder_fd,

                            Looper::POLL_CALLBACK,

                            Looper::EVENT_INPUT,

                            cb,

                            nullptr /*data*/);

    return cb;

}

  


int handleEvent(int /* fd */, int /* events */, void* /* data */) override {

    IPCThreadState::self()->handlePolledCommands();

    return 1;  // Continue receiving callbacks.

}

我们知道looper使用的是epoll机制,在收到事件的时候,就会触发这里的handleEvent,最终进入handlePolledCommands:

c++ 复制代码
status_t IPCThreadState::handlePolledCommands()

{

    status_t result;

    do {

        //循环与Binder驱动通信

        result = getAndExecuteCommand();

    } while (mIn.dataPosition() < mIn.dataSize());

    processPendingDerefs();

    flushCommands();

    return result;

}

在没有事情做的时候,这个线程就会睡眠,等有事件过来,线程就被唤醒,然后开始从Binder驱动中读取数据,具体的交互逻辑我们在后面分析。

三、总结

servicemanager作为一个单独的进程存在,为其他的进程提供服务,servicemanager在启动之后,将创建出来的对象地址设置到Binder驱动层,然后进入循环,等待Binder驱动的唤醒,servicemanager初始化完毕。

图3.1 - ServiceManager初始化时序图

相关推荐
闲暇部落24 分钟前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX2 小时前
Android 分区相关介绍
android
大白要努力!3 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle
Estar.Lee3 小时前
时间操作[取当前北京时间]免费API接口教程
android·网络·后端·网络协议·tcp/ip
Winston Wood4 小时前
Perfetto学习大全
android·性能优化·perfetto
Dnelic-7 小时前
【单元测试】【Android】JUnit 4 和 JUnit 5 的差异记录
android·junit·单元测试·android studio·自学笔记
Eastsea.Chen9 小时前
MTK Android12 user版本MtkLogger
android·framework
长亭外的少年16 小时前
Kotlin 编译失败问题及解决方案:从守护进程到 Gradle 配置
android·开发语言·kotlin
建群新人小猿19 小时前
会员等级经验问题
android·开发语言·前端·javascript·php
1024小神20 小时前
tauri2.0版本开发苹果ios和安卓android应用,环境搭建和最后编译为apk
android·ios·tauri