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 Binder | servicemanager | /dev/binder | service_contexts | service_manager_type |
| HIDL HwBinder | hwservicemanager | /dev/hwbinder | hwservice_contexts | hwservice_manager_type |
| Vendor Binder | vndservicemanager | /dev/vndbinder | vndservice_contexts | vndservice_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
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
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
manager u:object_r:service_manager_vndservice:s0
* u:object_r:default_android_vndservice:s0manager 是 vndservicemanager 自注册使用的名字。* 只保证未知名字能得到一个明确 target Context,方便拒绝与审计;它不是厂商服务可以长期使用的 target。
2.2 Type声明
源码文件:system/sepolicy/public/vndservice.te
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
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
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
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
case VndServiceContext:
flags = []string{"-e" /* allow empty */, "-v" /* vnd service */}源码文件:system/sepolicy/tools/checkfc.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
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
#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
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
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
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
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
# 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
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
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
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
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 的字符串完全一致。
vendor.sensor.algo u:object_r:vendor_sensor_algo_vndservice:s08.2 Type声明
type vendor_sensor_algo_vndservice, vndservice_manager_type;checkfc -v 会验证该 attribute。不要使用 default_android_vndservice,也不要把 system service_manager_type 当作替代。
8.3 Server规则
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规则
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 调用 denied | caller 到 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 构建检查
# 选择实际产品并构建 vendor contexts 与 checkfc -v 测试。
source build/envsetup.sh
lunch PRODUCT-userdebug
m vndservice_contexts vndservice_contexts_test vndservicemanager11.2 设备观察
# 确认 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日志
# 同时筛选名字空间权限与 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_contexts | manager、* |
| target类型 | system/sepolicy/public/vndservice.te | vndservice_manager_type |
| vendor-only构建 | system/sepolicy/contexts/Android.bp | vndservice_contexts |
| module约束 | system/sepolicy/build/soong/selinux_contexts.go | vndServiceFactory、-v |
| Context handle | external/selinux/libselinux/src/android/android.c | vndservice_context_paths |
| system/vendor变体选择 | frameworks/native/cmds/servicemanager/Access.cpp | kIsVendor、getSehandle |
| driver和自注册 | frameworks/native/cmds/servicemanager/main.cpp | initWithDriver、manager |
| 功能裁剪 | frameworks/native/cmds/servicemanager/ServiceManager.cpp | VENDORSERVICEMANAGER branches |
| init恢复范围 | frameworks/native/cmds/servicemanager/vndservicemanager.rc | onrestart class_restart |
| manager policy | system/sepolicy/vendor/vndservicemanager.te | contexts read、set_context_mgr |
| vendor client宏 | system/sepolicy/public/te_macros | vndbinder_use |
| Treble边界 | system/sepolicy/private/domain.te | full_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 接口。
