ServiceManager.addService
系统服务注册不是一次 Java 静态方法调用。调用方把一个 IBinder 和名称交给 Java ServiceManager,它通过 context manager Binder 获取 IServiceManager,native shim 再转到 AIDL unified backend,最后由独立 servicemanager 进程执行 caller、名称、VINTF、dump priority 和死亡通知校验,成功后写入 mNameToService。
1. Java入口
源码文件:frameworks/base/core/java/android/os/ServiceManager.java
public static void addService(String name, IBinder service,
boolean allowIsolated, int dumpPriority) {
try {
getIServiceManager().addService(
name, service, allowIsolated, dumpPriority);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) return sServiceManager;
sServiceManager = ServiceManagerNative.asInterface(
Binder.allowBlocking(
BinderInternal.getContextObject()));
return sServiceManager;
}Java 层缓存 sServiceManager 代理;首次注册通过 handle 0 的 context object 获取 servicemanager。addService() 捕获 RemoteException 后只记录日志并返回 void,因此 Java 调用方不能仅凭“方法返回”判断注册成功,必须通过查询或服务端日志确认名称表状态。
2. Native shim
源码文件:frameworks/native/libs/binder/IServiceManager.cpp
status_t CppBackendShim::addService(
const String16& name,
const sp<IBinder>& service,
bool allowIsolated,
int dumpsysPriority) {
Status status = mUnifiedServiceManager->addService(
String8(name).c_str(), service,
allowIsolated, dumpsysPriority);
return status.exceptionCode();
}shim 负责字符串编码、AIDL Status 到 legacy status_t 的转换;服务对象仍由 sp<IBinder> 持有。真正的权限和名称检查不在这里完成,mUnifiedServiceManager 的远端实现才是注册 owner。
3. 服务端前置校验
源码文件:frameworks/native/cmds/servicemanager/ServiceManager.cpp
auto ctx = mAccess->getCallingContext();
if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
return Status::fromExceptionCode(
Status::EX_SECURITY,
"App UIDs cannot add services.");
}
if (auto status = canAddService(
ctx, name, &accessorName); !status.isOk()) {
return status;
}
if (binder == nullptr) {
return Status::fromExceptionCode(
Status::EX_ILLEGAL_ARGUMENT, "Null binder.");
}
if (!isValidServiceName(name)) {
return Status::fromExceptionCode(
Status::EX_ILLEGAL_ARGUMENT,
"Invalid service name.");
}servicemanager 从 Binder calling context 得到 UID/SID/PID,再拒绝普通应用 UID 注册服务。随后 canAddService() 处理服务名对应的 SELinux/add 权限;空 Binder 和非法字符名称分别是参数错误。校验顺序决定失败 owner:这些失败发生在名称表写入前,不会产生服务项。
4. VINTF与dump
#ifndef VENDORSERVICEMANAGER
if (!meetsDeclarationRequirements(ctx, binder, name)) {
return Status::fromExceptionCode(
Status::EX_ILLEGAL_ARGUMENT,
"VINTF declaration error.");
}
#endif
if ((dumpPriority & DUMP_FLAG_PRIORITY_ALL) == 0) {
ALOGW("Dump flag priority is not set when adding %s",
name.c_str());
}非 vendor servicemanager 构建会检查稳定服务的 VINTF 声明;vendor 构建跳过该条件编译块。dump priority 没有有效位时只产生 warning,不阻止注册。不能把 warning 与 VINTF declaration error 当作同一失败等级。
5. 死亡与覆盖
if (binder->remoteBinder() != nullptr
&& binder->linkToDeath(
sp<ServiceManager>::fromExisting(this)) != OK) {
return Status::fromExceptionCode(
Status::EX_ILLEGAL_STATE,
"Couldn't linkToDeath.");
}
auto it = mNameToService.find(name);
bool prevClients = false;
if (it != mNameToService.end()) {
prevClients = it->second.hasClients;
// 同名覆盖会记录 UID/SID/PID 差异。
}远程 Binder 注册前先把 servicemanager 自身作为 DeathRecipient 链接到对象;服务进程死亡时,servicemanager 能按 Binder 身份删除表项。已有同名服务会被覆盖,但会比较旧、新注册者的 UID/SID/PID 并记录 warning;hasClients 状态被保留,避免注册回调观察到错误的客户端状态。
6. 名称表写入与通知
mNameToService[name] = Service{
.binder = binder,
.allowIsolated = allowIsolated,
.dumpPriority = dumpPriority,
.hasClients = prevClients,
.guaranteeClient = false,
.ctx = ctx,
};
if (auto it = mNameToRegistrationCallback.find(name);
it != mNameToRegistrationCallback.end()) {
mNameToService[name].guaranteeClient = true;
CHECK(handleServiceClientCallback(
2 /* sm + transaction */, name, false));
dispatchRegistrationCallbacks(
name, binder, allowIsolated,
/*callbacks=*/it->second);
}
return Status::ok();写入后,名称成为 servicemanager 的 owner,Binder 对象和注册上下文一起保存。若已有 registerForNotifications 等待者,先更新 client callback 状态,再派发注册通知;这保证等待者观察到的 Binder 与名称表一致。通知失败会通过 CHECK 暴露为服务端致命状态,不能当作普通空返回。
7. 死亡清理
源码文件:frameworks/native/cmds/servicemanager/ServiceManager.cpp
void ServiceManager::binderDied(const wp<IBinder>& who) {
for (auto it = mNameToService.begin();
it != mNameToService.end();) {
if (who == it->second.binder) {
it = mNameToService.erase(it);
} else {
++it;
}
}
for (auto it = mNameToRegistrationCallback.begin();
it != mNameToRegistrationCallback.end();) {
removeRegistrationCallback(who, &it, nullptr);
}
for (auto it = mNameToClientCallback.begin();
it != mNameToClientCallback.end();) {
removeClientCallback(who, &it);
}
}死亡回调按 Binder 对象匹配并删除服务表、注册回调和客户端回调。清理后同名服务不会自动指向新对象,必须由新的服务进程重新调用 addService();客户端下一次查询才会看到新 Binder。
8. 失败定位
- Java 返回正常但查询为空:检查 RemoteException 日志、服务端校验和名称表;
EX_SECURITY:检查 caller UID、canAddService()和 SELinux add 权限;EX_ILLEGAL_ARGUMENT:检查空 Binder、名称格式和 VINTF 声明;- 注册成功后查询失效:检查 DeathRecipient、服务进程退出和重新注册;
- 同名服务异常替换:比较 servicemanager 记录的 UID/SID/PID。
# Java/native 调用入口与状态转换。
rg -n "addService\(|getIServiceManager|CppBackendShim::addService" \
frameworks/base/core/java/android/os/ServiceManager.java \
frameworks/native/libs/binder/IServiceManager.cpp
# servicemanager 校验、名称表、死亡清理和通知。
rg -n "ServiceManager::addService|canAddService|isValidServiceName|meetsDeclarationRequirements|linkToDeath|mNameToService|binderDied|dispatchRegistrationCallbacks" \
frameworks/native/cmds/servicemanager/ServiceManager.cpp下一篇将分析 SystemServiceManager.startService() 如何实例化 Java SystemService、去重、调用 onStart() 并保存生命周期列表;不会重复本文的跨进程名称表校验。
