Skip to content

getService查询服务

追踪 getService 从 Java 代理、ServiceManager 服务表和权限检查到 lazy service 启动、客户端状态回调与返回 metadata。

基于android-17.0.0_r1
AndroidBinderServiceManagergetService源码阅读

getService查询服务 ​

getService() 的结果不是简单的“按名字从 map 取 Binder”。Android 17 的 ServiceManager 会先区分 legacy getService 与 getService2,再根据调用者身份检查 isolated 访问和 SELinux find 权限;服务不存在且调用方允许启动时,还会异步请求 init 启动 lazy AIDL 服务。服务存在时,查询过程还会更新 client callback 状态,并把 isLazyService metadata 一起返回给 native backend。

本文面向已经读过 addService注册服务、SM成为context_manager 和 Binder事务发送 的读者。本文回答一个具体问题:一次查询从 Java ServiceManager.getService() 如何到达 ServiceManager::tryGetBinder(),服务表、权限、lazy 启动和缓存分别由谁拥有、何时生效。本文不展开 waitForService() 的阻塞重试协议,也不把 Java sCache 与 native backend cache 当作同一个缓存。

1. 入口分层 ​

1.1 Java查询 ​

源码文件:frameworks/base/core/java/android/os/ServiceManager.java

相关函数:getService()、rawGetService()

java
public static IBinder getService(String name) {
    try {
        IBinder service = sCache.get(name);
        if (service != null) {
            return service;
        } else {
            return Binder.allowBlocking(rawGetService(name));
        }
    } catch (RemoteException e) {
        Log.e(TAG, "error in getService", e);
    }
    return null;
}

private static IBinder rawGetService(String name) throws RemoteException {
    final IBinder binder = getIServiceManager().getService2(name)
            .getServiceWithMetadata().service;
    return binder;
}

Java 层先查 sCache,命中时不会进入 Binder;未命中才调用 rawGetService()。因此“ServiceManager 服务表中已有服务”并不等于每个 Java 调用都会穿过 ServiceManager 进程。RemoteException 或返回的空 Binder 最终都表现为 null,调用者需要结合日志和后端状态进一步区分原因。

1.2 AIDL代理 ​

源码文件:frameworks/base/core/java/android/os/ServiceManagerNative.java

相关类型:ServiceManagerProxy

java
public IBinder getService(String name) throws RemoteException {
    return checkService2(name).getServiceWithMetadata().service;
}

public Service getService2(String name) throws RemoteException {
    return checkService2(name);
}

public Service checkService2(String name) throws RemoteException {
    return mServiceManager.checkService2(name);
}

Android 17 的旧 getService() 代理最终调用 checkService2();真正决定是否尝试 lazy 启动的是服务端方法是否使用 startIfNotFound=true。Java 代理的命名不能直接当作服务端语义:服务端 legacy getService() 与 getService2() 都走 tryGetService(name, true),而 checkService2() 走 false。

1.3 Native缓存 ​

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

相关函数:getService2()、checkService2()

cpp
Status BackendUnifiedServiceManager::getService2(
        const std::string& name, os::Service* out) {
    if (returnIfCached(name, out)) {
        return Status::ok();
    }

    os::Service service;
    Status status = Status::ok();
    if (mTheRealServiceManager) {
        status = mTheRealServiceManager->getService2(name, &service);
    }
    if (status.isOk()) {
        status = toBinderService(name, service, out);
        if (status.isOk()) {
            return updateCache(name, service);
        }
    }
    return status;
}

BackendUnifiedServiceManager 的 cache 位于 native backend,命中后直接返回;未命中才调用真实 ServiceManager。checkService2() 也有相同的 cache 入口,但服务端使用的 startIfNotFound 不同。native cache 的更新发生在结果转换成功之后,不能把 cache 命中误解成服务端再次执行权限检查。

2. 服务端分叉 ​

2.1 Legacy接口 ​

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

相关函数:getService()、getService2()、checkService()、checkService2()

cpp
Status ServiceManager::getService(const std::string& name,
                                   sp<IBinder>* outBinder) {
    *outBinder = tryGetBinder(name, true).service;
    return Status::ok();
}

Status ServiceManager::getService2(const std::string& name,
                                    os::Service* outService) {
    *outService = tryGetService(name, true);
    return Status::ok();
}

Status ServiceManager::checkService2(const std::string& name,
                                      os::Service* outService) {
    *outService = tryGetService(name, false);
    return Status::ok();
}

四个接口最终都返回 Status::ok(),即使服务不存在或权限导致结果为空;查询结果放在输出参数或 os::Service 变体中。这是 legacy 兼容语义,不能用 Binder Status 是否为 ok 判断服务是否找到。真正的结果要看输出 Binder、service tag 和 metadata。

2.2 Accessor分支 ​

cpp
os::Service ServiceManager::tryGetService(const std::string& name,
                                           bool startIfNotFound) {
    std::optional<std::string> accessorName;
#ifndef VENDORSERVICEMANAGER
    accessorName = getVintfAccessorName(name);
#endif
    if (accessorName.has_value()) {
        auto ctx = mAccess->getCallingContext();
        if (!mAccess->canFind(ctx, name)) {
            return os::Service::make<os::Service::Tag::accessor>(nullptr);
        }
        return os::Service::make<os::Service::Tag::accessor>(
                tryGetBinder(*accessorName, startIfNotFound).service);
    }
    return os::Service::make<os::Service::Tag::serviceWithMetadata>(
            tryGetBinder(name, startIfNotFound));
}

VINTF 声明的服务可能通过 accessor 变体返回,而不是直接返回普通 serviceWithMetadata。调用者先对原始名字做 find 权限检查,再查询 accessor 名字;VENDORSERVICEMANAGER 构建条件会跳过 accessor 解析。这个 tag 差异是 native backend 需要调用 toBinderService() 转换的原因之一。

3. 查询状态 ​

3.1 表查找 ​

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

相关函数:tryGetBinder()

cpp
auto ctx = mAccess->getCallingContext();

sp<IBinder> out;
Service* service = nullptr;
if (auto it = mNameToService.find(name);
        it != mNameToService.end()) {
    service = &(it->second);

    if (!service->allowIsolated &&
            is_multiuser_uid_isolated(ctx.uid)) {
        LOG(WARNING) << "Isolated app requested '" << name << "'";
        return os::ServiceWithMetadata();
    }
    out = service->binder;
}

表查找先得到 Service*,再检查 isolated UID 是否被该服务允许。服务存在但 isolated caller 不被允许时,函数立即返回空结果,后面的 canFind() 和 lazy 启动都不会执行。这个顺序意味着“服务名存在”不是“当前调用者可获得 Binder”。

3.2 SELinux查找 ​

cpp
if (!mAccess->canFind(ctx, name)) {
    return os::ServiceWithMetadata();
}

if (!out && startIfNotFound) {
    tryStartService(ctx, name);
}

服务不存在时仍必须先通过 find 权限检查,只有权限通过且 startIfNotFound 为 true 才会请求 lazy 启动。权限失败返回空对象,不会因为服务缺失而启动一个调用者无权访问的服务。

3.3 Client状态 ​

cpp
if (out) {
    service->guaranteeClient = true;
    CHECK(handleServiceClientCallback(
            2 /* sm + transaction */, name, false));
    service->guaranteeClient = true;
}

os::ServiceWithMetadata serviceWithMetadata;
serviceWithMetadata.service = out;
serviceWithMetadata.isLazyService = service
        ? service->dumpPriority & FLAG_IS_LAZY_SERVICE
        : false;
return serviceWithMetadata;

成功查询会把 ServiceManager 自己和当前 Binder transaction 计入已知 client 数量,并重新设置 guaranteeClient,避免定时器过早清除状态。最后根据注册时的 dumpPriority 返回 isLazyService metadata;这个位和 dump 显示优先级共享整数参数,但服务端把它解释为 lazy 标志。

4. Lazy启动 ​

4.1 属性请求 ​

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

相关函数:tryStartService()

cpp
void ServiceManager::tryStartService(
        const Access::CallingContext& ctx,
        const std::string& name) {
    std::thread([=] {
        if (!base::SetProperty(
                "ctl.interface_start", "aidl/" + name)) {
            ALOGI("Tried to start aidl service %s, but was unable to.",
                  name.c_str());
        }
    }).detach();
}

启动请求在 detached thread 中执行,并通过 ctl.interface_start 交给 init;查询线程不会同步等待服务变为可用。因此 getService() 对未找到服务的返回仍可能是空,即使 init 随后成功拉起服务。只有专门的等待接口才承担“启动后等待 ready”的语义。

4.2 两种查询 ​

调用startIfNotFound缺失时动作典型结果
getService / getService2true异步请求 lazy AIDL 启动当前调用仍可能得到空
checkService / checkService2false不启动直接得到空
waitForService独立 native 路径启动并等待见等待专题

5. 失败边界 ​

5.1 结果分类 ​

现象源码位置是否触发 lazy 启动
Java sCache 命中ServiceManager.getService()否
服务存在且允许访问tryGetBinder()否
isolated caller 不被允许tryGetBinder()否
SELinux find 拒绝tryGetBinder()否
服务不存在,getServicetryGetBinder()是,异步
服务不存在,checkServicetryGetBinder()否
backend 无真实 managerBackendUnifiedServiceManager由 backend 返回错误

5.2 取消与恢复 ​

查询本身没有可取消的等待状态:getService() 只是一次调用,lazy 启动请求在 detached thread 中提交后不由这次 Binder 调用持有。恢复路径由后续查询或 waitForService() 重新观察服务表;服务进程注册成功后,addService() 会写入表并触发注册回调。若服务进程死亡,前文所述 binderDied() 删除表项,下一次允许启动的查询又可能重新请求 lazy 服务。

6. 源码测试 ​

6.1 服务端测试 ​

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

GetService.HappyHappy 先注册 Binder,再调用 getService2() 与 legacy getService(),断言返回的是同一个 Binder;GetService.NonExistent 断言不存在服务返回空;GetService.IsolatedNotAllowed 使用 isolated UID 且服务不允许 isolated,断言结果为空。这些测试覆盖表查找、返回对象和 isolated 分支,但不直接断言真实 init 属性启动。

6.2 Fake缓存测试 ​

源码文件:frameworks/native/libs/fakeservicemanager/test_sm.cpp

SetupFakeServiceManager.GetExistingService 验证 fake manager 注册后查询得到同一 Binder;ClearFakeServiceManager.GetServiceAfterClear 注册后清空 fake manager,再断言查询为空。它们证明客户端接口可以观察到“写入/清理”状态,不证明真实 ServiceManager 的 SELinux、VINTF、lazy 属性或死亡通知。

6.3 可执行阅读 ​

bash
rg -n "getService\(|rawGetService|sCache|checkService2" \
  frameworks/base/core/java/android/os/ServiceManager.java \
  frameworks/base/core/java/android/os/ServiceManagerNative.java

rg -n "getService2|checkService2|returnIfCached|updateCache" \
  frameworks/native/libs/binder/BackendUnifiedServiceManager.cpp

rg -n "tryGetService|tryGetBinder|startIfNotFound|tryStartService|canFind|guaranteeClient" \
  frameworks/native/cmds/servicemanager/ServiceManager.cpp

rg -n "GetService|IsolatedNotAllowed|ClearFakeServiceManager" \
  frameworks/native/cmds/servicemanager/test_sm.cpp \
  frameworks/native/libs/fakeservicemanager/test_sm.cpp

当 getService() 返回空时,先问四个问题:Java cache 是否命中、服务表是否有名字、调用者是否通过 isolated/SELinux 检查、这次查询是否允许 lazy 启动。只有沿这四个分叉定位,才能把“服务不存在”“无权限”“启动尚未完成”和“缓存/后端问题”区分开。