Android Vendor SELinux Policy编译过程分析
自从Android 8引入Treble框架后,Android将System和Vendor分为两个部分,允许独立升级system和vendor,随后引入了Product、ODM等分区。在这样的背景下,SELinux规则也被划分为platform(system)、system_ext、product、vendor和odm几个部分。
本文以Vendor分区为例,详细分析了如何将sepolicy文件包含到Android编译系统中,以及Android.mk的变量如何传递到Soong编译系统,并最终如何与Android.bp中的模块和变量相对应。
1. Android Makefile中 include SELinux policy文件
首先,Vendor的SELinux策略文件通过 BOARD_VENDOR_SEPOLICY_DIRS 或者 BOARD_SEPOLICY_DIRS 变量添加到Android的编译系统中。例如:
BOARD_VENDOR_SEPOLICY_DIRS += vendor/xx/featureA/sepolicy
2. Android Makefile变量传递给Soong
这些Makefile变量通过 soong_config.mk 被转换为JSON格式,然后传递给Soong编译系统,指定相应的Go语言变量(例如 BoardVendorSepolicyDirs)。
./build/make/core/soong_config.mk:203: $(call add_json_list, BoardVendorSepolicyDirs, $(BOARD_VENDOR_SEPOLICY_DIRS) $(BOARD_SEPOLICY_DIRS))
3. Soong中变量的声明
在Soong的 variable.go 文件中,定义了存储Vendor SELinux策略文件路径的变量。
./build/soong/android/variable.go:355: BoardVendorSepolicyDirs []string `json:",omitempty"`
4. 获取Vendor策略路径的接口
Soong提供了接口来获取Vendor策略文件的路径列表。
func (c *deviceConfig) VendorSepolicyDirs() []string {
return c.config.productVariables.BoardVendorSepolicyDirs
}
5. Android.bp中变量与Makefile中SELinux变量的对应关系
在Android编译系统的 build/soong/build_files.go 文件中,实现了Android.bp中变量与Makefile中SELinux变量的映射关系。
func (b *buildFiles) GenerateAndroidBuildActions(ctx android.ModuleContext) {
b.srcs = make(map[string]android.Paths)
b.srcs[".reqd_mask"] = b.findSrcsInDirs(ctx, filepath.Join(ctx.ModuleDir(), "reqd_mask"))
b.srcs[".plat_public"] = b.findSrcsInDirs(ctx, filepath.Join(ctx.ModuleDir(), "public"))
b.srcs[".plat_private"] = b.findSrcsInDirs(ctx, filepath.Join(ctx.ModuleDir(), "private"))
b.srcs[".plat_vendor"] = b.findSrcsInDirs(ctx, filepath.Join(ctx.ModuleDir(), "vendor"))
b.srcs[".system_ext_public"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().SystemExtPublicSepolicyDirs()...)
b.srcs[".system_ext_private"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().SystemExtPrivateSepolicyDirs()...)
b.srcs[".product_public"] = b.findSrcsInDirs(ctx, ctx.Config().ProductPublicSepolicyDirs()...)
b.srcs[".product_private"] = b.findSrcsInDirs(ctx, ctx.Config().ProductPrivateSepolicyDirs()...)
b.srcs[".vendor"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().VendorSepolicyDirs()...)
b.srcs[".odm"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().OdmSepolicyDirs()...)
if ctx.DeviceConfig().PlatformSepolicyVersion() == ctx.DeviceConfig().BoardSepolicyVers() {
// vendor uses the same source with plat policy
b.srcs[".reqd_mask_for_vendor"] = b.srcs[".reqd_mask"]
b.srcs[".plat_vendor_for_vendor"] = b.srcs[".plat_vendor"]
b.srcs[".plat_public_for_vendor"] = b.srcs[".plat_public"]
b.srcs[".plat_private_for_vendor"] = b.srcs[".plat_private"]
b.srcs[".system_ext_public_for_vendor"] = b.srcs[".system_ext_public"]
b.srcs[".system_ext_private_for_vendor"] = b.srcs[".system_ext_private"]
b.srcs[".product_public_for_vendor"] = b.srcs[".product_public"]
b.srcs[".product_private_for_vendor"] = b.srcs[".product_private"]
} else {
// use vendor-supplied plat prebuilts
b.srcs[".reqd_mask_for_vendor"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().BoardReqdMaskPolicy()...)
b.srcs[".plat_vendor_for_vendor"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().BoardPlatVendorPolicy()...)
b.srcs[".plat_public_for_vendor"] = b.findSrcsInDirs(ctx, filepath.Join(ctx.ModuleDir(), "prebuilts", "api", ctx.DeviceConfig().BoardSepolicyVers(), "public"))
b.srcs[".plat_private_for_vendor"] = b.findSrcsInDirs(ctx, filepath.Join(ctx.ModuleDir(), "prebuilts", "api", ctx.DeviceConfig().BoardSepolicyVers(), "private"))
b.srcs[".system_ext_public_for_vendor"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().BoardSystemExtPublicPrebuiltDirs()...)
b.srcs[".system_ext_private_for_vendor"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().BoardSystemExtPrivatePrebuiltDirs()...)
b.srcs[".product_public_for_vendor"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().BoardProductPublicPrebuiltDirs()...)
b.srcs[".product_private_for_vendor"] = b.findSrcsInDirs(ctx, ctx.DeviceConfig().BoardProductPrivatePrebuiltDirs()...)
}
}
在上述代码中, b.srcs[xxx] 中的 xxx 是Android.bp中的变量,可以直接在Android.bp文件中使用。因此,总结如下表所示,其中前四个变量是Android平台默认提供的,Vendor厂商无法定制。
| Android.bp | 对应的Android.mk变量或代码目录 |
|---|---|
| .reqd_mask | system/sepolicy/reqd_mask |
| .plat_public | system/sepolicy/public |
| .plat_private | system/sepolicy/private |
| .plat_vendor | system/sepolicy/vendor |
| .system_ext_public | $(SYSTEM_EXT_PUBLIC_SEPOLICY_DIRS) $(BOARD_PLAT_PUBLIC_SEPOLICY_DIR) |
| .system_ext_private | $(SYSTEM_EXT_PRIVATE_SEPOLICY_DIRS) $(BOARD_PLAT_PRIVATE_SEPOLICY_DIR) |
| .product_public | $(PRODUCT_PUBLIC_SEPOLICY_DIRS) |
| .product_private | $(PRODUCT_PRIVATE_SEPOLICY_DIRS) |
| .vendor | $(BOARD_VENDOR_SEPOLICY_DIRS) $(BOARD_SEPOLICY_DIRS) |
如果 BOARD_SEPOLICY_VERS 和 PLATFORM_SEPOLICY_VERSION 相等,表示Vendor使用当前平台的SELinux规则;否则使用 BOARD_SEPOLICY_VERS 指定的SELinux规则。在相等情况下,相关Android.bp中的SELinux策略变量可以简化为以下形式:
| Android.bp | 取值 |
|---|---|
| .reqd_mask_for_vendor | .reqd_mask |
| .plat_public_for_vendor | .plat_public |
| .plat_private_for_vendor | .plat_private |
| .plat_vendor_for_vendor | .plat_vendor |
| .system_ext_public_for_vendor | .system_ext_public |
| .system_ext_private_for_vendor | .system_ext_private |
| .product_public_for_vendor | .product_public |
| .product_private_for_vendor | .product_private |
6. plat_policy_for_vendor 模块的编译
plat_policy_for_vendor的最终编译生成是plat_policy_for_vendor.cli文件,plat_policy_for_vendor.cli文件依赖plat_policy_for_vendor.conf文件, plat_policy_for_vendor.conf的编译过程如下:
se_policy_conf {
name: "plat_policy_for_vendor.conf",
srcs: plat_policies_for_vendor,
installable: false,
}
plat_policies_for_vendor如下:
plat_policies_for_vendor = [
":se_build_files{.plat_public_for_vendor}",
":se_build_files{.plat_private_for_vendor}",
":se_build_files{.system_ext_public_for_vendor}",
":se_build_files{.system_ext_private_for_vendor}",
":se_build_files{.product_public_for_vendor}",
":se_build_files{.product_private_for_vendor}",
]
可以看到,plat_policy_for_vendor的编译过程不会使用plat_vendor_for_vendor中定义的sepolicy文件,所以如果在system_ext_public_for_vendor中增加了一个规则,但是新增的规则依赖plat_vendor_for_vendor中的type,肯定会编译出错。

