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()
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()
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 首次注册
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()
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
void ClientCounterCallbackImpl::forcePersist(bool persist) {
std::lock_guard<std::mutex> lock(mMutex);
mForcePersist = persist;
if (!mForcePersist) {
maybeTryShutdownLocked();
}
}forcePersist=true 阻止无客户端自动退出;切回 false 会立即重新评估当前计数。它不是永久保活承诺,源码要求最终允许恢复动态关闭。
4.2 活跃回调
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 注销与恢复
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 可执行阅读
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 配置的自动行为。
