Skip to content

ServiceManager启动

追踪 ServiceManager 从 init 服务定义、Binder context manager 注册到 Looper 轮询和客户端回调定时器的启动主线。

基于android-17.0.0_r1
AndroidBinderServiceManagercontext manager源码阅读

ServiceManager启动 ​

ServiceManager 启动并不是“new 一个对象后调用 joinThreadPool()”。Android 17 的 servicemanager 进程先初始化 /dev/binder 对应的 ProcessState,明确禁止普通同步 Binder 调用和额外线程池线程;随后创建本地 ServiceManager,先把它登记为名为 manager 的服务和 context object,再通过 becomeContextManager() 占据 Binder 驱动的 context-manager 角色。运行阶段由 Looper 同时轮询 Binder fd 和一个 client-callback timerfd。

本文面向已经读过 Binder设备打开、BINDER_WRITE_READ命令、Binder线程管理 和 Binder死亡通知 的读者。本文只讲 AOSP servicemanager 进程如何达到“可处理服务目录请求”的状态,不提前展开 addService()、getService()、VINTF accessor 或 lazy service 的具体业务规则。

读完后,应该能从 init rc 定义找到可执行程序,再从 main() 解释为什么 setThreadPoolMaxThreadCount(0) 不代表进程不会收 Binder 请求,为什么 setTheContextObject() 与 becomeContextManager() 缺一不可,以及 Binder fd 回调、定时器回调和 ready property 分别在何时生效。

1. 启动边界 ​

1.1 Init服务 ​

源码文件:frameworks/native/cmds/servicemanager/servicemanager.rc

text
service servicemanager /system/bin/servicemanager
    class core animation
    user system
    group system readproc
    critical
    file /dev/kmsg w
    onrestart setprop servicemanager.ready false
    onrestart restart --only-if-running apexd
    onrestart restart audioserver
    onrestart restart gatekeeperd
    onrestart class_restart --only-enabled main
    onrestart class_restart --only-enabled hal
    onrestart class_restart --only-enabled early_hal
    task_profiles ProcessCapacityHigh
    shutdown critical

这份 rc 文件定义 AOSP 系统镜像中的 servicemanager 服务:它属于 core animation class,以 system 用户运行,并在重启时先清除 ready property,再重启一组依赖服务。critical 和 shutdown critical 是 init 对此服务的策略,不是 Binder 驱动的 context-manager 协议字段;设备厂商可以在自己的系统配置中加入额外策略。

1.2 可执行目标 ​

源码文件:frameworks/native/cmds/servicemanager/Android.bp

相关模块:servicemanager

Android.bp 将 main.cpp、ServiceManager.cpp 和 Access.cpp 组成 servicemanager 可执行程序,并链接 binder、utils、base 等库。这里的可执行模块与 ServiceManager C++ 类不是同一个概念:前者由 init 启动,后者是该进程内接受 Binder 调用的本地对象。

2. Main顺序 ​

2.1 参数与日志 ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

相关函数:main()

cpp
android::base::InitLogging(
        argv, android::base::KernelLogger);

if (argc > 2) {
    LOG(FATAL) << "usage: "
               << argv[0]
               << " [binder driver]";
}

const char* driver = argc == 2
        ? argv[1] : "/dev/binder";
LOG(INFO) << "Starting sm instance on "
          << driver;

程序只接受零或一个 Binder driver 路径参数。默认路径是 /dev/binder;参数检查失败会在任何 Binder 状态建立之前 fatal。日志采用 KernelLogger,这影响观测位置,不改变 ServiceManager 的 Binder 协议。

2.2 主线图 ​

图中的两个 callback 共用同一 Looper,但职责不同:Binder fd 有输入时消费驱动命令,timerfd 到期时检查服务的 client callback 状态。前者是服务目录 Binder 请求的入口,后者不是 Binder transaction 的替代路径。

3. Binder准备 ​

3.1 ProcessState ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

相关函数:main()

cpp
sp<ProcessState> ps =
        ProcessState::initWithDriver(driver);
ps->setThreadPoolMaxThreadCount(0);
ps->setCallRestriction(
        ProcessState::CallRestriction::
                FATAL_IF_NOT_ONEWAY);

IPCThreadState::self()->
        disableBackgroundScheduling(true);

initWithDriver() 建立本进程的 Binder driver 与 VMA 状态。线程池上限设为 0 表示 ServiceManager 不依赖 startThreadPool()/joinThreadPool() 创建额外 Binder worker;它仍可通过下文的 setupPolling() 在主 Looper 线程处理 Binder fd。调用限制是本进程作为调用方的约束,防止 ServiceManager 主动做普通同步 Binder 调用;它不阻止其他进程同步调用 ServiceManager。

禁用后台调度影响当前 IPCThreadState 的调度行为,不能简化为“ServiceManager 永远只有一个 Linux 线程”。本篇只证明主服务循环的 Binder 消费由 Looper 注册的 fd 承担。

3.2 本地对象 ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

相关类型:ServiceManager、Access

cpp
sp<ServiceManager> manager =
        sp<ServiceManager>::make(
                std::make_unique<Access>());
manager->setRequestingSid(true);

if (!manager->addService(
        "manager", manager,
        false /*allowIsolated*/,
        IServiceManager::
                DUMP_FLAG_PRIORITY_DEFAULT)
                .isOk()) {
    LOG(ERROR) << "Could not self register "
               << "servicemanager";
}

manager 是一个本地 Binder 实体,Access 是服务目录 API 的权限判断 owner。setRequestingSid(true) 要求 transaction 交付时带上 SELinux security context;自注册把名称 manager 放入 ServiceManager 自己的服务表,为同进程服务目录 API 提供普通名字查询入口。日志错误不立即终止,后续 context-manager 注册仍会执行。

3.3 Context角色 ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

相关函数:IPCThreadState::setTheContextObject()、ProcessState::becomeContextManager()

cpp
IPCThreadState::self()->
        setTheContextObject(manager);
if (!ps->becomeContextManager()) {
    LOG(FATAL) << "Could not become "
               << "context manager";
}

这两步的 owner 不同:setTheContextObject() 设置本进程用户态在收到 context-manager transaction 时要分发给的 BBinder 对象;becomeContextManager() 通过 driver 协议申请全局 context-manager 角色。只有前者会留下本地分发对象,只有后者会让其他进程的 handle 0 请求被驱动路由到该 Binder context。后者失败会 fatal,因为没有 context-manager 的 ServiceManager 不能承担目录角色。

4. Looper消费 ​

4.1 Binder fd ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

相关类型:BinderCallback

cpp
IPCThreadState::self()->setupPolling(
        &cb->mBinderFd);
LOG_ALWAYS_FATAL_IF(cb->mBinderFd < 0,
        "Failed to setupPolling: %d",
        cb->mBinderFd);

int ret = looper->addFd(
        cb->mBinderFd,
        Looper::POLL_CALLBACK,
        Looper::EVENT_INPUT, cb, nullptr);
LOG_ALWAYS_FATAL_IF(ret != 1,
        "Failed to add binder FD to Looper");

setupPolling() 把当前 IPCThreadState 准备为可轮询的 Binder fd;Looper::addFd() 只注册输入事件,尚未执行 transaction。fd 无效或注册失败都会 fatal,因为主循环无法再接收 Binder work。

4.2 Binder回调 ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

相关函数:BinderCallback::handleEvent()

cpp
int handleEvent(int /*fd*/, int /*events*/,
        void* /*data*/) override {
    IPCThreadState::self()->
            handlePolledCommands();
    return 1;
}

当 Binder fd 可读时,Looper 调用这个 callback;handlePolledCommands() 再读取 BR 命令、把请求分发给 context object 或处理其他 Binder command。返回 1 表示 callback 保持注册,因而不是“一次处理后退出”的线程池循环。

4.3 Client定时器 ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

相关类型:ClientCallbackCallback

cpp
itimerspec timespec {
    .it_interval = { .tv_sec = 5 },
    .it_value = { .tv_sec = 5 },
};
timerfd_settime(fdTimer, 0, &timespec, nullptr);

int handleEvent(int fd, int /*events*/,
        void* /*data*/) override {
    uint64_t expirations;
    read(fd, &expirations, sizeof(expirations));
    mManager->handleClientCallbacks();
    mBinderCallback->repoll();
    return 1;
}

定时器每 5 秒触发一次 ServiceManager 的 client callback 检查,再显式 repoll Binder fd。它服务于 lazy service/client 状态,而不是周期性扫描服务注册表的通用机制;timerfd 读取失败只记录错误,callback 仍返回 1 继续运行。

5. Ready与循环 ​

5.1 Ready属性 ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

cpp
#ifndef VENDORSERVICEMANAGER
if (!SetProperty(
        "servicemanager.ready", "true")) {
    LOG(ERROR) << "Failed to set "
               << "servicemanager ready property";
}
#endif

默认 ServiceManager 在 context-manager 成功、Looper callback 与 client callback timer 建立之后才尝试发布 ready;编译为 VENDORSERVICEMANAGER 时这段不参与。SetProperty 失败只记录错误,主循环仍然启动,因此 property true 是启动完成的可观测信号,不是 Binder driver 本身的有效性证明。

5.2 无限轮询 ​

源码文件:frameworks/native/cmds/servicemanager/main.cpp

cpp
while (true) {
    looper->pollAll(-1);
}

pollAll(-1) 无限等待 fd 事件。正常路径没有“启动函数返回成功”的阶段:进程一旦进入循环,就通过 Binder callback 和 timer callback 重复处理工作。fatal 失败发生在进入循环前的 Binder fd、context-manager 或 timer 注册关键步骤。

6. 失败与恢复 ​

阶段条件可观察结果后续状态
参数多于一个 driver 参数LOG(FATAL)未打开 Binder
Context角色becomeContextManager() 失败LOG(FATAL)不进入 Looper
Binder轮询fd 无效或 addFd 失败LOG_ALWAYS_FATAL_IF不进入主循环
Timertimerfd_create/settime/addFd 失败LOG_ALWAYS_FATAL_IF不发布 ready
自注册addService("manager") 失败记录 error继续尝试 context-manager
Ready属性SetProperty 失败记录 error仍进入 pollAll
进程重启init service 重启规则ready 先置 falseinit 重建进程状态

ServiceManager 的 init critical 策略与内部 LOG(FATAL) 需要区分:前者决定 init 如何处理进程反复失败,后者是当前进程是否继续运行的代码路径。本文不从 rc 文件推导设备实际重启阈值或厂商重启策略。

7. 测试边界 ​

7.1 名称工具 ​

源码文件:frameworks/native/cmds/servicemanager/ServiceManagerUnittest.cpp

相关测试:ServiceManager.NativeName、NativeName_Malformed

这些 unit test 覆盖 native service 名称转换与格式错误,不启动真实 main(),也不打开 Binder driver、申请 context-manager 或运行 Looper。它们能反向约束 ServiceManager 的名称辅助逻辑,但不能证明启动顺序。

7.2 Main边界 ​

当前 cmds/servicemanager 的单元测试和 fuzz target 主要覆盖 ServiceManager API、名称处理和输入健壮性;在固定源码范围内没有找到直接执行生产 main()、真实 becomeContextManager()、Binder fd poll 与 ready property 的单元测试。本文对这些步骤只依据源码控制流和 fatal/错误分支,不把未执行的设备启动写成运行观察。

7.3 可执行验证 ​

读者可先从源码复现顺序:

bash
rg -n "initWithDriver|setThreadPoolMaxThreadCount|setTheContextObject|becomeContextManager|pollAll" \
  frameworks/native/cmds/servicemanager/main.cpp

rg -n "setupPolling|handlePolledCommands|timerfd_create|handleClientCallbacks|repoll" \
  frameworks/native/cmds/servicemanager/main.cpp

rg -n "service servicemanager|critical|onrestart|servicemanager.ready" \
  frameworks/native/cmds/servicemanager/servicemanager.rc

rg -n "NativeName|Malformed" \
  frameworks/native/cmds/servicemanager/ServiceManagerUnittest.cpp

如果能解释“为什么 0 线程池仍然能服务 Binder 请求”“为什么 context object 和 context-manager 注册各自不可替代”“为什么 ready property 在 Looper 建立后才设置”“为什么自注册失败与 context-manager fatal 是不同级别的错误”,就已经掌握了 ServiceManager 启动的真实边界。