Skip to content

Vndservice Contexts

从 vndservice_contexts 的 vendor-only 构建,追踪到 vndservicemanager 的独立 label handle、/dev/vndbinder、add/find/list 和 Treble 隔离。

基于android-17.0.0_r1
AndroidSELinuxvndservice_contextsvndservicemanagervndbinderTreble源码阅读

Vndservice Contexts ​

本文面向已经读过 Service Contexts、Hwservice Contexts 和 Binder 基础文章的读者。system servicemanager 与 vndservicemanager 复用同一套 Access.cpp、ServiceManager.cpp 和 main.cpp,但后者通过编译宏、独立驱动和独立 Context handle 形成 vendor Binder 名字空间。本篇解释这套“代码复用、运行边界分离”的真实实现。

Android 17 平台的 vndservice_contexts 只有 manager 与 * 两条。更关键的是,policy 禁止任何 domain 对 default_android_vndservice 做 service_manager 操作,所以 * 不是可用于快速放行的默认服务类型。厂商新增名字服务时,必须建立“名字条目 -> 专用 vndservice_manager_type -> server add/client find -> vndbinder 通信”的完整闭环。

本文不把 vndbinder 描述为所有 vendor 进程的默认 IPC。现代稳定 AIDL HAL 通常使用 /dev/binder 和 system servicemanager;HIDL 使用 /dev/hwbinder。/dev/vndbinder 是另一套 vendor-private Binder 名字空间,并受到 full-Treble neverallow 限制。读完后,读者应能区分驱动访问失败、Context lookup 失败、add/find 拒绝、lazy service 启动失败和真实 Binder call 失败。

1. 三套Manager ​

1.1 运行边界 ​

名字空间进程驱动Context文件target属性
System Binderservicemanager/dev/binderservice_contextsservice_manager_type
HIDL HwBinderhwservicemanager/dev/hwbinderhwservice_contextshwservice_manager_type
Vendor Bindervndservicemanager/dev/vndbindervndservice_contextsvndservice_manager_type

vndservicemanager 与 system servicemanager 都使用 service_manager object class;差异在 target type attribute、label handle、驱动和可访问 domain,而不是另造一个 vndservice_manager class。

1.2 启动配置 ​

源码文件:frameworks/native/cmds/servicemanager/vndservicemanager.rc

text
service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder
    class core
    user system
    group system readproc
    file /dev/kmsg w
    task_profiles ServiceCapacityLow
    onrestart class_restart main
    onrestart class_restart hal
    onrestart class_restart early_hal
    shutdown critical

驱动路径作为 main() 的第一个参数传入,因此同一二进制主逻辑可分别初始化 /dev/binder 或 /dev/vndbinder。

1.3 编译变体 ​

源码文件: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"],
}

VENDORSERVICEMANAGER 控制 Access 选择 vendor handle,并裁掉 system-only VINTF accessor、APEX、Perfetto 和 ready property 等分支。

2. Context文件 ​

2.1 平台输入 ​

源码文件:system/sepolicy/vendor/vndservice_contexts

text
manager                 u:object_r:service_manager_vndservice:s0
*                       u:object_r:default_android_vndservice:s0

manager 是 vndservicemanager 自注册使用的名字。* 只保证未知名字能得到一个明确 target Context,方便拒绝与审计;它不是厂商服务可以长期使用的 target。

2.2 Type声明 ​

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

text
type service_manager_vndservice, vndservice_manager_type;
type default_android_vndservice, vndservice_manager_type;

厂商自定义 target type 也必须带 vndservice_manager_type。普通 service_manager_type 或 hwservice_manager_type 不能替代它,否则 checkfc -v 和 Treble policy 会暴露边界错误。

2.3 默认拒绝 ​

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

text
neverallow * default_android_vndservice:service_manager *;

这条规则意味着旧文中“给 server/client 对 default_android_vndservice 增加 add/find”不可通过 policy 编译。正确做法是新增专用名字和专用 type。

3. Vendor构建 ​

3.1 单一Module ​

vndservice contexts 只有 vendor module,没有 platform/system_ext/product/odm 五份运行文件。输入来自 platform vendor、device vendor 和 reqd_mask,安装到 vendor 分区。

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

make
vndservice_contexts {
    name: "vndservice_contexts",
    defaults: ["contexts_flags_defaults"],
    srcs: [
        ":vndservice_contexts_files{.plat_vendor}",
        ":vndservice_contexts_files{.vendor}",
        ":vndservice_contexts_files{.reqd_mask}",
    ],
    soc_specific: true,
}

3.2 Vendor强制 ​

vndServiceFactory() 复用 buildGeneralContexts(),并在 load hook 中要求 module 必须是 soc_specific。这阻止 vndservice contexts 被错误安装到 system/product。

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

go
func vndServiceFactory() android.Module {
    m := newModule()
    m.build = m.buildGeneralContexts
    android.AddLoadHook(m, func(ctx android.LoadHookContext) {
        if !ctx.SocSpecific() {
            ctx.ModuleErrorf(m.Name(), "must set vendor: true")
            return
        }
    })
    return m
}

3.3 静态检查 ​

vndservice_contexts_test 使用 checkfc -e -v,其中 -v 选择 vendor service backend,attribute 断言是 vndservice_manager_type。

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

go
case VndServiceContext:
    flags = []string{"-e" /* allow empty */, "-v" /* vnd service */}

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

c
static const char * const CHECK_VND_SC_ASSERT_ATTRS[] = {
    "vndservice_manager_type", NULL
};

4. Vendor Handle ​

4.1 路径集合 ​

libselinux 的 vendor service handle 只读取 vendor 文件及根目录兼容路径,不合并 platform service_contexts。

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

c
static const path_alts_t vndservice_context_paths = { .paths = {
    {
        "/vendor/etc/selinux/vndservice_contexts",
        "/vndservice_contexts"
    }
}};

struct selabel_handle*
selinux_android_vendor_service_context_handle(void)
{
    return context_handle(SELABEL_CTX_ANDROID_SERVICE,
                          &vndservice_context_paths,
                          "vndservice");
}

backend 仍是 SELABEL_CTX_ANDROID_SERVICE,所以 vndservicemanager 的 object class 仍为 service_manager;独立性来自输入文件和 target attribute。

4.2 Access选择 ​

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

cpp
#ifdef VENDORSERVICEMANAGER
constexpr bool kIsVendor = true;
#else
constexpr bool kIsVendor = false;
#endif

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

同一函数在 system 变体加载五分区 service contexts,在 vendor 变体只加载 vndservice contexts。

4.3 日志回调 ​

Access 构造函数为 vendor 变体选择 selinux_vendor_log_callback。但是 lookup 失败的固定日志字符串仍写着 in service_contexts,排查 vndservicemanager 日志时不要因此误判它加载了 platform service contexts。

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

cpp
cb.func_log = kIsVendor
        ? selinux_vendor_log_callback
        : selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);

4.4 权限调用 ​

add/find 仍是名字 lookup 后调用 selinux_check_access(source, target, "service_manager", perm);list 仍以 vndservicemanager 自身 Context 为 target。

5. Manager启动 ​

5.1 Driver参数 ​

main() 默认 driver 是 /dev/binder,但 vndservicemanager rc 显式传入 /dev/vndbinder。ProcessState 因而在独立 binder driver 上成为 context manager。

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

cpp
const char* driver = argc == 2 ? argv[1] : "/dev/binder";
LOG(INFO) << "Starting sm instance on " << driver;

sp<ProcessState> ps = ProcessState::initWithDriver(driver);
ps->setThreadPoolMaxThreadCount(0);
ps->setCallRestriction(
        ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);

5.2 自注册 ​

vendor manager 仍将自身注册为 manager。该名字命中 service_manager_vndservice,而 vendor policy 的 add_service(vndservicemanager, service_manager_vndservice) 提供 add/find 并排除其他注册者。

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

5.3 Ready差异 ​

system servicemanager 会设置 servicemanager.ready=true;该代码被 #ifndef VENDORSERVICEMANAGER 包围,vendor 实例不设置独立 ready property。vendor 服务由 init class 和重启依赖协调。

5.4 重启范围 ​

vndservicemanager rc 的 onrestart 会重启 main、hal、early_hal class。名字表丢失后,仅重启 manager 不足以恢复服务,注册者也必须重新 add;这就是 rc 扩大恢复范围的原因。

6. 功能裁剪 ​

6.1 VINTF接口 ​

ServiceManager.cpp 中 accessor、declared instances、updatable APEX 和 connection info 等 VINTF 功能被 #ifndef VENDORSERVICEMANAGER 排除。vendor manager 的 canAdd/canFind 只做原始名字的 SELinux 检查,不再计算 accessor name。

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

cpp
Status ServiceManager::canAddService(
        const Access::CallingContext& ctx,
        const std::string& name,
        std::optional<std::string>* accessor) {
    if (!mAccess->canAdd(ctx, name)) {
        return Status::fromExceptionCode(
                Status::EX_SECURITY, "SELinux denied for service.");
    }
#ifndef VENDORSERVICEMANAGER
    *accessor = getVintfAccessorName(name);
#endif
    if (accessor->has_value() &&
        !mAccess->canAdd(ctx, accessor->value())) {
        return Status::fromExceptionCode(
                Status::EX_SECURITY,
                "SELinux denied for the accessor of the service.");
    }
    return Status::ok();
}

6.2 Lazy服务 ​

tryStartService() 没有被 vendor 宏裁掉,所以 vndservicemanager 的 getService 仍可能设置 ctl.interface_start=aidl/<name>。vendor policy 显式允许它设置 ctl_interface_start_prop。

源码文件:system/sepolicy/vendor/vndservicemanager.te

yaml
# Start lazy services
set_prop(vndservicemanager, ctl_interface_start_prop)

这并不保证厂商 rc 已声明匹配的 interface aidl/<name>;property 设置成功和服务最终注册仍是两个阶段。

6.3 Perfetto与Ready ​

Perfetto track-event 初始化和 servicemanager.ready property 都只在非 vendor 构建出现。调试 vndservicemanager 时不应期待与 system manager 完全相同的 trace/category/ready 信号。

7. Vendor Policy ​

7.1 Manager权限 ​

源码文件:system/sepolicy/vendor/vndservicemanager.te

text
type vndservicemanager_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(vndservicemanager);

allow vndservicemanager self:binder set_context_mgr;
allow vndservicemanager
    { domain -coredomain -init -vendor_init }:binder transfer;
allow vndservicemanager vndbinder_device:chr_file rw_file_perms;
allow vndservicemanager vndservice_contexts_file:file r_file_perms;

add_service(vndservicemanager, service_manager_vndservice)
set_prop(vndservicemanager, ctl_interface_start_prop)
selinux_check_access(vndservicemanager)

manager 可以向非 coredomain vendor 进程 transfer binder 引用,但不能把这条规则理解为所有 vendor domain 彼此可 call;server/client 之间仍需 Binder policy。

7.2 vndbinder_use ​

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

text
define(`vndbinder_use', `
  allow $1 vndbinder_device:chr_file rw_file_perms;
  allow $1 vndservicemanager:binder { call transfer };
')

宏只解决打开 driver 和调用 manager,不包含具体 vndservice target 的 find/add,也不包含 client 到 server 的 binder_call。

7.3 Full Treble隔离 ​

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

text
full_treble_only(`
  neverallow {
    coredomain
    -shell
    userdebug_or_eng(`-su')
  } vndservice_manager_type:service_manager *;
')

full_treble_only(`
  neverallow {
    coredomain
    -shell
    userdebug_or_eng(`-su')
  } vndservicemanager:binder *;
')

system core domain 在 full-Treble 设备上不能访问 vendor service names,也不能直接和 vndservicemanager Binder 通信。shell/su 例外服务于调试,不代表产品代码可依赖。

7.4 Driver隔离 ​

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

text
neverallow servicemanager vndbinder_device:chr_file no_rw_file_perms;
neverallow hwservicemanager vndbinder_device:chr_file no_rw_file_perms;
neverallow vndservicemanager binder_device:chr_file no_rw_file_perms;
neverallow vndservicemanager hwbinder_device:chr_file no_rw_file_perms;

三种 manager 只能访问各自 driver;普通 untrusted/isolated app 还被单独禁止使用 vndbinder。

8. 自定义服务 ​

8.1 名字映射 ​

设备 vendor sepolicy 中先为真实注册名添加 Context。ServiceManager 的名称规则允许字母、数字、点、下划线、短横线和斜杠;条目必须与代码传给 addService 的字符串完全一致。

text
vendor.sensor.algo       u:object_r:vendor_sensor_algo_vndservice:s0

8.2 Type声明 ​

text
type vendor_sensor_algo_vndservice, vndservice_manager_type;

checkfc -v 会验证该 attribute。不要使用 default_android_vndservice,也不要把 system service_manager_type 当作替代。

8.3 Server规则 ​

text
vndbinder_use(vendor_sensor_algo)
allow vendor_sensor_algo
    vendor_sensor_algo_vndservice:service_manager { add find };
neverallow { domain -vendor_sensor_algo }
    vendor_sensor_algo_vndservice:service_manager add;

server 通常也需要 find 自己的服务;neverallow 确保只有指定 domain 可以 add。厂商可以封装类似 add_service 的本地宏,但输出 target 必须属于 vndservice attribute。

8.4 Client规则 ​

text
vndbinder_use(vendor_sensor_client)
allow vendor_sensor_client
    vendor_sensor_algo_vndservice:service_manager find;
binder_call(vendor_sensor_client, vendor_sensor_algo)

三组权限分别证明:client 能调用 manager、能通过名字发现 binder、能对 server domain 发 transaction。缺任何一组都会在不同位置失败。

8.5 进程与驱动 ​

vendor native 进程需要让 libbinder 使用 /dev/vndbinder 对应的 ProcessState。仅添加 vndbinder_use 不会自动修改程序选择的 driver;若程序仍初始化 /dev/binder,它会进入 system ServiceManager 名字空间。

9. 生命周期 ​

9.1 注册 ​

vndservicemanager 复用 ServiceManager::addService():先拒绝 App UID,做 vndservice lookup/add 检查,再验证 binder、名字和 linkToDeath,最后写入 mNameToService。VINTF declaration/accessor 分支被 vendor 宏裁掉。

9.2 查找 ​

getService()/checkService() 同样复用 system 实现。target Context 来自 vendor handle;isolated allowIsolated、find 权限和输出 binder 语义保持一致。

9.3 Lazy启动 ​

名字有 find 权限但 binder 不存在时,getService 可能异步请求 ctl.interface_start=aidl/<name>。调用者第一次仍收到空 binder,需要等待服务注册通知或重试。

9.4 死亡与重启 ​

server binder death 会删除名字表项;vndservicemanager 自身死亡则整个 vendor 名字表丢失。init rc 重启 main/hal/early_hal class,使相关进程重新建立 Binder driver 状态并 add 服务。

10. 失败定位 ​

10.1 Driver错误 ​

现象检查
vendor 进程访问 binder_device denied程序是否错误选择 /dev/binder
访问 vndbinder_device denied是否缺少 vndbinder_use 或被 Treble neverallow
manager 调用 deniedcaller 到 vndservicemanager:binder 权限

10.2 名字错误 ​

如果日志显示 No match for ... in service_contexts,对 vendor 变体而言实际应检查 /vendor/etc/selinux/vndservice_contexts。固定日志文本沿用了 system manager 名称。

10.3 默认标签 ​

target 是 default_android_vndservice 时说明缺少专用映射或产物未更新。不要尝试 allow 默认 target,neverallow 会阻止这种修复。

10.4 Treble拒绝 ​

coredomain 在 full-Treble 设备上访问 vndservicemanager 或 vndservice target 会触发 neverallow/运行时 deny。若通信需要跨 system/vendor 边界,应选择稳定 AIDL HAL 或其他正式接口,而不是放宽 vendor-private 名字空间。

10.5 Binder调用 ​

find 成功但 transaction denied 时,检查 client/server domain 的 binder_call、fd use 和接口业务权限;继续修改 vndservice_contexts 不会改变 server process SID。

11. 验证方法 ​

11.1 构建检查 ​

bash
# 选择实际产品并构建 vendor contexts 与 checkfc -v 测试。
source build/envsetup.sh
lunch PRODUCT-userdebug
m vndservice_contexts vndservice_contexts_test vndservicemanager

11.2 设备观察 ​

bash
# 确认 manager、driver 与 Context 文件。
adb shell ps -AZ | grep vndservicemanager
adb shell ls -Z /dev/vndbinder
adb shell cat /vendor/etc/selinux/vndservice_contexts

# vndservicemanager 使用独立 driver,普通 service 命令未必连接它;
# 应使用产品提供的 vendor Binder 客户端或专用测试程序验证 add/find。

11.3 Audit日志 ​

bash
# 同时筛选名字空间权限与 driver 权限。
adb shell dmesg | grep -E \
  'vndservicemanager|vndbinder|default_android_vndservice|service_manager'

11.4 反向断言 ​

可以故意为测试服务暂时省略专用 mapping:预期 lookup 落到 default target,policy 构建或运行访问被拒绝;恢复专用 type/mapping 后,checkfc -v 应通过。该实验只在测试策略中进行,不要把默认 target allow 留入产品。

12. 源码导航 ​

问题首选源码关键符号
平台默认条目system/sepolicy/vendor/vndservice_contextsmanager、*
target类型system/sepolicy/public/vndservice.tevndservice_manager_type
vendor-only构建system/sepolicy/contexts/Android.bpvndservice_contexts
module约束system/sepolicy/build/soong/selinux_contexts.govndServiceFactory、-v
Context handleexternal/selinux/libselinux/src/android/android.cvndservice_context_paths
system/vendor变体选择frameworks/native/cmds/servicemanager/Access.cppkIsVendor、getSehandle
driver和自注册frameworks/native/cmds/servicemanager/main.cppinitWithDriver、manager
功能裁剪frameworks/native/cmds/servicemanager/ServiceManager.cppVENDORSERVICEMANAGER branches
init恢复范围frameworks/native/cmds/servicemanager/vndservicemanager.rconrestart class_restart
manager policysystem/sepolicy/vendor/vndservicemanager.tecontexts read、set_context_mgr
vendor client宏system/sepolicy/public/te_macrosvndbinder_use
Treble边界system/sepolicy/private/domain.tefull_treble_only neverallow

复述一个自定义 vendor Binder 服务时,应包括:进程选择 /dev/vndbinder 并通过 vndbinder_use 调用 manager;vndservicemanager 使用 vendor-only handle 将名字映射到专用 vndservice_manager_type;server 通过 add、client 通过 find;ServiceManager 把 binder 写入独立名字表并管理死亡/回调;拿到引用后,client/server 仍需 binder_call。如果名字落到 default target,正确动作是补齐 mapping/type,而不是给默认标签放权;如果 coredomain 需要访问,应重新审视架构是否应该迁移到稳定 system Binder 接口。