dfa4a48b1c
Sorting algorithm of fc_sort is not perfect and often causes unexpected behaviors. We are moving from fc_sort to manual ordering of platform file_contexts files. In addition, this sets remove_comment as true by default, as fc_sort has been removing comments / empty lines. Bug: 299839280 Test: TH Change-Id: Ic8a02b64fc70481234467a470506580d2e6efd94
702 lines
21 KiB
Go
702 lines
21 KiB
Go
// Copyright (C) 2019 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package selinux
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
"android/soong/android"
|
|
"android/soong/sysprop"
|
|
)
|
|
|
|
type selinuxContextsProperties struct {
|
|
// Filenames under sepolicy directories, which will be used to generate contexts file.
|
|
Srcs []string `android:"path"`
|
|
|
|
// Output file name. Defaults to module name
|
|
Stem *string
|
|
|
|
Product_variables struct {
|
|
Address_sanitize struct {
|
|
Srcs []string `android:"path"`
|
|
}
|
|
}
|
|
|
|
// Whether the comments in generated contexts file will be removed or not.
|
|
Remove_comment *bool
|
|
|
|
// Whether the result context file is sorted with fc_sort or not.
|
|
Fc_sort *bool
|
|
|
|
// Make this module available when building for recovery
|
|
Recovery_available *bool
|
|
}
|
|
|
|
type seappProperties struct {
|
|
// Files containing neverallow rules.
|
|
Neverallow_files []string `android:"path"`
|
|
|
|
// Precompiled sepolicy binary file which will be fed to checkseapp.
|
|
Sepolicy *string `android:"path"`
|
|
}
|
|
|
|
type selinuxContextsModule struct {
|
|
android.ModuleBase
|
|
|
|
properties selinuxContextsProperties
|
|
seappProperties seappProperties
|
|
build func(ctx android.ModuleContext, inputs android.Paths) android.Path
|
|
deps func(ctx android.BottomUpMutatorContext)
|
|
outputPath android.Path
|
|
installPath android.InstallPath
|
|
}
|
|
|
|
var (
|
|
reuseContextsDepTag = dependencyTag{name: "reuseContexts"}
|
|
syspropLibraryDepTag = dependencyTag{name: "sysprop_library"}
|
|
)
|
|
|
|
func init() {
|
|
pctx.HostBinToolVariable("fc_sort", "fc_sort")
|
|
|
|
android.RegisterModuleType("file_contexts", fileFactory)
|
|
android.RegisterModuleType("hwservice_contexts", hwServiceFactory)
|
|
android.RegisterModuleType("property_contexts", propertyFactory)
|
|
android.RegisterModuleType("service_contexts", serviceFactory)
|
|
android.RegisterModuleType("keystore2_key_contexts", keystoreKeyFactory)
|
|
android.RegisterModuleType("seapp_contexts", seappFactory)
|
|
android.RegisterModuleType("vndservice_contexts", vndServiceFactory)
|
|
|
|
android.RegisterModuleType("file_contexts_test", fileContextsTestFactory)
|
|
android.RegisterModuleType("property_contexts_test", propertyContextsTestFactory)
|
|
android.RegisterModuleType("hwservice_contexts_test", hwserviceContextsTestFactory)
|
|
android.RegisterModuleType("service_contexts_test", serviceContextsTestFactory)
|
|
android.RegisterModuleType("vndservice_contexts_test", vndServiceContextsTestFactory)
|
|
}
|
|
|
|
func (m *selinuxContextsModule) InstallInRoot() bool {
|
|
return m.InRecovery()
|
|
}
|
|
|
|
func (m *selinuxContextsModule) InstallInRecovery() bool {
|
|
// ModuleBase.InRecovery() checks the image variant
|
|
return m.InRecovery()
|
|
}
|
|
|
|
func (m *selinuxContextsModule) onlyInRecovery() bool {
|
|
// ModuleBase.InstallInRecovery() checks commonProperties.Recovery property
|
|
return m.ModuleBase.InstallInRecovery()
|
|
}
|
|
|
|
func (m *selinuxContextsModule) DepsMutator(ctx android.BottomUpMutatorContext) {
|
|
if m.deps != nil {
|
|
m.deps(ctx)
|
|
}
|
|
|
|
if m.InRecovery() && !m.onlyInRecovery() {
|
|
ctx.AddFarVariationDependencies([]blueprint.Variation{
|
|
{Mutator: "image", Variation: android.CoreVariation},
|
|
}, reuseContextsDepTag, ctx.ModuleName())
|
|
}
|
|
}
|
|
|
|
func (m *selinuxContextsModule) propertyContextsDeps(ctx android.BottomUpMutatorContext) {
|
|
for _, lib := range sysprop.SyspropLibraries(ctx.Config()) {
|
|
ctx.AddFarVariationDependencies([]blueprint.Variation{}, syspropLibraryDepTag, lib)
|
|
}
|
|
}
|
|
|
|
func (m *selinuxContextsModule) stem() string {
|
|
return proptools.StringDefault(m.properties.Stem, m.Name())
|
|
}
|
|
|
|
func (m *selinuxContextsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
if m.InRecovery() {
|
|
// Installing context files at the root of the recovery partition
|
|
m.installPath = android.PathForModuleInstall(ctx)
|
|
} else {
|
|
m.installPath = android.PathForModuleInstall(ctx, "etc", "selinux")
|
|
}
|
|
|
|
if m.InRecovery() && !m.onlyInRecovery() {
|
|
dep := ctx.GetDirectDepWithTag(m.Name(), reuseContextsDepTag)
|
|
|
|
if reuseDeps, ok := dep.(*selinuxContextsModule); ok {
|
|
m.outputPath = reuseDeps.outputPath
|
|
ctx.InstallFile(m.installPath, m.stem(), m.outputPath)
|
|
return
|
|
}
|
|
}
|
|
|
|
m.outputPath = m.build(ctx, android.PathsForModuleSrc(ctx, m.properties.Srcs))
|
|
ctx.InstallFile(m.installPath, m.stem(), m.outputPath)
|
|
}
|
|
|
|
func newModule() *selinuxContextsModule {
|
|
m := &selinuxContextsModule{}
|
|
m.AddProperties(
|
|
&m.properties,
|
|
&m.seappProperties,
|
|
)
|
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
|
android.AddLoadHook(m, func(ctx android.LoadHookContext) {
|
|
m.selinuxContextsHook(ctx)
|
|
})
|
|
return m
|
|
}
|
|
|
|
func (m *selinuxContextsModule) selinuxContextsHook(ctx android.LoadHookContext) {
|
|
// TODO: clean this up to use build/soong/android/variable.go after b/79249983
|
|
var srcs []string
|
|
|
|
for _, sanitize := range ctx.Config().SanitizeDevice() {
|
|
if sanitize == "address" {
|
|
srcs = append(srcs, m.properties.Product_variables.Address_sanitize.Srcs...)
|
|
break
|
|
}
|
|
}
|
|
|
|
m.properties.Srcs = append(m.properties.Srcs, srcs...)
|
|
}
|
|
|
|
func (m *selinuxContextsModule) AndroidMk() android.AndroidMkData {
|
|
nameSuffix := ""
|
|
if m.InRecovery() && !m.onlyInRecovery() {
|
|
nameSuffix = ".recovery"
|
|
}
|
|
return android.AndroidMkData{
|
|
Class: "ETC",
|
|
OutputFile: android.OptionalPathForPath(m.outputPath),
|
|
SubName: nameSuffix,
|
|
Extra: []android.AndroidMkExtraFunc{
|
|
func(w io.Writer, outputFile android.Path) {
|
|
fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", m.installPath.String())
|
|
fmt.Fprintln(w, "LOCAL_INSTALLED_MODULE_STEM :=", m.stem())
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func (m *selinuxContextsModule) ImageMutatorBegin(ctx android.BaseModuleContext) {
|
|
if proptools.Bool(m.properties.Recovery_available) && m.ModuleBase.InstallInRecovery() {
|
|
ctx.PropertyErrorf("recovery_available",
|
|
"doesn't make sense at the same time as `recovery: true`")
|
|
}
|
|
}
|
|
|
|
func (m *selinuxContextsModule) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return !m.ModuleBase.InstallInRecovery()
|
|
}
|
|
|
|
func (m *selinuxContextsModule) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return false
|
|
}
|
|
|
|
func (m *selinuxContextsModule) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return false
|
|
}
|
|
|
|
func (m *selinuxContextsModule) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return false
|
|
}
|
|
|
|
func (m *selinuxContextsModule) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return m.ModuleBase.InstallInRecovery() || proptools.Bool(m.properties.Recovery_available)
|
|
}
|
|
|
|
func (m *selinuxContextsModule) ExtraImageVariations(ctx android.BaseModuleContext) []string {
|
|
return nil
|
|
}
|
|
|
|
func (m *selinuxContextsModule) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
|
|
}
|
|
|
|
var _ android.ImageInterface = (*selinuxContextsModule)(nil)
|
|
|
|
func (m *selinuxContextsModule) buildGeneralContexts(ctx android.ModuleContext, inputs android.Paths) android.Path {
|
|
builtContext := pathForModuleOut(ctx, ctx.ModuleName()+"_m4out")
|
|
|
|
rule := android.NewRuleBuilder(pctx, ctx)
|
|
|
|
newlineFile := pathForModuleOut(ctx, "newline")
|
|
|
|
rule.Command().Text("echo").FlagWithOutput("> ", newlineFile)
|
|
rule.Temporary(newlineFile)
|
|
|
|
var inputsWithNewline android.Paths
|
|
for _, input := range inputs {
|
|
inputsWithNewline = append(inputsWithNewline, input, newlineFile)
|
|
}
|
|
|
|
rule.Command().
|
|
Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
|
|
Text("--fatal-warnings -s").
|
|
FlagForEachArg("-D", ctx.DeviceConfig().SepolicyM4Defs()).
|
|
Inputs(inputsWithNewline).
|
|
FlagWithOutput("> ", builtContext)
|
|
|
|
if proptools.Bool(m.properties.Remove_comment) {
|
|
rule.Temporary(builtContext)
|
|
|
|
remove_comment_output := pathForModuleOut(ctx, ctx.ModuleName()+"_remove_comment")
|
|
|
|
rule.Command().
|
|
Text("sed -e 's/#.*$//' -e '/^$/d'").
|
|
Input(builtContext).
|
|
FlagWithOutput("> ", remove_comment_output)
|
|
|
|
builtContext = remove_comment_output
|
|
}
|
|
|
|
if proptools.Bool(m.properties.Fc_sort) {
|
|
rule.Temporary(builtContext)
|
|
|
|
sorted_output := pathForModuleOut(ctx, ctx.ModuleName()+"_sorted")
|
|
|
|
rule.Command().
|
|
Tool(ctx.Config().HostToolPath(ctx, "fc_sort")).
|
|
FlagWithInput("-i ", builtContext).
|
|
FlagWithOutput("-o ", sorted_output)
|
|
|
|
builtContext = sorted_output
|
|
}
|
|
|
|
ret := pathForModuleOut(ctx, m.stem())
|
|
rule.Temporary(builtContext)
|
|
rule.Command().Text("cp").Input(builtContext).Output(ret)
|
|
|
|
rule.DeleteTemporaryFiles()
|
|
rule.Build("selinux_contexts", "building contexts: "+m.Name())
|
|
|
|
return ret
|
|
}
|
|
|
|
func (m *selinuxContextsModule) buildFileContexts(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 fileFactory() android.Module {
|
|
m := newModule()
|
|
m.build = m.buildFileContexts
|
|
return m
|
|
}
|
|
|
|
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 (m *selinuxContextsModule) checkVendorPropertyNamespace(ctx android.ModuleContext, inputs android.Paths) android.Paths {
|
|
shippingApiLevel := ctx.DeviceConfig().ShippingApiLevel()
|
|
ApiLevelR := android.ApiLevelOrPanic(ctx, "R")
|
|
|
|
rule := android.NewRuleBuilder(pctx, ctx)
|
|
|
|
// This list is from vts_treble_sys_prop_test.
|
|
allowedPropertyPrefixes := []string{
|
|
"ctl.odm.",
|
|
"ctl.vendor.",
|
|
"ctl.start$odm.",
|
|
"ctl.start$vendor.",
|
|
"ctl.stop$odm.",
|
|
"ctl.stop$vendor.",
|
|
"init.svc.odm.",
|
|
"init.svc.vendor.",
|
|
"ro.boot.",
|
|
"ro.hardware.",
|
|
"ro.odm.",
|
|
"ro.vendor.",
|
|
"odm.",
|
|
"persist.odm.",
|
|
"persist.vendor.",
|
|
"vendor.",
|
|
}
|
|
|
|
// persist.camera is also allowed for devices launching with R or eariler
|
|
if shippingApiLevel.LessThanOrEqualTo(ApiLevelR) {
|
|
allowedPropertyPrefixes = append(allowedPropertyPrefixes, "persist.camera.")
|
|
}
|
|
|
|
var allowedContextPrefixes []string
|
|
|
|
if shippingApiLevel.GreaterThanOrEqualTo(ApiLevelR) {
|
|
// This list is from vts_treble_sys_prop_test.
|
|
allowedContextPrefixes = []string{
|
|
"vendor_",
|
|
"odm_",
|
|
}
|
|
}
|
|
|
|
var ret android.Paths
|
|
for _, input := range inputs {
|
|
cmd := rule.Command().
|
|
BuiltTool("check_prop_prefix").
|
|
FlagWithInput("--property-contexts ", input).
|
|
FlagForEachArg("--allowed-property-prefix ", proptools.ShellEscapeList(allowedPropertyPrefixes)). // contains shell special character '$'
|
|
FlagForEachArg("--allowed-context-prefix ", allowedContextPrefixes)
|
|
|
|
if !ctx.DeviceConfig().BuildBrokenVendorPropertyNamespace() {
|
|
cmd.Flag("--strict")
|
|
}
|
|
|
|
out := pathForModuleOut(ctx, "namespace_checked").Join(ctx, input.String())
|
|
rule.Command().Text("cp -f").Input(input).Output(out)
|
|
ret = append(ret, out)
|
|
}
|
|
rule.Build("check_namespace", "checking namespace of "+ctx.ModuleName())
|
|
return ret
|
|
}
|
|
|
|
func (m *selinuxContextsModule) buildPropertyContexts(ctx android.ModuleContext, inputs android.Paths) android.Path {
|
|
// vendor/odm properties are enforced for devices launching with Android Q or later. So, if
|
|
// vendor/odm, make sure that only vendor/odm properties exist.
|
|
shippingApiLevel := ctx.DeviceConfig().ShippingApiLevel()
|
|
ApiLevelQ := android.ApiLevelOrPanic(ctx, "Q")
|
|
if (ctx.SocSpecific() || ctx.DeviceSpecific()) && shippingApiLevel.GreaterThanOrEqualTo(ApiLevelQ) {
|
|
inputs = m.checkVendorPropertyNamespace(ctx, inputs)
|
|
}
|
|
|
|
builtCtxFile := m.buildGeneralContexts(ctx, inputs)
|
|
|
|
var apiFiles android.Paths
|
|
ctx.VisitDirectDepsWithTag(syspropLibraryDepTag, func(c android.Module) {
|
|
i, ok := c.(interface{ CurrentSyspropApiFile() android.OptionalPath })
|
|
if !ok {
|
|
panic(fmt.Errorf("unknown dependency %q for %q", ctx.OtherModuleName(c), ctx.ModuleName()))
|
|
}
|
|
if api := i.CurrentSyspropApiFile(); api.Valid() {
|
|
apiFiles = append(apiFiles, api.Path())
|
|
}
|
|
})
|
|
|
|
// check compatibility with sysprop_library
|
|
if len(apiFiles) > 0 {
|
|
out := pathForModuleOut(ctx, ctx.ModuleName()+"_api_checked")
|
|
rule := android.NewRuleBuilder(pctx, ctx)
|
|
|
|
msg := `\n******************************\n` +
|
|
`API of sysprop_library doesn't match with property_contexts\n` +
|
|
`Please fix the breakage and rebuild.\n` +
|
|
`******************************\n`
|
|
|
|
rule.Command().
|
|
Text("( ").
|
|
BuiltTool("sysprop_type_checker").
|
|
FlagForEachInput("--api ", apiFiles).
|
|
FlagWithInput("--context ", builtCtxFile).
|
|
Text(" || ( echo").Flag("-e").
|
|
Flag(`"` + msg + `"`).
|
|
Text("; exit 38) )")
|
|
|
|
rule.Command().Text("cp -f").Input(builtCtxFile).Output(out)
|
|
rule.Build("property_contexts_check_api", "checking API: "+m.Name())
|
|
builtCtxFile = out
|
|
}
|
|
|
|
return builtCtxFile
|
|
}
|
|
|
|
func (m *selinuxContextsModule) shouldCheckCoredomain(ctx android.ModuleContext) bool {
|
|
if !ctx.SocSpecific() && !ctx.DeviceSpecific() {
|
|
return false
|
|
}
|
|
|
|
return ctx.DeviceConfig().CheckVendorSeappViolations()
|
|
}
|
|
|
|
func (m *selinuxContextsModule) buildSeappContexts(ctx android.ModuleContext, inputs android.Paths) android.Path {
|
|
neverallowFile := pathForModuleOut(ctx, "neverallow")
|
|
ret := pathForModuleOut(ctx, m.stem())
|
|
|
|
rule := android.NewRuleBuilder(pctx, ctx)
|
|
rule.Command().Text("(grep").
|
|
Flag("-ihe").
|
|
Text("'^neverallow'").
|
|
Inputs(android.PathsForModuleSrc(ctx, m.seappProperties.Neverallow_files)).
|
|
Text(os.DevNull). // to make grep happy even when Neverallow_files is empty
|
|
Text(">").
|
|
Output(neverallowFile).
|
|
Text("|| true)") // to make ninja happy even when result is empty
|
|
|
|
rule.Temporary(neverallowFile)
|
|
checkCmd := rule.Command().BuiltTool("checkseapp").
|
|
FlagWithInput("-p ", android.PathForModuleSrc(ctx, proptools.String(m.seappProperties.Sepolicy))).
|
|
FlagWithOutput("-o ", ret).
|
|
Inputs(inputs).
|
|
Input(neverallowFile)
|
|
|
|
if m.shouldCheckCoredomain(ctx) {
|
|
checkCmd.Flag("-c") // check coredomain for vendor contexts
|
|
}
|
|
|
|
rule.Build("seapp_contexts", "Building seapp_contexts: "+m.Name())
|
|
return ret
|
|
}
|
|
|
|
func hwServiceFactory() android.Module {
|
|
m := newModule()
|
|
m.build = m.buildServiceContexts
|
|
return m
|
|
}
|
|
|
|
func propertyFactory() android.Module {
|
|
m := newModule()
|
|
m.build = m.buildPropertyContexts
|
|
m.deps = m.propertyContextsDeps
|
|
return m
|
|
}
|
|
|
|
func serviceFactory() android.Module {
|
|
m := newModule()
|
|
m.build = m.buildServiceContexts
|
|
return m
|
|
}
|
|
|
|
func keystoreKeyFactory() android.Module {
|
|
m := newModule()
|
|
m.build = m.buildGeneralContexts
|
|
return m
|
|
}
|
|
|
|
func seappFactory() android.Module {
|
|
m := newModule()
|
|
m.build = m.buildSeappContexts
|
|
return m
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
var _ android.OutputFileProducer = (*selinuxContextsModule)(nil)
|
|
|
|
// Implements android.OutputFileProducer
|
|
func (m *selinuxContextsModule) OutputFiles(tag string) (android.Paths, error) {
|
|
if tag == "" {
|
|
return []android.Path{m.outputPath}, nil
|
|
}
|
|
return nil, fmt.Errorf("unsupported module reference tag %q", tag)
|
|
}
|
|
|
|
type contextsTestProperties struct {
|
|
// Contexts files to be tested.
|
|
Srcs []string `android:"path"`
|
|
|
|
// Precompiled sepolicy binary to be tesed together.
|
|
Sepolicy *string `android:"path"`
|
|
}
|
|
|
|
type fileContextsTestProperties struct {
|
|
// Test data. File passed to `checkfc -t` to validate how contexts are resolved.
|
|
Test_data *string `android:"path"`
|
|
}
|
|
|
|
type contextsTestModule struct {
|
|
android.ModuleBase
|
|
|
|
// The type of context.
|
|
context contextType
|
|
|
|
properties contextsTestProperties
|
|
fileProperties fileContextsTestProperties
|
|
testTimestamp android.OutputPath
|
|
}
|
|
|
|
type contextType int
|
|
|
|
const (
|
|
FileContext contextType = iota
|
|
PropertyContext
|
|
ServiceContext
|
|
HwServiceContext
|
|
VndServiceContext
|
|
)
|
|
|
|
// checkfc parses a context file and checks for syntax errors.
|
|
// If -s is specified, the service backend is used to verify binder services.
|
|
// If -l is specified, the service backend is used to verify hwbinder services.
|
|
// Otherwise, context_file is assumed to be a file_contexts file
|
|
// If -e is specified, then the context_file is allowed to be empty.
|
|
|
|
// file_contexts_test tests given file_contexts files with checkfc.
|
|
func fileContextsTestFactory() android.Module {
|
|
m := &contextsTestModule{context: FileContext}
|
|
m.AddProperties(&m.properties)
|
|
m.AddProperties(&m.fileProperties)
|
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
|
return m
|
|
}
|
|
|
|
// property_contexts_test tests given property_contexts files with property_info_checker.
|
|
func propertyContextsTestFactory() android.Module {
|
|
m := &contextsTestModule{context: PropertyContext}
|
|
m.AddProperties(&m.properties)
|
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
|
return m
|
|
}
|
|
|
|
// hwservice_contexts_test tests given hwservice_contexts files with checkfc.
|
|
func hwserviceContextsTestFactory() android.Module {
|
|
m := &contextsTestModule{context: HwServiceContext}
|
|
m.AddProperties(&m.properties)
|
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
|
return m
|
|
}
|
|
|
|
// service_contexts_test tests given service_contexts files with checkfc.
|
|
func serviceContextsTestFactory() android.Module {
|
|
// checkfc -s: service_contexts test
|
|
m := &contextsTestModule{context: ServiceContext}
|
|
m.AddProperties(&m.properties)
|
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
|
return m
|
|
}
|
|
|
|
// vndservice_contexts_test tests given vndservice_contexts files with checkfc.
|
|
func vndServiceContextsTestFactory() android.Module {
|
|
m := &contextsTestModule{context: VndServiceContext}
|
|
m.AddProperties(&m.properties)
|
|
android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
|
|
return m
|
|
}
|
|
|
|
func (m *contextsTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
|
tool := "checkfc"
|
|
if m.context == PropertyContext {
|
|
tool = "property_info_checker"
|
|
}
|
|
|
|
if len(m.properties.Srcs) == 0 {
|
|
ctx.PropertyErrorf("srcs", "can't be empty")
|
|
return
|
|
}
|
|
|
|
validateWithPolicy := true
|
|
if proptools.String(m.properties.Sepolicy) == "" {
|
|
if m.context == FileContext {
|
|
if proptools.String(m.fileProperties.Test_data) == "" {
|
|
ctx.PropertyErrorf("test_data", "Either test_data or sepolicy should be provided")
|
|
return
|
|
}
|
|
validateWithPolicy = false
|
|
} else {
|
|
ctx.PropertyErrorf("sepolicy", "can't be empty")
|
|
return
|
|
}
|
|
}
|
|
|
|
flags := []string(nil)
|
|
switch m.context {
|
|
case FileContext:
|
|
if !validateWithPolicy {
|
|
flags = []string{"-t"}
|
|
}
|
|
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 */}
|
|
}
|
|
|
|
srcs := android.PathsForModuleSrc(ctx, m.properties.Srcs)
|
|
rule := android.NewRuleBuilder(pctx, ctx)
|
|
|
|
if validateWithPolicy {
|
|
sepolicy := android.PathForModuleSrc(ctx, proptools.String(m.properties.Sepolicy))
|
|
rule.Command().BuiltTool(tool).
|
|
Flags(flags).
|
|
Input(sepolicy).
|
|
Inputs(srcs)
|
|
} else {
|
|
test_data := android.PathForModuleSrc(ctx, proptools.String(m.fileProperties.Test_data))
|
|
rule.Command().BuiltTool(tool).
|
|
Flags(flags).
|
|
Inputs(srcs).
|
|
Input(test_data)
|
|
}
|
|
|
|
m.testTimestamp = pathForModuleOut(ctx, "timestamp")
|
|
rule.Command().Text("touch").Output(m.testTimestamp)
|
|
rule.Build("contexts_test", "running contexts test: "+ctx.ModuleName())
|
|
}
|
|
|
|
func (m *contextsTestModule) AndroidMkEntries() []android.AndroidMkEntries {
|
|
return []android.AndroidMkEntries{android.AndroidMkEntries{
|
|
Class: "FAKE",
|
|
// OutputFile is needed, even though BUILD_PHONY_PACKAGE doesn't use it.
|
|
// Without OutputFile this module won't be exported to Makefile.
|
|
OutputFile: android.OptionalPathForPath(m.testTimestamp),
|
|
Include: "$(BUILD_PHONY_PACKAGE)",
|
|
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
|
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
|
entries.SetString("LOCAL_ADDITIONAL_DEPENDENCIES", m.testTimestamp.String())
|
|
},
|
|
},
|
|
}}
|
|
}
|
|
|
|
// contextsTestModule implements ImageInterface to be able to include recovery_available contexts
|
|
// modules as its sources.
|
|
func (m *contextsTestModule) ImageMutatorBegin(ctx android.BaseModuleContext) {
|
|
}
|
|
|
|
func (m *contextsTestModule) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return true
|
|
}
|
|
|
|
func (m *contextsTestModule) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return false
|
|
}
|
|
|
|
func (m *contextsTestModule) VendorRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return false
|
|
}
|
|
|
|
func (m *contextsTestModule) DebugRamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return false
|
|
}
|
|
|
|
func (m *contextsTestModule) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
|
|
return false
|
|
}
|
|
|
|
func (m *contextsTestModule) ExtraImageVariations(ctx android.BaseModuleContext) []string {
|
|
return nil
|
|
}
|
|
|
|
func (m *contextsTestModule) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
|
|
}
|
|
|
|
var _ android.ImageInterface = (*contextsTestModule)(nil)
|