Support passing flag parameters to M4

This will be used to guard sepolicy changes. Also this adds default
modules for se_policy_conf and contexts modules.

Bug: 306563735
Test: build
Change-Id: I9b3460aaca07d325e0f83a1e2bf0e57caa498101
diff --git a/build/soong/Android.bp b/build/soong/Android.bp
index 83b31b4..0abfdf6 100644
--- a/build/soong/Android.bp
+++ b/build/soong/Android.bp
@@ -35,6 +35,7 @@
         "build_files.go",
         "cil_compat_map.go",
         "compat_cil.go",
+        "flags.go",
         "mac_permissions.go",
         "policy.go",
         "selinux.go",
diff --git a/build/soong/flags.go b/build/soong/flags.go
new file mode 100644
index 0000000..b1aebac
--- /dev/null
+++ b/build/soong/flags.go
@@ -0,0 +1,54 @@
+// Copyright (C) 2023 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 (
+	"android/soong/android"
+)
+
+type flagsProperties struct {
+	// List of flags to be passed to M4 macro.
+	Flags []string
+}
+
+type flaggableModule interface {
+	android.Module
+	flagModuleBase() *flaggableModuleBase
+	getBuildFlags(ctx android.ModuleContext) map[string]string
+}
+
+type flaggableModuleBase struct {
+	properties flagsProperties
+}
+
+func initFlaggableModule(m flaggableModule) {
+	base := m.flagModuleBase()
+	m.AddProperties(&base.properties)
+}
+
+func (f *flaggableModuleBase) flagModuleBase() *flaggableModuleBase {
+	return f
+}
+
+// getBuildFlags returns a map from flag names to flag values.
+func (f *flaggableModuleBase) getBuildFlags(ctx android.ModuleContext) map[string]string {
+	ret := make(map[string]string)
+	for _, flag := range android.SortedUniqueStrings(f.properties.Flags) {
+		if val, ok := ctx.Config().GetBuildFlag(flag); ok {
+			ret[flag] = val
+		}
+	}
+	return ret
+}
diff --git a/build/soong/policy.go b/build/soong/policy.go
index 0793e2a..9d87275 100644
--- a/build/soong/policy.go
+++ b/build/soong/policy.go
@@ -58,6 +58,7 @@
 
 func init() {
 	android.RegisterModuleType("se_policy_conf", policyConfFactory)
+	android.RegisterModuleType("se_policy_conf_defaults", policyConfDefaultFactory)
 	android.RegisterModuleType("se_policy_cil", policyCilFactory)
 	android.RegisterModuleType("se_policy_binary", policyBinaryFactory)
 }
@@ -93,6 +94,8 @@
 
 type policyConf struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
+	flaggableModuleBase
 
 	properties policyConfProperties
 
@@ -100,12 +103,35 @@
 	installPath   android.InstallPath
 }
 
+var _ flaggableModule = (*policyConf)(nil)
+
 // se_policy_conf merges collection of policy files into a policy.conf file to be processed by
 // checkpolicy.
 func policyConfFactory() android.Module {
 	c := &policyConf{}
 	c.AddProperties(&c.properties)
+	initFlaggableModule(c)
 	android.InitAndroidArchModule(c, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(c)
+	return c
+}
+
+type policyConfDefaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+// se_policy_conf_defaults provides a set of properties that can be inherited by other
+// se_policy_conf_defaults modules. A module can use the properties from a se_policy_conf_defaults
+// using `defaults: ["<:default_module_name>"]`. Properties of both modules are merged (when
+// possible) by prepending the default module's values to the depending module's values.
+func policyConfDefaultFactory() android.Module {
+	c := &policyConfDefaults{}
+	c.AddProperties(
+		&policyConfProperties{},
+		&flagsProperties{},
+	)
+	android.InitDefaultsModule(c)
 	return c
 }
 
@@ -216,6 +242,7 @@
 		return findPolicyConfOrder(srcs[x].Base()) < findPolicyConfOrder(srcs[y].Base())
 	})
 
+	flags := c.getBuildFlags(ctx)
 	rule.Command().Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
 		Flag("--fatal-warnings").
 		FlagForEachArg("-D ", ctx.DeviceConfig().SepolicyM4Defs()).
@@ -234,6 +261,7 @@
 		FlagWithArg("-D target_requires_insecure_execmem_for_swiftshader=", strconv.FormatBool(ctx.DeviceConfig().RequiresInsecureExecmemForSwiftshader())).
 		FlagWithArg("-D target_enforce_debugfs_restriction=", c.enforceDebugfsRestrictions(ctx)).
 		FlagWithArg("-D target_recovery=", strconv.FormatBool(c.isTargetRecovery())).
+		Flags(flagsToM4Macros(flags)).
 		Flag("-s").
 		Inputs(srcs).
 		Text("> ").Output(conf)
@@ -242,10 +270,6 @@
 	return conf
 }
 
-func (c *policyConf) DepsMutator(ctx android.BottomUpMutatorContext) {
-	// do nothing
-}
-
 func (c *policyConf) GenerateAndroidBuildActions(ctx android.ModuleContext) {
 	if !c.installable() {
 		c.SkipInstall()
diff --git a/build/soong/selinux.go b/build/soong/selinux.go
index 5fbe01eb..f811231 100644
--- a/build/soong/selinux.go
+++ b/build/soong/selinux.go
@@ -40,3 +40,13 @@
 
 	return android.PathForModuleOut(ctx, ctx.Config().DeviceName()).Join(ctx, paths...)
 }
+
+// flagsToM4Macros converts given map to a list of M4's -D parameters to guard te files and contexts
+// files.
+func flagsToM4Macros(flags map[string]string) []string {
+	flagMacros := []string{}
+	for _, flag := range android.SortedKeys(flags) {
+		flagMacros = append(flagMacros, "-D target_flag_"+flag+"="+flags[flag])
+	}
+	return flagMacros
+}
diff --git a/build/soong/selinux_contexts.go b/build/soong/selinux_contexts.go
index de7355c..5f7d525 100644
--- a/build/soong/selinux_contexts.go
+++ b/build/soong/selinux_contexts.go
@@ -59,6 +59,8 @@
 
 type selinuxContextsModule struct {
 	android.ModuleBase
+	android.DefaultableModuleBase
+	flaggableModuleBase
 
 	properties      selinuxContextsProperties
 	seappProperties seappProperties
@@ -68,6 +70,8 @@
 	installPath     android.InstallPath
 }
 
+var _ flaggableModule = (*selinuxContextsModule)(nil)
+
 var (
 	reuseContextsDepTag  = dependencyTag{name: "reuseContexts"}
 	syspropLibraryDepTag = dependencyTag{name: "sysprop_library"}
@@ -76,6 +80,7 @@
 func init() {
 	pctx.HostBinToolVariable("fc_sort", "fc_sort")
 
+	android.RegisterModuleType("contexts_defaults", contextsDefaultsFactory)
 	android.RegisterModuleType("file_contexts", fileFactory)
 	android.RegisterModuleType("hwservice_contexts", hwServiceFactory)
 	android.RegisterModuleType("property_contexts", propertyFactory)
@@ -155,13 +160,35 @@
 		&m.properties,
 		&m.seappProperties,
 	)
+	initFlaggableModule(m)
 	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
+	android.InitDefaultableModule(m)
 	android.AddLoadHook(m, func(ctx android.LoadHookContext) {
 		m.selinuxContextsHook(ctx)
 	})
 	return m
 }
 
+type contextsDefaults struct {
+	android.ModuleBase
+	android.DefaultsModuleBase
+}
+
+// contexts_defaults provides a set of properties that can be inherited by other contexts modules.
+// (file_contexts, property_contexts, seapp_contexts, etc.) A module can use the properties from a
+// contexts_defaults using `defaults: ["<:default_module_name>"]`. Properties of both modules are
+// erged (when possible) by prepending the default module's values to the depending module's values.
+func contextsDefaultsFactory() android.Module {
+	m := &contextsDefaults{}
+	m.AddProperties(
+		&selinuxContextsProperties{},
+		&seappProperties{},
+		&flagsProperties{},
+	)
+	android.InitDefaultsModule(m)
+	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
@@ -245,10 +272,12 @@
 		inputsWithNewline = append(inputsWithNewline, input, newlineFile)
 	}
 
+	flags := m.getBuildFlags(ctx)
 	rule.Command().
 		Tool(ctx.Config().PrebuiltBuildTool(ctx, "m4")).
 		Text("--fatal-warnings -s").
 		FlagForEachArg("-D", ctx.DeviceConfig().SepolicyM4Defs()).
+		Flags(flagsToM4Macros(flags)).
 		Inputs(inputsWithNewline).
 		FlagWithOutput("> ", builtContext)