summaryrefslogtreecommitdiff
path: root/android/defaults.go
diff options
context:
space:
mode:
Diffstat (limited to 'android/defaults.go')
-rw-r--r--android/defaults.go252
1 files changed, 213 insertions, 39 deletions
diff --git a/android/defaults.go b/android/defaults.go
index d4fbf487d..81e340e8e 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -15,6 +15,8 @@
package android
import (
+ "reflect"
+
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
)
@@ -30,22 +32,53 @@ type defaultsProperties struct {
}
type DefaultableModuleBase struct {
- defaultsProperties defaultsProperties
- defaultableProperties []interface{}
+ defaultsProperties defaultsProperties
+ defaultableProperties []interface{}
+ defaultableVariableProperties interface{}
+
+ // The optional hook to call after any defaults have been applied.
+ hook DefaultableHook
}
func (d *DefaultableModuleBase) defaults() *defaultsProperties {
return &d.defaultsProperties
}
-func (d *DefaultableModuleBase) setProperties(props []interface{}) {
+func (d *DefaultableModuleBase) setProperties(props []interface{}, variableProperties interface{}) {
d.defaultableProperties = props
+ d.defaultableVariableProperties = variableProperties
}
+func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) {
+ d.hook = hook
+}
+
+func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) {
+ if d.hook != nil {
+ d.hook(ctx)
+ }
+}
+
+// Interface that must be supported by any module to which defaults can be applied.
type Defaultable interface {
+ // Get a pointer to the struct containing the Defaults property.
defaults() *defaultsProperties
- setProperties([]interface{})
+
+ // Set the property structures into which defaults will be added.
+ setProperties(props []interface{}, variableProperties interface{})
+
+ // Apply defaults from the supplied Defaults to the property structures supplied to
+ // setProperties(...).
applyDefaults(TopDownMutatorContext, []Defaults)
+
+ // Set the hook to be called after any defaults have been applied.
+ //
+ // Should be used in preference to a AddLoadHook when the behavior of the load
+ // hook is dependent on properties supplied in the Android.bp file.
+ SetDefaultableHook(hook DefaultableHook)
+
+ // Call the hook if specified.
+ callHookIfAvailable(context DefaultableHookContext)
}
type DefaultableModule interface {
@@ -56,42 +89,138 @@ type DefaultableModule interface {
var _ Defaultable = (*DefaultableModuleBase)(nil)
func InitDefaultableModule(module DefaultableModule) {
- module.(Defaultable).setProperties(module.(Module).GetProperties())
+ if module.(Module).base().module == nil {
+ panic("InitAndroidModule must be called before InitDefaultableModule")
+ }
+ module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties)
module.AddProperties(module.defaults())
}
+// A restricted subset of context methods, similar to LoadHookContext.
+type DefaultableHookContext interface {
+ EarlyModuleContext
+
+ CreateModule(ModuleFactory, ...interface{}) Module
+}
+
+type DefaultableHook func(ctx DefaultableHookContext)
+
+// The Defaults_visibility property.
+type DefaultsVisibilityProperties struct {
+
+ // Controls the visibility of the defaults module itself.
+ Defaults_visibility []string
+}
+
type DefaultsModuleBase struct {
DefaultableModuleBase
- defaultProperties []interface{}
+
+ // Container for defaults of the common properties
+ commonProperties commonProperties
+
+ defaultsVisibilityProperties DefaultsVisibilityProperties
}
+// The common pattern for defaults modules is to register separate instances of
+// the xxxProperties structs in the AddProperties calls, rather than reusing the
+// ones inherited from Module.
+//
+// The effect is that e.g. myDefaultsModuleInstance.base().xxxProperties won't
+// contain the values that have been set for the defaults module. Rather, to
+// retrieve the values it is necessary to iterate over properties(). E.g. to get
+// the commonProperties instance that have the real values:
+//
+// d := myModule.(Defaults)
+// for _, props := range d.properties() {
+// if cp, ok := props.(*commonProperties); ok {
+// ... access property values in cp ...
+// }
+// }
+//
+// The rationale is that the properties on a defaults module apply to the
+// defaultable modules using it, not to the defaults module itself. E.g. setting
+// the "enabled" property false makes inheriting modules disabled by default,
+// rather than disabling the defaults module itself.
type Defaults interface {
Defaultable
+
+ // Although this function is unused it is actually needed to ensure that only modules that embed
+ // DefaultsModuleBase will type-assert to the Defaults interface.
isDefaults() bool
+
+ // Get the structures containing the properties for which defaults can be provided.
properties() []interface{}
+
+ productVariableProperties() interface{}
+
+ // Return the defaults common properties.
+ common() *commonProperties
+
+ // Return the defaults visibility properties.
+ defaultsVisibility() *DefaultsVisibilityProperties
}
func (d *DefaultsModuleBase) isDefaults() bool {
return true
}
+type DefaultsModule interface {
+ Module
+ Defaults
+}
+
func (d *DefaultsModuleBase) properties() []interface{} {
return d.defaultableProperties
}
-func InitDefaultsModule(module DefaultableModule) {
+func (d *DefaultsModuleBase) productVariableProperties() interface{} {
+ return d.defaultableVariableProperties
+}
+
+func (d *DefaultsModuleBase) common() *commonProperties {
+ return &d.commonProperties
+}
+
+func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties {
+ return &d.defaultsVisibilityProperties
+}
+
+func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+func InitDefaultsModule(module DefaultsModule) {
+ commonProperties := module.common()
+
module.AddProperties(
&hostAndDeviceProperties{},
- &commonProperties{},
- &variableProperties{})
+ commonProperties,
+ &ApexProperties{})
+ initAndroidModuleBase(module)
+ initProductVariableModule(module)
InitArchModule(module)
InitDefaultableModule(module)
- module.AddProperties(&module.base().nameProperties)
+ // Add properties that will not have defaults applied to them.
+ base := module.base()
+ defaultsVisibility := module.defaultsVisibility()
+ module.AddProperties(&base.nameProperties, defaultsVisibility)
+
+ // Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
+ // Instead it is stored in a separate instance of commonProperties created above so clear the
+ // existing list of properties.
+ clearVisibilityProperties(module)
+
+ // The defaults_visibility property controls the visibility of a defaults module so it must be
+ // set as the primary property, which also adds it to the list.
+ setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility)
+
+ // The visibility property needs to be checked (but not parsed) by the visibility module during
+ // its checking phase and parsing phase so add it to the list as a normal property.
+ AddVisibilityProperty(module, "visibility", &commonProperties.Visibility)
- module.base().module = module
+ base.module = module
}
var _ Defaults = (*DefaultsModuleBase)(nil)
@@ -101,16 +230,57 @@ func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContex
for _, defaults := range defaultsList {
for _, prop := range defaultable.defaultableProperties {
- for _, def := range defaults.properties() {
- if proptools.TypeEqual(prop, def) {
- err := proptools.PrependProperties(prop, def, nil)
- if err != nil {
- if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
- ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
- } else {
- panic(err)
- }
- }
+ if prop == defaultable.defaultableVariableProperties {
+ defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
+ } else {
+ defaultable.applyDefaultProperties(ctx, defaults, prop)
+ }
+ }
+ }
+}
+
+// Product variable properties need special handling, the type of the filtered product variable
+// property struct may not be identical between the defaults module and the defaultable module.
+// Use PrependMatchingProperties to apply whichever properties match.
+func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
+ defaults Defaults, defaultableProp interface{}) {
+ if defaultableProp == nil {
+ return
+ }
+
+ defaultsProp := defaults.productVariableProperties()
+ if defaultsProp == nil {
+ return
+ }
+
+ dst := []interface{}{
+ defaultableProp,
+ // Put an empty copy of the src properties into dst so that properties in src that are not in dst
+ // don't cause a "failed to find property to extend" error.
+ proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
+ }
+
+ err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
+ if err != nil {
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
+ }
+ }
+}
+
+func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
+ defaults Defaults, defaultableProp interface{}) {
+
+ for _, def := range defaults.properties() {
+ if proptools.TypeEqual(defaultableProp, def) {
+ err := proptools.PrependProperties(defaultableProp, def, nil)
+ if err != nil {
+ if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
+ ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
+ } else {
+ panic(err)
}
}
}
@@ -129,25 +299,29 @@ func defaultsDepsMutator(ctx BottomUpMutatorContext) {
}
func defaultsMutator(ctx TopDownMutatorContext) {
- if defaultable, ok := ctx.Module().(Defaultable); ok && len(defaultable.defaults().Defaults) > 0 {
- var defaultsList []Defaults
- seen := make(map[Defaults]bool)
-
- ctx.WalkDeps(func(module, parent Module) bool {
- if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
- if defaults, ok := module.(Defaults); ok {
- if !seen[defaults] {
- seen[defaults] = true
- defaultsList = append(defaultsList, defaults)
- return len(defaults.defaults().Defaults) > 0
+ if defaultable, ok := ctx.Module().(Defaultable); ok {
+ if len(defaultable.defaults().Defaults) > 0 {
+ var defaultsList []Defaults
+ seen := make(map[Defaults]bool)
+
+ ctx.WalkDeps(func(module, parent Module) bool {
+ if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
+ if defaults, ok := module.(Defaults); ok {
+ if !seen[defaults] {
+ seen[defaults] = true
+ defaultsList = append(defaultsList, defaults)
+ return len(defaults.defaults().Defaults) > 0
+ }
+ } else {
+ ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
+ ctx.OtherModuleName(module))
}
- } else {
- ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
- ctx.OtherModuleName(module))
}
- }
- return false
- })
- defaultable.applyDefaults(ctx, defaultsList)
+ return false
+ })
+ defaultable.applyDefaults(ctx, defaultsList)
+ }
+
+ defaultable.callHookIfAvailable(ctx)
}
}