Android,  Selinux

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_VERSPLATFORM_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,肯定会编译出错。

0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
最旧
最新 最多投票
内联反馈
查看所有评论
0
希望看到您的想法,请您发表评论x