Skip to content

LazyServiceRegistrar

追踪 LazyServiceRegistrar 注册、客户端计数回调、自动注销、进程退出和重新注册路径。

基于android-17.0.0_r1
AndroidBinderServiceManagerLazyServiceRegistrar源码阅读

LazyServiceRegistrar ​

LazyServiceRegistrar 把“服务没有客户端时可以退出”变成一条可执行的 Binder 状态机:注册时强制加入 lazy 标志并向 ServiceManager 注册 IClientCallback;ServiceManager 根据 Binder 引用计数回调 onClients(true/false);当进程中所有服务都没有客户端时,注册器尝试注销全部服务并退出。注销失败则重新注册,避免服务名消失后客户端永远无法找到它。

本文面向已经读过 addService注册服务、getService查询服务、waitForService等待服务 和 SM的Binder死亡通知 的读者。本文只讲 lazy 服务端注册器如何消费 ServiceManager 的 client callback;查询端如何发起 ctl.interface_start 只作为对端边界,不重复展开。

1. 注册入口 ​

1.1 单例对象 ​

源码文件:frameworks/native/libs/binder/LazyServiceRegistrar.cpp

相关函数:getInstance()、registerService()

cpp
LazyServiceRegistrar& LazyServiceRegistrar::getInstance() {
    static auto registrarInstance = new LazyServiceRegistrar();
    return *registrarInstance;
}

status_t LazyServiceRegistrar::registerService(
        const sp<IBinder>& service, const std::string& name,
        bool allowIsolated, int dumpFlags) {
    if (!mClientCC->registerService(
            service, name, allowIsolated, dumpFlags)) {
        return UNKNOWN_ERROR;
    }
    return OK;
}

默认对象是进程内单例;createExtraTestInstance() 明确只为测试竞态。单例的意义是一个进程内所有 lazy 服务共享客户端计数,不能为每个服务随意创建独立 registrar。

1.2 强制lazy位 ​

源码文件:frameworks/native/libs/binder/LazyServiceRegistrar.cpp

相关函数:ClientCounterCallbackImpl::registerServiceLocked()

cpp
if (dumpFlags & android::os::IServiceManager::FLAG_IS_LAZY_SERVICE) {
    ALOGW("FLAG_IS_LAZY_SERVICE flag already set.");
}
dumpFlags |= android::os::IServiceManager::FLAG_IS_LAZY_SERVICE;

if (Status status = manager->addService(
        name.c_str(), service, allowIsolated, dumpFlags);
        !status.isOk()) {
    return false;
}

调用方不需要自行设置 lazy 位;注册器会强制设置。dumpFlags 同时保留原有 priority,lazy 只是额外的 metadata 位。

2. 回调建立 ​

2.1 首次注册 ​

cpp
bool reRegister = mRegisteredServices.count(name) > 0;
if (!reRegister) {
    if (Status status = manager->registerClientCallback(
            name, service,
            sp<android::os::IClientCallback>::fromExisting(this));
            !status.isOk()) {
        return false;
    }
    mRegisteredServices[name] = {
        .service = service,
        .allowIsolated = allowIsolated,
        .dumpFlags = dumpFlags
    };
}

第一次注册才建立 client callback 和本地记录;重新注册只重新调用 addService()。本地 mRegisteredServices 保存服务对象、权限和 flags,并额外记录 clients、registered 状态。

2.2 服务端回调 ​

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

相关函数:registerClientCallback()

ServiceManager 要求 callback 非空、调用者是该服务进程、传入 Binder 与当前服务表对象相同,然后调用 linkToDeath() 并把 callback 放进 mNameToClientCallback。因此注册器不是普通观察者,而是服务 owner 对自己服务的受限回调。

3. 客户端计数 ​

3.1 回调入口 ​

源码文件:frameworks/native/libs/binder/LazyServiceRegistrar.cpp

相关函数:ClientCounterCallbackImpl::onClients()

cpp
Status ClientCounterCallbackImpl::onClients(
        const sp<IBinder>& service, bool clients) {
    std::lock_guard<std::mutex> lock(mMutex);
    auto& [name, registered] = *assertRegisteredService(service);
    if (registered.clients == clients) {
        LOG_ALWAYS_FATAL("Process already thought ...");
    }
    registered.clients = clients;
    updateCacheClientCount();
    maybeTryShutdownLocked();
    return Status::ok();
}

回调按 Binder 对象查本地服务,不按名字查;重复收到相同布尔状态会 fatal,因为它违反了双方状态同步假设。mNumConnectedServices 是“有客户端的服务数量”,不是客户端总数。

3.2 引用计数 ​

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

相关函数:handleServiceClientCallback()

ServiceManager 读取 Binder node strong ref 数量,扣除已知的 ServiceManager 和当前 transaction 引用;引用数变化后才向 callback 发送 onClients。驱动不支持该统计时,源码保守地认为“有客户端”,不会触发自动退出。

4. 退出策略 ​

4.1 forcePersist ​

源码文件:frameworks/native/libs/binder/LazyServiceRegistrar.cpp、frameworks/native/libs/binder/include/binder/LazyServiceRegistrar.h

cpp
void ClientCounterCallbackImpl::forcePersist(bool persist) {
    std::lock_guard<std::mutex> lock(mMutex);
    mForcePersist = persist;
    if (!mForcePersist) {
        maybeTryShutdownLocked();
    }
}

forcePersist=true 阻止无客户端自动退出;切回 false 会立即重新评估当前计数。它不是永久保活承诺,源码要求最终允许恢复动态关闭。

4.2 活跃回调 ​

cpp
if (mActiveServicesCallback != nullptr) {
    bool hasClients = mNumConnectedServices != 0;
    if (hasClients != mPreviousHasClients) {
        handledInCallback = mActiveServicesCallback(hasClients);
        mPreviousHasClients = hasClients;
    }
}

if (!handledInCallback && mNumConnectedServices == 0) {
    tryShutdownLocked();
}

应用层 callback 返回 true 时可以接管关闭决策;返回 false 或没有 callback 时,零活跃服务进入注销和退出路径。

4.3 注销与恢复 ​

cpp
void ClientCounterCallbackImpl::tryShutdownLocked() {
    if (tryUnregisterLocked()) {
        exit(EXIT_SUCCESS);
    }
    reRegisterLocked();
}

tryUnregisterLocked() 对所有已登记服务调用 tryUnregisterService(),成功项标记 registered=false。任一注销失败时,reRegisterLocked() 重新注册已注销项;重新注册失败是 fatal,因为继续运行却不恢复服务名会破坏后续客户端获取。

5. 边界与测试 ​

5.1 多服务进程 ​

mNumConnectedServices 由所有 mRegisteredServices 的 clients 标志重新计算。一个服务无客户端不代表进程可以退出;只有全部注册服务都为 false,且没有 forcePersist 或 active callback 接管,才进入关闭。

5.2 注册失败 ​

addService() 成功而 registerClientCallback() 失败时,registerServiceLocked() 返回 false;源码没有在这个分支自动撤销刚写入的服务,调用方必须把 UNKNOWN_ERROR 作为启动失败处理,不能假定服务已具备 lazy 生命周期。

5.3 可执行阅读 ​

bash
rg -n "FLAG_IS_LAZY_SERVICE|registerClientCallback|onClients|tryUnregister|reRegister|forcePersist" \
  frameworks/native/libs/binder/LazyServiceRegistrar.cpp \
  frameworks/native/libs/binder/include/binder/LazyServiceRegistrar.h \
  frameworks/native/cmds/servicemanager/ServiceManager.cpp

rg -n "handleServiceClientCallback|getNodeStrongRefCount|mNumConnectedServices" \
  frameworks/native/cmds/servicemanager/ServiceManager.cpp \
  frameworks/native/libs/binder/LazyServiceRegistrar.cpp

读完后应能解释:lazy 位由谁设置、client 数由谁观察、何时调用 tryUnregisterService()、为什么注销失败要重新注册,以及一个进程内多个服务为何共享退出决定。本文固定源码范围没有把这些路径外推为所有 vendor init 配置的自动行为。