Skip to content

Service Contexts

从 service_contexts 分区构建和 Context lookup,追踪到 servicemanager 的 add/find/list 校验、lazy AIDL 服务、VINTF accessor 与死亡清理。

基于android-17.0.0_r1
AndroidSELinuxservice_contextsservicemanagerBinder源码阅读

Service Contexts ​

本文面向已经读过 安全上下文、TE规则语法、File Contexts、Property Contexts 和 Binder 系列基础文章的读者。前文说明路径、属性名如何映射到 Context;本篇聚焦系统 Binder 的名字空间:service_contexts 如何把 activity、android.hardware.power.IPower/default 这样的服务名映射到 service_manager 对象类的 target Context,servicemanager 如何据此检查 add/find/list,服务表何时更新,以及 lazy service、VINTF accessor 和死亡回调如何改变结束路径。

本文不讨论 hwservice_contexts 或 vndservice_contexts 的完整实现,它们分别属于后续专题。也不把 service_manager add/find 和服务对象真正执行 Binder transaction 的 binder call 混为一谈:前者由 servicemanager 使用 service_contexts 授权名字空间操作,后者由 Binder 驱动和目标进程的 process/domain policy 消费。读完后,读者应能从一个服务名追到文本条目、分区 module、selabel_lookup()、Access::actionAllowed()、ServiceManager 的状态表和错误返回,并能定位“服务未注册”“注册被拒绝”“查找被拒绝”“找到服务但调用被拒绝”四种不同故障。

1. 名字与对象 ​

1.1 服务名 ​

service_contexts 的 key 是 servicemanager 接口使用的字符串。Framework 服务通常使用短名;AIDL/HAL 服务使用接口全名加实例名。两者在 lookup 层没有不同的安全机制,都会作为同一个 service_manager backend 的 key。

源码文件:system/sepolicy/private/service_contexts

text
activity                                  u:object_r:activity_service:s0
window                                    u:object_r:window_service:s0
android.hardware.power.IPower/default     u:object_r:hal_power_service:s0
android.hardware.camera.provider.ICameraProvider/internal/0 \
                                           u:object_r:hal_camera_service:s0
*                                         u:object_r:default_android_service:s0

最后的 * 是服务 backend 的默认 Context;它不自动给予任何域 add 或 find 权限。target type 仍必须在 policy 中具有 service_manager_type attribute,调用者还必须满足相应 access vector。

1.2 三种权限 ​

servicemanager 对名字空间暴露三种与本篇直接相关的权限:

权限消费者作用
addServiceManager::addService()将 binder 对象写入名字到服务的表
findgetService()、checkService()、通知/连接信息查询读取名字对应的 binder 对象或请求 lazy 启动
listlistServices()、debug info列出服务名或服务调试信息

这三个权限的 target object class 都是 service_manager,target Context 来自 service_contexts。获得 binder 引用之后,客户端再发起 transaction 时还会经过 binder 类的 call 检查;service_contexts 不替代该检查。

1.3 Service表 ​

ServiceManager 的 owner 是 mNameToService,键是服务名,值保存 binder、allowIsolated、dump priority、client 状态和注册者 CallingContext。注册回调和 client 回调分别保存在两个 map 中。

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

cpp
using ServiceCallbackMap =
        std::map<std::string, std::vector<RegistrationCallback>>;
using ClientCallbackMap =
        std::map<std::string, std::vector<sp<IClientCallback>>>;
using ServiceMap = std::map<std::string, Service>;

ServiceMap mNameToService;
ServiceCallbackMap mNameToRegistrationCallback;
ClientCallbackMap mNameToClientCallback;
std::unique_ptr<Access> mAccess;

2. 文本条目 ​

2.1 平台服务 ​

Android 17 平台文件包含大量 framework 服务名和 AIDL 服务名。下面只取能说明命名层级的条目,不是服务清单。

源码文件:system/sepolicy/private/service_contexts

text
android.frameworks.stats.IStats/default       u:object_r:fwk_stats_service:s0
android.frameworks.sensorservice.ISensorManager/default \
                                                 u:object_r:fwk_sensor_service:s0
android.system.keystore2.IKeystoreService/default \
                                                 u:object_r:keystore_service:s0
android.system.net.netd.INetd/default          u:object_r:system_net_netd_service:s0
android.os.UpdateEngineService                 u:object_r:update_engine_service:s0
android.security.keystore                      u:object_r:keystore_service:s0

服务名是否带 /instance 是接口注册约定;SELinux 只按最终字符串查找 Context。相同 target type 可以被多个服务名共享,但每个调用者仍需要对该 target type 的 add 或 find 权限。

2.2 条件条目 ​

Contexts 文件经过 M4,因此 release flag 可以控制条目是否进入当前输出。条件没有满足时,源码中存在的名字不会出现在产物中。

源码文件:system/sepolicy/private/service_contexts

text
is_flag_enabled(RELEASE_HARDWARE_BLUETOOTH_RANGING_SERVICE, `
    android.hardware.bluetooth.ranging.IBluetoothChannelSounding/default \
        u:object_r:hal_bluetooth_service:s0
')

is_flag_enabled(RELEASE_AISEAL_FRAMEWORK, `
    aiseal_host u:object_r:aiseal_host_service:s0
    aiseal_internal u:object_r:aiseal_internal_service:s0
')

2.3 默认Context ​

平台文件通常用 * 提供 default Android service Context。lookup 是否使用它由 selabel backend 决定;如果 backend 没有 handle,servicemanager 不会用任意字符串继续完成 MAC 检查。

源码文件:system/sepolicy/private/service_contexts

text
*                                         u:object_r:default_android_service:s0

3. 分区构建 ​

3.1 输入Module ​

Soong 为 platform、system_ext、product、vendor 和 odm 分别注册 service_contexts module。分区属性决定输入 filegroup 和安装变体;运行时 system/vendor ServiceManager 再选择对应 handle。

源码文件:system/sepolicy/contexts/Android.bp

make
service_contexts {
    name: "plat_service_contexts",
    defaults: ["contexts_flags_defaults"],
    srcs: [":service_contexts_files{.plat_private}"],
}

service_contexts {
    name: "system_ext_service_contexts",
    defaults: ["contexts_flags_defaults"],
    srcs: [":service_contexts_files{.system_ext_private}"],
    system_ext_specific: true,
}

service_contexts {
    name: "vendor_service_contexts",
    defaults: ["contexts_flags_defaults"],
    srcs: [
        ":service_contexts_files{.plat_vendor}",
        ":service_contexts_files{.vendor}",
        ":service_contexts_files{.reqd_mask}",
    ],
    soc_specific: true,
}

3.2 通用生成 ​

service_contexts 使用 buildServiceContexts(),默认把 Remove_comment 设为 true,再复用 buildGeneralContexts() 的 newline、M4、release flag 和注释清理。service contexts 不使用 file contexts 的 fc_sort 分支。

源码文件:system/sepolicy/build/soong/selinux_contexts.go

go
func (m *selinuxContextsModule) buildServiceContexts(
        ctx android.ModuleContext, inputs android.Paths) android.Path {
    if m.properties.Remove_comment == nil {
        m.properties.Remove_comment = proptools.BoolPtr(true)
    }
    return m.buildGeneralContexts(ctx, inputs)
}

func serviceFactory() android.Module {
    m := newModule()
    m.build = m.buildServiceContexts
    return m
}

3.3 测试Module ​

service contexts 测试使用 checkfc -s,而不是 file contexts 的默认 backend。-s 表示 binder service backend;测试加载编译 policy,验证 target type 属于 service_manager_type。

源码文件:system/sepolicy/build/soong/selinux_contexts.go

go
case ServiceContext:
    flags = []string{"-s" /* binder services */}
case HwServiceContext:
    flags = []string{"-e" /* allow empty */, "-l" /* hwbinder services */}
case VndServiceContext:
    flags = []string{"-e" /* allow empty */, "-v" /* vnd service */}

4. Libselinux加载 ​

4.1 路径选择 ​

libselinux 为 service contexts 定义正式路径。Android 17 的实现按分区选择存在的文件,再交给 Android service label backend;vendor ServiceManager 使用 vendor 变体。

源码文件:external/selinux/libselinux/src/android/android.c

c
static const path_alts_t service_context_paths = { .paths = {
    { "/system/etc/selinux/plat_service_contexts", "/plat_service_contexts" },
    { "/system_ext/etc/selinux/system_ext_service_contexts", "/system_ext_service_contexts" },
    { "/product/etc/selinux/product_service_contexts", "/product_service_contexts" },
    { "/vendor/etc/selinux/vendor_service_contexts", "/vendor_service_contexts" },
    { "/odm/etc/selinux/odm_service_contexts", "/odm_service_contexts" },
}};

4.2 Handle缓存 ​

Access 缓存一个 selabel_handle。SELinux 状态更新后,旧 handle 被关闭,下一次操作重新打开;服务表中的已有 binder 不会因为 handle 刷新而自动重注册。

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

cpp
static struct selabel_handle* getSehandle() {
    static struct selabel_handle* gSehandle = nullptr;
    if (gSehandle != nullptr && selinux_status_updated()) {
        selabel_close(gSehandle);
        gSehandle = nullptr;
    }

    if (gSehandle == nullptr) {
        gSehandle = kIsVendor
            ? selinux_android_vendor_service_context_handle()
            : selinux_android_service_context_handle();
    }

    CHECK(gSehandle != nullptr);
    return gSehandle;
}

4.3 Lookup失败 ​

服务名 lookup 失败时,Access 记录 No match for ... in service_contexts 并返回 false;它不会把未匹配的名字当作允许。

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

cpp
bool Access::actionAllowedFromLookup(const CallingContext& sctx,
                                     const std::string& name,
                                     const char* perm) {
    char* tctx = nullptr;
    if (selabel_lookup(getSehandle(), &tctx, name.c_str(),
                       SELABEL_CTX_ANDROID_SERVICE) != 0) {
        LOG(ERROR) << "SELinux: No match for " << name
                   << " in service_contexts.\n";
        return false;
    }

    bool allowed = actionAllowed(sctx, tctx, perm, name);
    freecon(tctx);
    return allowed;
}

5. Access判定 ​

5.1 Caller Context ​

source SID 来自 Binder 调用者,优先从 IPCThreadState 读取;target Context 来自服务名 lookup。这两个来源在代码中分别由 getCallingContext() 和 selabel_lookup() 表达。

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

cpp
Access::CallingContext Access::getCallingContext() {
    IPCThreadState* ipc = IPCThreadState::self();
    const char* callingSid = ipc->getCallingSid();
    pid_t callingPid = ipc->getCallingPid();

    return CallingContext{
        .debugPid = callingPid,
        .uid = ipc->getCallingUid(),
        .sid = callingSid ? std::string(callingSid)
                          : getPidcon(callingPid),
    };
}

5.2 MAC调用 ​

actionAllowed() 固定使用 service_manager class,把 add、find 或 list 作为 permission 传入 selinux_check_access()。

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

cpp
bool Access::actionAllowed(const CallingContext& sctx,
                           const char* tctx,
                           const char* perm,
                           const std::string& tname) {
#ifdef __ANDROID__
    const char* tclass = "service_manager";
    AuditCallbackData data{.context = &sctx, .tname = &tname};
    return 0 == selinux_check_access(
            sctx.sid.c_str(), tctx, tclass, perm,
            reinterpret_cast<void*>(&data));
#else
    return true;
#endif
}

5.3 三个入口 ​

canAdd()、canFind() 都按服务名 lookup;canList() 使用 servicemanager 自身 Context 作为 target,因此 list 不是逐服务 find。

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

cpp
bool Access::canFind(const CallingContext& ctx,
                     const std::string& name) {
    return actionAllowedFromLookup(ctx, name, "find");
}

bool Access::canAdd(const CallingContext& ctx,
                    const std::string& name) {
    return actionAllowedFromLookup(ctx, name, "add");
}

bool Access::canList(const CallingContext& ctx) {
    return actionAllowed(ctx, mThisProcessContext,
                         "list", "service_manager");
}

5.4 Target属性 ​

服务 Context 的 type 必须拥有 service_manager_type attribute;API attribute 决定 app domain 的可见范围。

源码文件:system/sepolicy/public/service.te

text
type activity_service, app_api_service, ephemeral_app_api_service,
    system_server_service, service_manager_type;
type window_service, system_api_service,
    system_server_service, service_manager_type;
type hal_power_service, protected_service,
    hal_service_type, service_manager_type;

源码文件:system/sepolicy/private/service.te

text
neverallow domain ~{ service_manager_type vndservice_manager_type }:
    service_manager { add find };

6. 注册路径 ​

6.1 UID检查 ​

普通 App UID 在进入 SELinux canAddService() 前就被 ServiceManager 拒绝。

源码文件: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.");
}

6.2 权限与名称 ​

通过 canAddService() 后,ServiceManager 仍检查 binder 非空和名称合法性;名称允许 /,所以 AIDL instance 名可以保留接口/实例结构。

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

cpp
if (binder == nullptr) {
    return Status::fromExceptionCode(
            Status::EX_ILLEGAL_ARGUMENT, "Null binder.");
}

if (!isValidServiceName(name)) {
    ALOGE("%s Invalid service name: %s",
          ctx.toDebugString().c_str(), name.c_str());
    return Status::fromExceptionCode(
            Status::EX_ILLEGAL_ARGUMENT, "Invalid service name.");
}

6.3 表项提交 ​

注册成功后把 binder、allowIsolated、dump priority 和 server Context 写入名字表。同名注册覆盖旧表项并保留 client 状态。

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

cpp
auto it = mNameToService.find(name);
bool prevClients = false;
if (it != mNameToService.end()) {
    const Service& existing = it->second;
    prevClients = existing.hasClients;
    if (existing.ctx.sid != ctx.sid) {
        ALOGW("Service '%s' originally registered from SID %s "
              "but it is now being registered from SID %s.",
              name.c_str(), existing.ctx.sid.c_str(), ctx.sid.c_str());
    }
}

mNameToService[name] = Service{
    .binder = binder,
    .allowIsolated = allowIsolated,
    .dumpPriority = dumpPriority,
    .hasClients = prevClients,
    .guaranteeClient = false,
    .ctx = ctx,
};

6.4 死亡清理 ​

远程 binder 在写表前 linkToDeath;死亡回调删除服务表和关联 callback。清理后名字仍可由新 server 重新 add。

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

cpp
if (binder->remoteBinder() != nullptr &&
    binder->linkToDeath(
        sp<ServiceManager>::fromExisting(this)) != OK) {
    return Status::fromExceptionCode(
            Status::EX_ILLEGAL_STATE, "Couldn't linkToDeath.");
}

7. 查找路径 ​

7.1 get与check ​

getService() 允许启动 lazy service,checkService() 不启动;两者的 Binder 状态通过输出参数表达,Status 出于历史兼容可能仍为 ok。

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

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

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

7.2 Isolated状态 ​

allowIsolated 是注册者写入的 Service 状态,不是 SELinux target attribute。isolated caller 即使拥有 find,也可能被该字段返回空。

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

cpp
if (!service->allowIsolated &&
    is_multiuser_uid_isolated(ctx.uid)) {
    LOG(WARNING) << "Isolated app with UID " << ctx.uid
                 << " requested '" << name
                 << "', but the service is not allowed for isolated apps.";
    return os::ServiceWithMetadata();
}

7.3 Find与Lazy ​

服务表有无 binder 不决定权限;canFind() 先决定 caller 是否可以观察该名字。只有 find 通过且 getService() 发现 binder 缺失时,才异步设置 ctl.interface_start。

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

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

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

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

cpp
std::thread([=] {
    if (!base::SetProperty("ctl.interface_start",
                           "aidl/" + name)) {
        ALOGI("Tried to start aidl service %s as a lazy service, "
              "but was unable to.", name.c_str());
    }
}).detach();

7.4 Accessor ​

平台 ServiceManager 对 VINTF accessor 服务先检查原名 find,再查 accessor binder;vendor 构建排除此路径。

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

cpp
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);
}

8. 列举与通知 ​

8.1 List权限 ​

listServices() 只执行一次 canList(),然后按 dump priority 遍历表。具体服务的 find 不会自动授予 list。

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

cpp
Status ServiceManager::listServices(
        int32_t dumpPriority,
        std::vector<std::string>* outList) {
    if (!mAccess->canList(mAccess->getCallingContext())) {
        return Status::fromExceptionCode(
                Status::EX_SECURITY, "SELinux denied.");
    }

    for (auto const& [name, service] : mNameToService) {
        if (service.dumpPriority & dumpPriority) {
            outList->push_back(name);
        }
    }
    return Status::ok();
}

8.2 注册通知 ​

registerForNotifications() 需要 find 权限。callback 保存于 mNameToRegistrationCallback,服务后来 add 时才 dispatch;已存在服务则立即通知。

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

cpp
Status ServiceManager::registerForNotifications(
        const std::string& name,
        const sp<IServiceCallback>& callback) {
    auto ctx = mAccess->getCallingContext();
    std::optional<std::string> accessorName;
    if (auto status = canFindService(ctx, name, &accessorName);
        !status.isOk()) {
        return status;
    }

    mNameToRegistrationCallback[name].push_back(
            RegistrationCallback{.callback = callback, .ctx = ctx});
    return Status::ok();
}

8.3 Client回调 ​

client callback 只允许服务自身注册。ServiceManager 比较调用 PID 和表中 server PID,再比较 binder 对象,避免任意 find 客户端伪造服务 client 状态。

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

cpp
if (serviceIt->second.ctx.debugPid !=
    IPCThreadState::self()->getCallingPid()) {
    return Status::fromExceptionCode(
            Status::EX_UNSUPPORTED_OPERATION,
            "Only service can register client callback for itself.");
}

if (serviceIt->second.binder != service) {
    return Status::fromExceptionCode(
            Status::EX_ILLEGAL_ARGUMENT, "Service mismatch.");
}

9. 自注册与实例 ​

9.1 manager服务 ​

servicemanager 启动后把自身注册为 manager,再成为 Binder context manager。自注册同样经过 add 权限和 service contexts lookup。

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

cpp
sp<ServiceManager> manager =
        sp<ServiceManager>::make(std::make_unique<Access>());
manager->setRequestingSid(true);
if (!manager->addService(
        "manager", manager, false /*allowIsolated*/,
        IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
    LOG(ERROR) << "Could not self register servicemanager";
}

IPCThreadState::self()->setTheContextObject(manager);
if (!ps->becomeContextManager()) {
    LOG(FATAL) << "Could not become context manager";
}

9.2 Ready属性 ​

系统 servicemanager 完成 Binder polling 和自注册后设置 servicemanager.ready=true。这是 property service 事件,不是 service_contexts 的注册完成标志。

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

cpp
#ifndef VENDORSERVICEMANAGER
if (!SetProperty("servicemanager.ready", "true")) {
    LOG(ERROR) << "Failed to set servicemanager ready property";
}
#endif

9.3 Vendor实例 ​

vndservicemanager 复用 Access/ServiceManager,但定义 VENDORSERVICEMANAGER=1,通常使用 /dev/vndbinder,并选择 vendor service Context handle。

源码文件:frameworks/native/cmds/servicemanager/Android.bp

make
cc_binary {
    name: "vndservicemanager",
    defaults: ["servicemanager_defaults"],
    init_rc: ["vndservicemanager.rc"],
    vendor: true,
    cflags: ["-DVENDORSERVICEMANAGER=1"],
    required: ["vndservice"],
    srcs: ["main.cpp"],
}

10. Policy配套 ​

10.1 服务类型 ​

target type 必须带 service_manager_type。Framework type 还使用 app/system API 和 system server attribute 描述可见范围。

源码文件:system/sepolicy/public/service.te

text
type activity_service, app_api_service,
    ephemeral_app_api_service, system_server_service,
    service_manager_type;
type window_service, system_api_service,
    system_server_service, service_manager_type;
type hal_power_service, protected_service,
    hal_service_type, service_manager_type;

10.2 Add规则 ​

服务端需要对 target type 拥有 service_manager add。

源码文件:system/sepolicy/private/system_server.te

text
add_service(system_server, system_server_service);
allow system_server artd_service:service_manager find;
allow system_server audioserver_service:service_manager find;
allow system_server cameraserver_service:service_manager find;
allow system_server drmserver_service:service_manager find;
allow system_server fingerprintd_service:service_manager find;

add_service(system_server, system_server_service) 展开为 system_server 对该 target 的 add/find,并生成“其他 domain 不得 add”的 neverallow;system_server 对具体服务的许多操作则是 find 规则,因为这些服务由其他进程提供。

10.3 Find规则 ​

客户端 find 与 server add 独立。拥有 find 不意味着能 add,也不意味着可以调用接口。

源码文件:system/sepolicy/private/isolated_app_all.te

text
allow isolated_app_all activity_service:service_manager find;
allow isolated_app_all activity_structured_service:service_manager find;
allow isolated_app_all display_service:service_manager find;

10.4 Binder调用 ​

取得 binder 后,transaction 继续由 binder class 的 call/transfer 权限和接口业务权限控制。

源码文件:system/sepolicy/public/te_macros

text
define(`binder_call', `
  allow $1 $2:binder { call transfer };
  allow $2 $1:binder transfer;
')

11. 失败定位 ​

11.1 注册失败 ​

现象代码位置先检查
App UIDs cannot add servicesaddService()caller UID
SELinux denied for servicecanAddService()key、target type、add rule
No match in service_contextsAccess::actionAllowedFromLookup()flag、分区产物、名字
Invalid service nameisValidServiceName()长度和字符集
VINTF declaration errormeetsDeclarationRequirements()accessor/manifest
Couldn't linkToDeathaddService()remote binder 生命周期

11.2 查找失败 ​

查找为空时分别检查表项是否存在、isolated 是否不允许、find 是否被拒绝、lazy property 是否设置、服务是否最终重新注册。getService() 的 Status 可能为 ok,真正结果是输出 binder。

11.3 调用失败 ​

服务已 find 但 transaction 被拒绝,应检查目标服务进程 domain、Binder call/transfer policy 和接口 permission;修改 service_contexts 不会授予 call。

11.4 Handle刷新 ​

SELinux status 更新会触发 handle 重载。新 contexts 文件缺失或损坏可能使 CHECK(gSehandle != nullptr) 致命退出,区别于一次性的 access deny。

12. 测试与验证 ​

12.1 Checkfc断言 ​

service contexts 的静态测试选择 checkfc -s,使用 service_manager_type attribute。它只证明文本和 policy 的静态契约,不证明 caller 权限。

源码文件:system/sepolicy/tools/checkfc.c

c
static const char * const CHECK_SC_ASSERT_ATTRS[] = {
    "service_manager_type", NULL
};

case filemode_service_contexts:
    return CHECK_SC_ASSERT_ATTRS;

12.2 SM测试 ​

构建文件声明 host/device 测试,覆盖 ServiceManager 的状态、API、回调和死亡处理。

源码文件:frameworks/native/cmds/servicemanager/Android.bp

make
cc_test {
    name: "servicemanager_test",
    host_supported: true,
    test_suites: ["device-tests"],
    defaults: ["servicemanager_defaults"],
    srcs: ["test_sm.cpp"],
    static_libs: ["libgmock"],
}

cc_test_host {
    name: "servicemanager_unittest",
    test_suites: ["general-tests"],
    defaults: ["servicemanager_defaults"],
    srcs: ["ServiceManagerUnittest.cpp"],
    static_libs: ["libgmock"],
}

12.3 构建命令 ​

bash
# 初始化构建环境并选择实际产品。
source build/envsetup.sh
lunch PRODUCT-userdebug

# 构建 contexts、静态检查和 ServiceManager 测试。
m plat_service_contexts plat_service_contexts_test \
  vendor_service_contexts vendor_service_contexts_test \
  servicemanager_unittest servicemanager_test

构建成功表示当前输入能生成文本并通过静态规则;还需设备运行时证据。

12.4 设备命令 ​

bash
# 查看名字表;该命令自身需要 servicemanager:list。
adb shell service list | rg 'activity|window|power'

# 查看调用者 domain。
adb shell id -Z

# 查看服务进程 domain;它不是 service_contexts target type。
adb shell ps -AZ | rg 'system_server|servicemanager'

# 筛选名字空间拒绝与服务名。
adb shell dmesg | rg 'service_manager|activity|window|denied'

service list 只证明名字表可列举;ps -AZ 只证明进程 domain;transaction 失败仍需检查 Binder call 和接口权限。

12.5 复述任务 ​

给定 activity,应能复述:system_server 调用 add,Access 以 calling SID 为 source、从 service_contexts 取 activity_service 为 target,执行 service_manager:add;通过名称、binder 和死亡链接后写入表;App 查找时重新执行 target lookup 和 find,拿到引用后再经过 Binder call 和 ActivityManager 业务权限。服务死亡会删除表项,lazy 启动还要经过 ctl.interface_start,不能从一行 service_contexts 推断全部生命周期。

13. 源码导航 ​

问题首选源码关键符号
服务名映射system/sepolicy/private/service_contexts条目、flag、默认项
分区生成system/sepolicy/contexts/Android.bpplat/vendor/odm_service_contexts
M4与去注释system/sepolicy/build/soong/selinux_contexts.gobuildServiceContexts
静态检查system/sepolicy/tools/checkfc.cservice backend、attribute断言
target typesystem/sepolicy/public/service.teservice_manager_type
add/find/listframeworks/native/cmds/servicemanager/Access.cppactionAllowedFromLookup、actionAllowed
handle刷新同上getSehandle
注册状态frameworks/native/cmds/servicemanager/ServiceManager.cppaddService、mNameToService
查找与lazy同上tryGetBinder、tryStartService
VINTF accessor同上canAddService、canFindService
死亡清理同上binderDied
自注册frameworks/native/cmds/servicemanager/main.cppaddService("manager")、becomeContextManager
Binder下一层system/sepolicy/public/te_macrosbinder_call