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

相关推荐
编程圈子14 分钟前
操作系统学习14 IDT + PIC + 键盘中断
android·学习·计算机外设
齊家治國平天下7 小时前
Android 14 Vehicle HAL (VHAL) 设计与实现深度解析
android·aaos·carservice·车载开发·android 14·vhal·vehicle hal
AFinalStone13 小时前
Android 7系统网络(八)应用API层—ConnectivityManager使用与实战调试
android·网络
plainGeekDev13 小时前
kapt 替换为 KSP
android·java·kotlin
蜡台14 小时前
通过Gradle脚本声明更改Java变量
android·java·开发语言·python·kotlin·gradle·groovy
阿pin17 小时前
Android随笔-SharedPreferences
android·sp
阿pin17 小时前
Android随笔-DataStore
android·datastore
茶栀(*´I`*)18 小时前
Android 测试入门指南:ADB 基础配置与常用设备管理命令解析
android·adb
ihuyigui20 小时前
海外酒店预订短信接口
android·java·运维·服务器·前端·后端·架构
gxgldyh20 小时前
Android Framework源码解析(七):BootAnimation 启动流程解析——开机动画是如何显示出来的?
android