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初始化时序图

相关推荐
拭心10 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
带电的小王13 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡13 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道13 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库14 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道15 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe15 小时前
Android Hook - 动态加载so库
android
居居飒16 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
Henry_He18 小时前
桌面列表小部件不能点击的问题分析
android
工程师老罗19 小时前
Android笔试面试题AI答之Android基础(1)
android