1// Copyright 2015 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package android 16 17import ( 18 "reflect" 19 20 "github.com/google/blueprint" 21 "github.com/google/blueprint/proptools" 22) 23 24type defaultsDependencyTag struct { 25 blueprint.BaseDependencyTag 26} 27 28var DefaultsDepTag defaultsDependencyTag 29 30type defaultsProperties struct { 31 Defaults []string 32} 33 34type DefaultableModuleBase struct { 35 defaultsProperties defaultsProperties 36 defaultableProperties []interface{} 37 defaultableVariableProperties interface{} 38 39 // The optional hook to call after any defaults have been applied. 40 hook DefaultableHook 41} 42 43func (d *DefaultableModuleBase) defaults() *defaultsProperties { 44 return &d.defaultsProperties 45} 46 47func (d *DefaultableModuleBase) setProperties(props []interface{}, variableProperties interface{}) { 48 d.defaultableProperties = props 49 d.defaultableVariableProperties = variableProperties 50} 51 52func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) { 53 d.hook = hook 54} 55 56func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) { 57 if d.hook != nil { 58 d.hook(ctx) 59 } 60} 61 62// Interface that must be supported by any module to which defaults can be applied. 63type Defaultable interface { 64 // Get a pointer to the struct containing the Defaults property. 65 defaults() *defaultsProperties 66 67 // Set the property structures into which defaults will be added. 68 setProperties(props []interface{}, variableProperties interface{}) 69 70 // Apply defaults from the supplied Defaults to the property structures supplied to 71 // setProperties(...). 72 applyDefaults(TopDownMutatorContext, []Defaults) 73 74 // Set the hook to be called after any defaults have been applied. 75 // 76 // Should be used in preference to a AddLoadHook when the behavior of the load 77 // hook is dependent on properties supplied in the Android.bp file. 78 SetDefaultableHook(hook DefaultableHook) 79 80 // Call the hook if specified. 81 callHookIfAvailable(context DefaultableHookContext) 82} 83 84type DefaultableModule interface { 85 Module 86 Defaultable 87} 88 89var _ Defaultable = (*DefaultableModuleBase)(nil) 90 91func InitDefaultableModule(module DefaultableModule) { 92 if module.(Module).base().module == nil { 93 panic("InitAndroidModule must be called before InitDefaultableModule") 94 } 95 module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties) 96 97 module.AddProperties(module.defaults()) 98} 99 100// A restricted subset of context methods, similar to LoadHookContext. 101type DefaultableHookContext interface { 102 EarlyModuleContext 103 104 CreateModule(ModuleFactory, ...interface{}) Module 105} 106 107type DefaultableHook func(ctx DefaultableHookContext) 108 109// The Defaults_visibility property. 110type DefaultsVisibilityProperties struct { 111 112 // Controls the visibility of the defaults module itself. 113 Defaults_visibility []string 114} 115 116type DefaultsModuleBase struct { 117 DefaultableModuleBase 118 119 // Container for defaults of the common properties 120 commonProperties commonProperties 121 122 defaultsVisibilityProperties DefaultsVisibilityProperties 123} 124 125// The common pattern for defaults modules is to register separate instances of 126// the xxxProperties structs in the AddProperties calls, rather than reusing the 127// ones inherited from Module. 128// 129// The effect is that e.g. myDefaultsModuleInstance.base().xxxProperties won't 130// contain the values that have been set for the defaults module. Rather, to 131// retrieve the values it is necessary to iterate over properties(). E.g. to get 132// the commonProperties instance that have the real values: 133// 134// d := myModule.(Defaults) 135// for _, props := range d.properties() { 136// if cp, ok := props.(*commonProperties); ok { 137// ... access property values in cp ... 138// } 139// } 140// 141// The rationale is that the properties on a defaults module apply to the 142// defaultable modules using it, not to the defaults module itself. E.g. setting 143// the "enabled" property false makes inheriting modules disabled by default, 144// rather than disabling the defaults module itself. 145type Defaults interface { 146 Defaultable 147 148 // Although this function is unused it is actually needed to ensure that only modules that embed 149 // DefaultsModuleBase will type-assert to the Defaults interface. 150 isDefaults() bool 151 152 // Get the structures containing the properties for which defaults can be provided. 153 properties() []interface{} 154 155 productVariableProperties() interface{} 156 157 // Return the defaults common properties. 158 common() *commonProperties 159 160 // Return the defaults visibility properties. 161 defaultsVisibility() *DefaultsVisibilityProperties 162} 163 164func (d *DefaultsModuleBase) isDefaults() bool { 165 return true 166} 167 168type DefaultsModule interface { 169 Module 170 Defaults 171} 172 173func (d *DefaultsModuleBase) properties() []interface{} { 174 return d.defaultableProperties 175} 176 177func (d *DefaultsModuleBase) productVariableProperties() interface{} { 178 return d.defaultableVariableProperties 179} 180 181func (d *DefaultsModuleBase) common() *commonProperties { 182 return &d.commonProperties 183} 184 185func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties { 186 return &d.defaultsVisibilityProperties 187} 188 189func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) { 190} 191 192func InitDefaultsModule(module DefaultsModule) { 193 commonProperties := module.common() 194 195 module.AddProperties( 196 &hostAndDeviceProperties{}, 197 commonProperties, 198 &ApexProperties{}) 199 200 initAndroidModuleBase(module) 201 initProductVariableModule(module) 202 InitArchModule(module) 203 InitDefaultableModule(module) 204 205 // Add properties that will not have defaults applied to them. 206 base := module.base() 207 defaultsVisibility := module.defaultsVisibility() 208 module.AddProperties(&base.nameProperties, defaultsVisibility) 209 210 // Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties. 211 // Instead it is stored in a separate instance of commonProperties created above so clear the 212 // existing list of properties. 213 clearVisibilityProperties(module) 214 215 // The defaults_visibility property controls the visibility of a defaults module so it must be 216 // set as the primary property, which also adds it to the list. 217 setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility) 218 219 // The visibility property needs to be checked (but not parsed) by the visibility module during 220 // its checking phase and parsing phase so add it to the list as a normal property. 221 AddVisibilityProperty(module, "visibility", &commonProperties.Visibility) 222 223 base.module = module 224} 225 226var _ Defaults = (*DefaultsModuleBase)(nil) 227 228func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext, 229 defaultsList []Defaults) { 230 231 for _, defaults := range defaultsList { 232 for _, prop := range defaultable.defaultableProperties { 233 if prop == defaultable.defaultableVariableProperties { 234 defaultable.applyDefaultVariableProperties(ctx, defaults, prop) 235 } else { 236 defaultable.applyDefaultProperties(ctx, defaults, prop) 237 } 238 } 239 } 240} 241 242// Product variable properties need special handling, the type of the filtered product variable 243// property struct may not be identical between the defaults module and the defaultable module. 244// Use PrependMatchingProperties to apply whichever properties match. 245func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext, 246 defaults Defaults, defaultableProp interface{}) { 247 if defaultableProp == nil { 248 return 249 } 250 251 defaultsProp := defaults.productVariableProperties() 252 if defaultsProp == nil { 253 return 254 } 255 256 dst := []interface{}{ 257 defaultableProp, 258 // Put an empty copy of the src properties into dst so that properties in src that are not in dst 259 // don't cause a "failed to find property to extend" error. 260 proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(), 261 } 262 263 err := proptools.PrependMatchingProperties(dst, defaultsProp, nil) 264 if err != nil { 265 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 266 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 267 } else { 268 panic(err) 269 } 270 } 271} 272 273func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext, 274 defaults Defaults, defaultableProp interface{}) { 275 276 for _, def := range defaults.properties() { 277 if proptools.TypeEqual(defaultableProp, def) { 278 err := proptools.PrependProperties(defaultableProp, def, nil) 279 if err != nil { 280 if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { 281 ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) 282 } else { 283 panic(err) 284 } 285 } 286 } 287 } 288} 289 290func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) { 291 ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel() 292 ctx.TopDown("defaults", defaultsMutator).Parallel() 293} 294 295func defaultsDepsMutator(ctx BottomUpMutatorContext) { 296 if defaultable, ok := ctx.Module().(Defaultable); ok { 297 ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...) 298 } 299} 300 301func defaultsMutator(ctx TopDownMutatorContext) { 302 if defaultable, ok := ctx.Module().(Defaultable); ok { 303 if len(defaultable.defaults().Defaults) > 0 { 304 var defaultsList []Defaults 305 seen := make(map[Defaults]bool) 306 307 ctx.WalkDeps(func(module, parent Module) bool { 308 if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag { 309 if defaults, ok := module.(Defaults); ok { 310 if !seen[defaults] { 311 seen[defaults] = true 312 defaultsList = append(defaultsList, defaults) 313 return len(defaults.defaults().Defaults) > 0 314 } 315 } else { 316 ctx.PropertyErrorf("defaults", "module %s is not an defaults module", 317 ctx.OtherModuleName(module)) 318 } 319 } 320 return false 321 }) 322 defaultable.applyDefaults(ctx, defaultsList) 323 } 324 325 defaultable.callHookIfAvailable(ctx) 326 } 327} 328