Skip to content

ServiceManager.addService

追踪 Java addService、IServiceManager、servicemanager 校验、名称表写入、死亡通知和失败返回。

基于android-17.0.0_r1
AndroidSystemServerServiceManagerBinder源码阅读

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

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

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

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 ​

cpp
#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. 死亡与覆盖 ​

cpp
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. 名称表写入与通知 ​

cpp
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

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。
bash
# 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() 并保存生命周期列表;不会重复本文的跨进程名称表校验。